Restricting WordPress features by user role is one of the most effective ways to keep the WordPress administration area secure, understandable and appropriate for the people who actually use it.
A typical WordPress installation gives different permissions to Administrators, Editors, Authors, Contributors and Subscribers. Plugins can add their own roles and capabilities, and developers can create completely custom permission structures.
The important distinction is that WordPress does not fundamentally secure features by the human-readable name of a role. Its authorization system is primarily based on capabilities.
That distinction determines whether a restriction is merely cosmetic or actually prevents unauthorized actions.
For the underlying permission model, start with WordPress user roles and capabilities, explained.
Why restrict WordPress features by user role?
Not every user who can access /wp-admin/ needs access to every available feature.
Consider a company website with:
- Administrators maintaining WordPress;
- Editors managing editorial content;
- Authors writing articles;
- marketing users updating landing pages;
- SEO specialists managing metadata;
- temporary developers troubleshooting technical issues;
- clients who only need access to specific sections.
Giving every person broad administrative access because it is convenient creates unnecessary risk.
A better model follows the principle of least privilege: each user receives only the permissions required to perform their responsibilities.
If the role architecture of an existing site has grown organically over several years, perform an audit of WordPress user roles before adding more restrictions.
Roles and capabilities are not the same thing
A WordPress role is essentially a named collection of capabilities.
For example, conceptually:
Editor
├── edit_posts
├── edit_pages
├── edit_others_posts
├── publish_posts
├── publish_pages
└── moderate_comments
The exact capability set is what matters.
Two users can theoretically have different roles while still sharing a particular capability.
Likewise, plugins can add capabilities that have nothing to do with WordPress core roles.
This is why WordPress developers should normally ask:
Can this user perform this action?
rather than:
Does this user have this role name?
The official WordPress Roles and Capabilities documentation explains this permission model in detail.
Use current_user_can() for authorization
The standard WordPress function for checking the current user’s permissions is current_user_can().
A basic capability check looks like this:
if ( current_user_can( 'manage_options' ) ) {
// User may access this feature.
}
You can therefore restrict functionality according to what a user is actually allowed to do.
For example:
if ( ! current_user_can( 'manage_options' ) ) {
return;
}
This is generally more robust than manually inspecting the current user’s role name.
Why checking role names directly is usually weaker
You will sometimes encounter code like this:
$user = wp_get_current_user();
if ( in_array( 'administrator', $user->roles, true ) ) {
// Allow something.
}
This can work when you genuinely need to identify membership of a particular role.
It is not normally the best authorization strategy.
A custom role could legitimately have the required permission without being called Administrator.
A site may also support users with multiple roles. The architectural differences between creating dedicated roles and combining existing ones are covered in Custom WordPress roles vs. combining existing ones.
Primitive and meta capabilities
WordPress permissions become more interesting when access depends on a specific object.
For example:
current_user_can( 'edit_posts' );
asks whether the current user has the general capability to edit posts.
But:
current_user_can( 'edit_post', $post_id );
asks whether the current user can edit a particular post.
The second form uses a meta capability that WordPress maps to the primitive capabilities required in that specific context.
The underlying mechanism is documented in map_meta_cap().
This matters when restrictions depend on ownership, post status, post type or another contextual condition.
Hiding a feature is not the same as restricting it
This is the most important practical rule in this entire subject.
Suppose you hide the Plugins menu from Editors.
The interface may look cleaner, but hiding a menu does not automatically remove the user’s underlying capability to access whatever operation the menu represented.
WordPress explicitly notes this distinction in its documentation for administration menus: removing a menu does not itself prevent direct access.
You therefore need to separate two concepts:
- UI restriction — remove irrelevant controls from the interface;
- authorization restriction — prevent the user from performing the protected operation.
Good implementations often use both.
Restricting WordPress admin menu items by role
One common requirement is simplifying the WordPress admin menu for different user groups.
For example, an editorial user might need:
Dashboard
Posts
Media
Pages
Comments
but not:
Appearance
Plugins
Tools
Settings
The visual side of this process is covered in How to Hide WordPress Admin Menu Items by Role.
WordPress provides remove_menu_page() for removing top-level menu entries.
For example:
add_action( 'admin_menu', function () {
if ( ! current_user_can( 'manage_options' ) ) {
remove_menu_page( 'tools.php' );
remove_menu_page( 'options-general.php' );
}
}, 999 );
This creates a cleaner interface for users who cannot manage site options.
If the objective is broader restructuring rather than simple restriction, see How to Reorganize the WordPress Admin Menu.
Restricting submenu pages
Submenus can be removed with remove_submenu_page().
For example:
add_action( 'admin_menu', function () {
if ( ! current_user_can( 'manage_options' ) ) {
remove_submenu_page(
'themes.php',
'theme-editor.php'
);
}
}, 999 );
Again, this should be treated as interface management rather than a complete security boundary.
Restricting access to an admin page
Suppose your plugin provides a configuration screen that should only be available to privileged users.
When registering the page, specify the required capability:
add_menu_page(
'Site Configuration',
'Site Configuration',
'manage_options',
'site-configuration',
'render_site_configuration'
);
The capability argument controls who should be able to access the menu page.
The official add_menu_page() reference also recommends checking the required capability inside the callback handling the page.
For example:
function render_site_configuration() {
if ( ! current_user_can( 'manage_options' ) ) {
wp_die( 'You are not allowed to access this page.' );
}
// Render page.
}
This gives you both interface-level and execution-level protection.
For a deeper treatment of this particular problem, see Controlling WordPress Admin Page Visibility by Role.
Restricting custom post types
Custom post types can have their own capability model.
This is particularly useful when a custom content structure should be managed only by a particular team.
Imagine a site containing:
Posts
Pages
Products
Case Studies
Internal Documents
The people managing public articles may not need permission to modify internal documents.
The register_post_type() API supports capability_type, custom capabilities and map_meta_cap.
A simplified example could look like:
register_post_type(
'internal_document',
array(
'public' => false,
'show_ui' => true,
'capability_type' => array(
'internal_document',
'internal_documents'
),
'map_meta_cap' => true,
)
);
This allows WordPress to generate a capability structure specifically for that content type.
Before designing permissions for a custom content model, it helps to understand WordPress post types vs. custom post types.
Custom capabilities for application-specific features
Sometimes an existing WordPress capability is too broad.
Suppose a plugin provides an analytics dashboard.
Using:
manage_options
would effectively make the feature Administrator-oriented.
Instead, you might create:
view_company_analytics
and assign that capability only to the appropriate roles.
For example:
$role = get_role( 'editor' );
if ( $role ) {
$role->add_cap( 'view_company_analytics' );
}
The feature can then check:
if ( ! current_user_can( 'view_company_analytics' ) ) {
wp_die( 'You are not allowed to access this feature.' );
}
This is much more expressive than pretending every privileged user needs to be an Administrator.
If the site requires a genuinely new responsibility group, see Creating a Custom WordPress Role Safely.
Restricting publishing without restricting editing
Editorial workflows often need users who can prepare content but cannot publish it independently.
WordPress capabilities already support this distinction.
For example, publishing posts depends on capabilities such as:
publish_posts
while editing permissions are controlled separately.
This allows workflows where a user can:
- create a post;
- edit the post;
- upload or select media if permitted;
- save drafts;
but cannot publish the content until someone with greater editorial authority approves it.
This is usually better than building a completely separate publishing system when the native capability model already represents the required workflow.
Restricting plugin and theme management
Plugin and theme management are high-impact administrative operations.
Relevant capabilities include permissions related to:
install_plugins
activate_plugins
update_plugins
delete_plugins
install_themes
switch_themes
update_themes
delete_themes
A user who only manages content rarely needs these capabilities.
Removing unnecessary technical permissions reduces both accidental changes and the consequences of a compromised account.
Periodic permission reviews can be combined with the process described in Auditing WordPress Plugins on a Client Site.
Restricting settings pages
Many WordPress configuration operations depend on:
manage_options
This capability is intentionally powerful.
A common mistake is granting it simply because a user needs access to one custom settings screen.
Instead, consider giving that particular feature its own capability.
For example:
manage_marketing_settings
Then register the page against that capability:
add_menu_page(
'Marketing Settings',
'Marketing',
'manage_marketing_settings',
'marketing-settings',
'render_marketing_settings'
);
This creates a much narrower permission boundary.
Restricting features inside an existing page
You do not always need to restrict an entire admin screen.
Sometimes users can access a page but should not see or use one particular feature.
For example:
if ( current_user_can( 'publish_posts' ) ) {
// Show publishing controls.
}
or:
if ( current_user_can( 'manage_categories' ) ) {
// Show taxonomy-management controls.
}
This lets you build interfaces whose functionality adapts to the user’s effective permissions.
Restricting taxonomy management
Taxonomies also have capability controls.
A user might be allowed to assign existing taxonomy terms without being allowed to create, edit or delete terms.
This distinction can be valuable on large editorial sites where taxonomy structure needs centralized governance.
For a broader explanation of how classifications work across WordPress content structures, see WordPress Taxonomies Beyond Posts and Pages.
Restricting the WordPress toolbar
Role-based customization can also extend to the toolbar displayed at the top of WordPress.
For example, different users might see different shortcuts according to their responsibilities.
A content editor may need:
Edit Post
New Post
Media
while a technical administrator might additionally need:
Plugins
Updates
Site Configuration
Maintenance Tools
For this interface specifically, see Customizing the WordPress Toolbar for Different Roles.
The broader toolbar architecture is covered in WordPress Admin Bar Customization Guide.
Removing toolbar items is still not authorization
The same principle that applies to admin menus applies to toolbar nodes.
Removing a shortcut only removes the shortcut.
It does not automatically revoke the capability behind the destination.
If you need to clean up toolbar items, see How to Remove Items from the WordPress Admin Bar, but keep capability enforcement separate.
Restricting functionality based on the current user
When checking a user other than the currently logged-in account, WordPress provides user_can().
For example:
$user = get_user_by( 'id', $user_id );
if ( $user && user_can( $user, 'edit_posts' ) ) {
// This user can edit posts.
}
This is useful for:
- administrative reports;
- permission audits;
- workflow routing;
- user-management interfaces;
- automated checks;
- role migration tools.
Roles are useful for targeting, not just authorization
There are legitimate situations where the role itself matters.
For example, you may want to:
- send a notice only to Editors;
- redirect Subscribers after login;
- show different onboarding instructions;
- customize dashboards;
- change toolbar shortcuts;
- provide role-specific documentation.
These are audience-targeting decisions rather than strict authorization checks.
For those scenarios, see How to Target WordPress Users by Role.
Role-based redirects
A related technique is sending users to different areas after authentication.
For example:
Administrator → Dashboard
Editor → Posts
Customer → Account
Subscriber → Profile
This can improve usability, but a redirect is not a security boundary either.
Users must still be prevented from accessing protected destinations when they enter the URL manually.
The mechanics are explained in WordPress Login Redirects by Role, Explained and Redirecting Users by Role in WordPress.
User metadata should not replace capabilities
WordPress user metadata is useful for storing attributes about users.
For example:
department
office_location
onboarding_completed
preferred_language
account_reference
Those values can help determine how an interface behaves.
But arbitrary user metadata should not casually replace WordPress’s authorization model.
For the distinction between user properties and actual permissions, see WordPress User Meta, Explained.
Restricting REST API operations
Feature restrictions must also account for interfaces outside the visible WordPress admin.
If an operation is exposed through the REST API, hiding its admin button is irrelevant to API authorization.
Custom REST routes should define appropriate permission callbacks.
Conceptually:
'permission_callback' => function () {
return current_user_can( 'manage_options' );
}
The same principle applies to other programmatic interfaces: every privileged operation needs authorization at the point where it is executed.
AJAX actions need their own permission checks
A hidden button does not secure an AJAX endpoint.
If an authenticated AJAX handler performs a privileged operation, verify the user’s capability inside the handler.
For example:
add_action( 'wp_ajax_my_admin_action', function () {
if ( ! current_user_can( 'manage_options' ) ) {
wp_send_json_error(
array( 'message' => 'Permission denied.' ),
403
);
}
// Perform protected operation.
} );
A nonce should generally be used to protect the request from cross-site request forgery, but a nonce does not replace authorization.
Do not confuse nonces with permissions
A WordPress nonce answers a question roughly equivalent to:
Did this request originate from an expected interaction?
A capability check answers:
Is this user allowed to perform the action?
Those are different questions.
A secure privileged operation commonly needs both.
check_admin_referer( 'save_company_settings' );
if ( ! current_user_can( 'manage_options' ) ) {
wp_die( 'Permission denied.' );
}
Do not rely on CSS to restrict features
This is not access control:
.plugin-settings {
display: none;
}
Neither is JavaScript that removes a button from the DOM.
CSS and JavaScript can improve interface presentation, but authorization must be enforced server-side.
The same distinction appears when manipulating the admin toolbar, which is why WordPress Admin Bar Removal vs. CSS Hiding Tricks is relevant beyond toolbar customization itself.
Restricting features for multiple-role users
Sites that allow multiple roles per user require extra care.
Consider:
Role A → can edit products
Role B → can manage orders
A user holding both roles may legitimately need both capability sets.
Restrictions based purely on detecting one role can therefore produce surprising results.
Capability checks naturally handle this model better because WordPress evaluates the user’s effective permissions.
Restricting features on WordPress Multisite
Multisite adds another layer to the permission model.
The same user can have different permissions on different sites within the network.
WordPress provides current_user_can_for_site() for checking a capability in the context of a particular site.
Super Administrator permissions also need special consideration because network-level authority differs from ordinary site administration.
Do not permanently modify roles on every page load
A common implementation mistake looks like:
$role = get_role( 'editor' );
$role->add_cap( 'some_capability' );
inside code that executes on every request.
Role capability changes are persistent.
They should normally happen during a controlled lifecycle event such as plugin activation, migration or explicit settings changes, rather than being rewritten continuously.
Be careful when removing capabilities
Removing a capability from a standard role can affect functionality provided by WordPress core, themes and plugins.
Before changing permissions:
- identify what currently uses the capability;
- check whether plugins depend on it;
- test representative users;
- document the previous configuration;
- keep a recovery path.
This is especially important on client sites where years of plugin installations may have created capabilities that are no longer obvious.
Audit historical roles and capabilities
WordPress sites frequently accumulate permission debris.
You may discover:
- roles created by plugins that were removed years ago;
- custom capabilities with no remaining purpose;
- former contractors retaining Administrator access;
- temporary accounts that became permanent;
- custom roles with Administrator-like permissions;
- users holding several overlapping roles.
This is why role restrictions should be treated as part of an ongoing access-control process rather than a one-time interface customization.
The practical workflow in How to Audit User Roles on a WordPress Site is particularly useful before restructuring an established installation.
Role restriction and temporary access
Temporary access deserves special treatment.
If a developer needs administrative permissions for three days, the easiest approach is often to grant Administrator access and remember to remove it later.
The obvious problem is the phrase “remember to remove it later.”
Temporary access should ideally:
- have a defined purpose;
- have the minimum necessary permissions;
- have an expiration;
- be attributable to a specific person;
- be reviewed when the work is complete.
Design permissions around responsibilities
A maintainable permission architecture starts with responsibilities rather than WordPress role names.
For example:
Content Writer
- Create articles
- Edit own articles
- Upload media
Content Editor
- Edit all articles
- Publish articles
- Moderate comments
Marketing Manager
- Edit landing pages
- Manage campaign settings
- View analytics
Site Administrator
- Configure WordPress
- Manage users
- Manage plugins
- Manage themes
You can then translate these responsibilities into capabilities.
This produces a system that is easier to understand and audit than assigning broad roles first and trying to remove unwanted features afterward.
Restrict by capability whenever permission is the real question
If the question is:
Can this person perform X?
check a capability.
If the question is:
Is this person part of audience Y?
a role may be appropriate.
That distinction avoids a surprising amount of fragile WordPress code.
Test restrictions using real non-administrator accounts
Testing while logged in as an Administrator is not sufficient.
Create representative accounts for the permission levels your site actually supports.
For example:
test-editor
test-author
test-marketing
test-support
Then test:
- admin menu visibility;
- direct admin URLs;
- editing permissions;
- publishing;
- deletion;
- media access;
- custom post types;
- taxonomy management;
- plugin-specific actions;
- AJAX requests;
- REST API requests;
- toolbar actions;
- login redirects.
Test direct URLs, not just menus
If you remove a Settings menu item, manually test:
/wp-admin/options-general.php
If you hide a custom plugin page, manually test its URL.
If you remove an editing button, test the action directly with an account that should not have permission.
The user should be denied because of authorization rules, not because the navigation path happened to disappear.
A practical role-restriction architecture
A reliable implementation usually has several layers.
1. Define responsibilities
Document what each user group needs to do.
2. Map responsibilities to capabilities
Prefer existing WordPress capabilities when they accurately represent the permission.
3. Add custom capabilities when necessary
Do not grant manage_options simply because no narrower capability currently exists.
4. Enforce capabilities server-side
Protect PHP callbacks, REST endpoints, AJAX handlers and other privileged operations.
5. Simplify the interface
Hide controls that users cannot use anyway.
6. Test direct access
Do not assume hidden navigation equals restricted access.
7. Audit periodically
Responsibilities change, employees leave and plugins introduce new capabilities.
Common mistakes when restricting WordPress by role
Checking only for Administrator
This makes custom permission architectures unnecessarily difficult.
Hiding menus without securing actions
UI cleanup is not authorization.
Using CSS as security
Anything hidden with CSS still exists.
Using JavaScript as the only restriction
Client-side controls can be bypassed.
Giving users manage_options for convenience
This grants far more authority than most custom features require.
Using role names when capabilities are what matter
This makes custom roles and multi-role users harder to support.
Forgetting REST and AJAX endpoints
Backend authorization must protect every route through which the operation can be executed.
Assuming a nonce proves authorization
A valid nonce does not establish that the user should have permission to perform the action.
Never reviewing old capabilities
Permissions accumulate just like plugins, database entries and every other charming form of WordPress archaeology.
Restricting WordPress features with TheOneWP
On sites where different people manage different areas of WordPress, permission management becomes easier when restrictions can be configured consistently instead of scattered across theme functions, custom snippets and unrelated plugins.
TheOneWP can complement WordPress’s native role and capability system by centralizing administrative controls and role-oriented customization.
The underlying rule should remain the same: WordPress capabilities provide the security boundary, while role-based interface controls make the administration experience cleaner for each user group.
This is especially useful when building client sites where the people editing content should not have to navigate technical controls that have nothing to do with their daily work.
WordPress role restriction checklist
- Document every user group and its responsibilities.
- Understand the difference between roles and capabilities.
- Prefer capability checks for authorization.
- Use
current_user_can()for the current user. - Use object-aware meta capabilities where appropriate.
- Avoid hardcoding Administrator checks unnecessarily.
- Use custom capabilities for narrowly scoped custom features.
- Do not grant
manage_optionsmerely for convenience. - Hide irrelevant admin menu entries.
- Do not treat hidden menu entries as security.
- Protect admin-page callbacks.
- Protect REST API endpoints.
- Protect AJAX handlers.
- Use nonces and capability checks for different purposes.
- Restrict custom post types with appropriate capabilities.
- Review taxonomy-management permissions.
- Review plugin and theme management permissions.
- Review toolbar customization separately from authorization.
- Account for users with multiple roles.
- Account for Multisite permissions.
- Review temporary access.
- Test representative non-administrator accounts.
- Test direct URLs.
- Audit old roles and capabilities periodically.
- Document custom permission architecture.
Related guides
- WordPress User Roles and Capabilities, Explained
- How to Audit User Roles on a WordPress Site
- Custom WordPress Roles vs. Combining Existing Ones
- How to Hide WordPress Admin Menu Items by Role
- Controlling WordPress Admin Page Visibility by Role
Final recommendation
Restricting WordPress features by user role works best when you stop thinking of roles as the security mechanism itself.
Roles are convenient collections of permissions. Capabilities are what WordPress actually uses to answer the more important question: whether a user may perform a particular operation.
Build restrictions around that distinction.
Use capabilities to protect sensitive operations server-side. Then customize menus, toolbar nodes, buttons and screens so users see an interface appropriate to their responsibilities.
Do not rely on hiding menu entries, CSS, JavaScript or redirects as substitutes for authorization. A user who is not permitted to perform an operation should remain blocked even when they know the exact URL or construct the request manually.
For custom functionality, prefer narrowly defined capabilities instead of handing out broad permissions such as manage_options. This makes the site’s permission architecture easier to understand, safer to maintain and considerably easier to audit later.
Finally, treat access control as something that changes over time. Users change responsibilities, plugins introduce new capabilities, contractors leave, custom roles accumulate and temporary access has an impressive human tendency to become permanent.
Review the permission model periodically, test it with real non-administrator accounts and keep the distinction between interface visibility and actual authorization explicit. That produces a WordPress backend that is both cleaner for users and substantially harder to misuse.

