Restrict wp-admin Access for Non-Staff Roles
Redirects any logged-in user without real admin-area capabilities away from wp-admin and back to the front end, while still letting AJAX and REST requests through untouched.
- Difficulty
- Intermediate
- Reading time
- ~1 min
- Where to add it
- A small custom plugin
- Last updated
- WooCommerce
- Compatible
The Problem
On membership sites and WooCommerce stores, every registered customer or member technically has a wp-admin login, and by default WordPress lets any logged-in user open wp-admin — most menu items are hidden by capability checks, but the result is still a confusing, half-empty dashboard shown to someone who only wanted to check an order or update their account details. Beyond the poor experience, it also needlessly exposes an entire surface area — admin-only CSS and JS, plugin admin-page behavior, potential information disclosure through admin AJAX handlers — to accounts that never had a legitimate reason to see wp-admin in the first place.
The Code
add_action( 'admin_init', 'devmubs_restrict_admin_access' );
function devmubs_restrict_admin_access() {
if ( wp_doing_ajax() || defined( 'REST_REQUEST' ) ) {
return;
}
if ( current_user_can( 'edit_posts' ) ) {
return;
}
wp_safe_redirect( home_url( '/' ) );
exit;
}How It Works
`admin_init` fires on every wp-admin page load, which is why the very first check is `wp_doing_ajax() || defined( 'REST_REQUEST' )` — a large number of plugins (including WooCommerce) rely on admin-ajax.php and REST endpoints being reachable even for non-staff logged-in users, so this guard runs first and returns immediately for those request types, before any redirect logic can interfere with them. `current_user_can( 'edit_posts' )` is used as the practical threshold for "has legitimate wp-admin business": WordPress's default Subscriber role and WooCommerce's Customer role both lack this capability, while Author, Editor, and Administrator all have it, so the check cleanly separates staff-ish roles from customer-ish roles without hardcoding role names directly. Anyone who fails that check gets sent to the homepage via `wp_safe_redirect()` before wp-admin renders any further.
Where To Add This
A small custom plugin. This is server-side access logic entirely unrelated to the theme, so it belongs in a small plugin that keeps enforcing the rule regardless of which theme is active.
Warnings & Caveats
- Choose the capability check to match your own setup — if a plugin grants `edit_posts` to a role that genuinely shouldn't have wp-admin access on your site (or withholds it from a support-staff role that should), adjust the capability accordingly and test with every role you actually use before relying on this.
- Always back up your site before adding custom code.