Easy Profile Mentions
Type @ in the WordPress block editor or comment form to tag user profiles. Supports WordPress, BuddyPress, and bbPress.
by Flex Perception · github.com/flexseth/easy-profile-mentions · website
Install
No release zip yet. The repository archive installs, but the folder name will carry the branch suffix and updates will not flow:
wp plugin install https://github.com/flexseth/easy-profile-mentions/archive/refs/heads/trunk.zipReadme
Easy Profile Mentions
Type @ in the WordPress block editor or comment form to tag user profiles. A live dropdown appears as you type — select a user to insert a linked mention.
Supports WordPress user accounts, BuddyPress profiles, and bbPress profiles.
Requirements
| Requirement | Minimum |
|---|---|
| WordPress | 6.4 |
| PHP | 7.4 |
| Node.js | 18+ (build only) |
| MySQL | 5.7 |
Installation
From source (development)
# 1. Clone or copy the plugin into your WordPress plugins directory
cd wp-content/plugins/
# 2. Install JS dependencies and build assets
cd easy-profile-mentions
npm install
npm run build
# 3. Activate in WordPress Admin → Plugins
From a zip
- Download or export the plugin folder as a
.zip - Go to WordPress Admin → Plugins → Add New → Upload Plugin
- Upload the zip and click Activate
The
build/directory must be present. If it is missing, runnpm install && npm run buildbefore zipping.
How to use
In the block editor
- Open any post, page, or custom post type in the block editor
- Click into a Paragraph, Heading, Quote, or any other rich-text block
- Type
@followed by at least one character (e.g.@jane) - A dropdown appears showing matching users with their avatar and display name
- Click a user or use Arrow keys to navigate and Enter to select
- The mention is inserted as a linked
@Display Nameinline element
In comment forms
- Navigate to any post with comments enabled
- Type
@followed by a name in the Comment textarea - The same autocomplete dropdown appears
- Select a user — their mention is inserted at the cursor
- Submit the comment as normal
Comment autocomplete requires the visitor to be logged in. Raw
@usernametokens typed by non-logged-in users are still resolved to profile links when the comment is displayed.
Keyboard shortcuts (dropdown)
| Key | Action |
|---|---|
↓ |
Move selection down |
↑ |
Move selection up |
Enter or Tab |
Insert selected mention |
Escape |
Close dropdown |
Profile URL resolution
The plugin resolves profile URLs in this order:
- BuddyPress —
bp_core_get_user_domain()(if BuddyPress is active) - bbPress —
bbp_get_user_profile_url()(if bbPress is active) - WordPress —
get_author_posts_url()(always available as fallback)
To override the URL for a specific user, use the epm_profile_url filter:
add_filter( 'epm_profile_url', function ( $url, $user_id ) {
// Return a custom URL for user ID 42.
if ( 42 === $user_id ) {
return 'https://example.com/members/jane/';
}
return $url;
}, 10, 2 );
REST API
The plugin registers a single read-only endpoint used by the autocomplete dropdown.
GET /wp-json/epm/v1/users
Authentication: Requires a logged-in user with the read capability. Send the REST nonce in the X-WP-Nonce header (automatically handled by the editor and comment form scripts).
Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
search |
string | "" |
Partial display name, login, or email |
per_page |
integer | 8 |
Max results (1–20) |
Example request:
GET /wp-json/epm/v1/users?search=jane&per_page=5
X-WP-Nonce: abc123
Example response:
[
{
"id": 42,
"slug": "jane-doe",
"login": "janedoe",
"displayName": "Jane Doe",
"profileUrl": "https://example.com/members/jane-doe/",
"avatar": "https://www.gravatar.com/avatar/…?s=48"
}
]
Results are cached as transients for 5 minutes. The cache is automatically flushed when a user profile is updated, a new user is registered, or a user is deleted.
Hooks & filters
epm_profile_url
Override the resolved profile URL for any user.
apply_filters( 'epm_profile_url', string $url, int $user_id )
epm_user_query_args
Modify the WP_User_Query arguments used for searching.
apply_filters( 'epm_user_query_args', array $args, string $search )
epm_user_search_results
Filter the full results array before it is returned by the REST endpoint.
apply_filters( 'epm_user_search_results', array $results, string $search )
epm_format_user
Filter a single user row before it is included in the REST response.
apply_filters( 'epm_format_user', array $data, WP_User $user )
Example — add a custom field to every result:
add_filter( 'epm_format_user', function ( $data, $user ) {
$data['jobTitle'] = get_user_meta( $user->ID, 'job_title', true );
return $data;
}, 10, 2 );
Styling mentions
Mentions render as <a> elements with the class epm-mention and a data-user-id attribute:
<a class="epm-mention" href="/members/jane-doe/" data-user-id="42">@Jane Doe</a>
Override the default styles in your theme:
.epm-mention {
color: #0073aa;
font-weight: 600;
text-decoration: none;
}
.epm-mention:hover {
text-decoration: underline;
}
Target a specific user:
.epm-mention[data-user-id="42"] {
color: #d63638;
}
Development
# Install dependencies
npm install
# Build for production (outputs to build/)
npm run build
# Watch for changes during development
npm start
# Lint JavaScript
npm run lint:js
# Lint CSS/SCSS
npm run lint:css
# Format files
npm run format
# Create a distributable zip
npm run plugin-zip
File structure
easy-profile-mentions/
├── easy-profile-mentions.php # Plugin bootstrap & asset registration
├── readme.txt # WordPress.org readme
├── README.md # This file
├── package.json
├── src/
│ ├── index.js # Registers epm/mention rich-text format
│ ├── mention-autocomplete.js # Block editor autocomplete completer
│ ├── view.js # Interactivity API store (comment form)
│ ├── editor.scss # Editor-only styles
│ └── style.scss # Shared front-end + editor styles
├── build/ # Compiled output (generated, not committed)
├── includes/
│ ├── rest-api.php # REST endpoint: GET epm/v1/users
│ ├── comment-support.php # Comment text filter + form directives
│ └── integrations.php # BuddyPress / bbPress URL resolution
└── assets/
└── css/
└── epm-mention.css # (optional) standalone stylesheet
Frequently asked questions
Does the plugin create database tables?
No. It uses WP_User_Query, the WordPress Transients API for caching, and no custom tables.
Do cached pages break mentions?
No. Mentions are stored as plain <a> elements in post content, so full-page caches (WP Super Cache, W3 Total Cache, etc.) serve them correctly. The REST search endpoint is only called inside authenticated editor sessions.
Does it work with Multisite?
Yes, but user searches are scoped to the current site. To search across the network, use the epm_user_query_args filter to modify the query.
Can non-logged-in users trigger mention autocomplete?
No — the REST endpoint requires authentication. Visitors who type @username manually in a comment will still have those tokens converted to profile links when the comment is displayed.
Changelog
1.0.0
- Initial release
- Block editor
@autocomplete viaregisterFormatType+editor.Autocomplete.completers - Interactivity API store for comment form live autocomplete
- REST endpoint
epm/v1/userswith nonce verification and transient caching - BuddyPress and bbPress profile URL resolution
@username→ profile link parsing in comment display- Hooks:
epm_profile_url,epm_user_query_args,epm_user_search_results,epm_format_user
License
GPL-2.0-or-later — see https://www.gnu.org/licenses/gpl-2.0.html