Writing

How to hide the WordPress admin bar for subscribers, customers and members — without a plugin

· Kristoff Bertram

Somebody signs up for your membership site, logs in, and the first thing WordPress does is bolt a black toolbar across the top of the page with a logo they do not recognise and a menu they cannot use. Here is the ten-line fix — the show_admin_bar filter with a capability check — where to put it, and the two things it must not do.

Picture the site. A course platform, or a members’ area behind a small shop, or a club with a login so people can see the fixtures. Every account on it is a subscriber — or a customer, or a member, or whatever the plugin that created it decided to call the role. None of them will ever write a post. And every one of them, the moment they log in, gets the WordPress admin bar: the W logo, the site name, Howdy, and thirty-two pixels shaved off the top of a design somebody paid for.

Then the email arrives. “What is this black bar? Did I break something?” They did not. WordPress assumes anyone who is logged in wants a toolbar for running the site, because for the first ten years of its life that was true. On a site with members, it no longer is.

So: hide the admin bar for subscribers. Not for the editors, not for you, and — this is the part people get wrong — not inside /wp-admin/. Front end only, decided by what the user can do, in ten lines you own. No plugin from the directory required, although the recommended home for it is technically a plugin of one file, and I will get to that.

What the WordPress admin bar is for

It is worth being fair to the thing before removing it. The admin bar is the bridge between the site and its back office: Edit Page on whatever you are looking at, New for a post or a media upload, the comment count, the update count, Customize, and the account menu with Log Out in it. For anyone who works on the site it earns its thirty-two pixels several times a day.

Every one of those links is either useless to a subscriber or hidden from them already. What they get is the frame with nothing in it — a logo, a site name and a greeting — which is worse than either having the bar or not having it. The bar is for people who can edit. That sentence is also the test we are about to write.

The show_admin_bar filter, with a capability check

WordPress decides whether to render the bar in one function, is_admin_bar_showing(), and the last thing that function does before answering is run the show_admin_bar filter. Core’s own comment on it says returning false there is the recommended way to hide the admin bar. That is the whole mechanism. Everything else is deciding who.

Here is the decision:

add_filter( 'show_admin_bar', function ( bool $show ): bool {
    return current_user_can( 'edit_posts' ) ? $show : false;
}, 1000 );

Read it as a sentence: if this user can edit posts, leave the bar as WordPress and the user’s own preference already decided; otherwise, no bar. edit_posts is the capability every Contributor, Author, Editor and Administrator holds and no Subscriber does — it is where WordPress itself draws the line between “works on the site” and “reads the site”. If your site draws it somewhere else, swap the capability: edit_pages, the management capability your shop plugin registers, or one you have registered yourself. The shape stays the same.

Three small things about those three lines. The parameter arrives as a boolean — core hands you true, false, or the user’s own Show Toolbar when viewing site preference, already cast — so the type declarations are honest, not decorative. You do not need is_user_logged_in(): a visitor who is not logged in never reaches this filter with true, and current_user_can() is false for them anyway. And the priority, 1000, is a choice rather than a magic number: it runs after the theme and the other plugins have had their say, and for a user who cannot edit it should be the last word.

Why a capability and not a role name

The version of this snippet you will find in a hundred forum answers checks the role instead:

// Don't do this.
add_filter( 'show_admin_bar', function ( bool $show ): bool {
    return in_array( 'subscriber', wp_get_current_user()->roles, true ) ? false : $show;
}, 1000 );

It works on the day you write it and breaks quietly afterwards, because a role is a label over a set of capabilities, and the label is the part that changes. The shop plugin you install next year adds a customer role and a shop_manager role; your check knows about neither, so customers get the bar back and the shop manager — who genuinely needs it — is fine by accident. The membership plugin creates member, gold_member and trial. A colleague makes a custom role for the newsletter people. Somebody holds two roles at once. On a multisite, the super admin has a subscriber role on this particular site and your test hides the bar from the one person who most needs it.

WordPress never asks “what is this user’s role?” when it decides what they may do. It asks current_user_can(), every time, for every screen. Your snippet should ask the same question, so that the answer changes only when the permissions change — which is the one time you want it to.

Why you never hide the admin bar on wp-admin

Here is the safety property, and it is the reason this snippet is safe to paste on a live site at five o’clock on a Friday: the show_admin_bar filter only governs the front end. Open wp-includes/admin-bar.php and read is_admin_bar_showing() — the check for is_admin() comes before the filter runs and returns true unconditionally. Inside /wp-admin/ the bar is part of the interface, and core does not let a filter take it away. Whatever you return, every user who lands on /wp-admin/profile.php — and every subscriber can — sees the bar, with the account menu and Log Out in it.

Which means this snippet cannot lock anyone out. Not you, not an editor, not a subscriber. That is not a property of your code; it is a property of the filter, and it is why the filter is the right tool and the alternatives are not:

Two things the bar was quietly providing need a home once it is gone for non-editors. The logout path: the bar’s account menu carried Log Out, so give members a link the theme owns instead — a menu item that points at wp_logout_url(), or the log-out link on their account page, which every membership and shop plugin I have met puts there anyway. Do not hand-write /wp-login.php?action=logout; it needs a nonce, and wp_logout_url() adds it. The Edit links: nothing to do. The capability check leaves the bar exactly as it was for everyone who can edit, Edit Page included.

Where the snippet lives: mu-plugin, functions.php or a snippets plugin

Three places will run those lines. They differ in who can switch them off, and by accident.

A must-use plugin — recommended

wp-content/mu-plugins/ is a directory WordPress loads on every request, before the ordinary plugins, without asking. Anything in it appears under Plugins → Must-Use with no activate or deactivate link. It survives a theme switch, it survives a plugin clear-out, and nobody can turn it off from the admin — the only way to remove it is to remove the file. For a rule about who sees what, that is exactly the durability you want.

  1. Look for wp-content/mu-plugins/ beside plugins/ and themes/. Most sites do not have it. Create it.
  2. Save the complete script below as wp-content/mu-plugins/hide-admin-bar-for-non-editors.php. Directly in the directory, not in a subfolder — WordPress only loads the PHP files at the top level of mu-plugins/.
  3. Upload it however you deploy files. It is live on the next request; there is nothing to activate.
  4. Open Plugins → Must-Use and confirm it is listed.

The theme’s functions.php — simplest

Paste the add_filter call — just those three lines, not the plugin header, and not a second <?php if the file already opens with one — at the end of the active theme’s functions.php. Thirty seconds, and if you are already in the theme it is the natural place. The cost: it dies with the theme. Switch themes and the bar is back for every member; update a theme you did not build and the file may be overwritten. If it goes here, it goes in a child theme.

A snippets plugin — a UI, at a price

There is a whole category of plugins whose job is to hold PHP snippets and give you an admin screen to manage them. Paste the add_filter call into a new PHP snippet, scope it to the front end if the plugin offers that, save, enable. What you get is a UI and a description field. What you pay is another plugin, another thing that can be deactivated, and one more place for the next developer to look when the bar disappears and nobody remembers why. On a site that already runs one, fine. Do not install one for this.

The complete script

This is the mu-plugin form. It is a single file, no dependencies, PHP 7.4 or later — which is also where the arrow function in the aside below needs to be. Copy the whole thing.

<?php
/**
 * Plugin Name: Hide the admin bar for non-editors
 * Description: On the front end, hides the WordPress admin bar for logged-in users who cannot edit content. wp-admin is untouched.
 * Version:     1.0.0
 */

// The show_admin_bar filter only runs on the front end: is_admin_bar_showing()
// returns true for wp-admin before this is ever consulted, so nobody can be
// locked out. Swap 'edit_posts' for the capability that defines "works on the
// site" for you; keep it a capability, not a role name.
add_filter( 'show_admin_bar', function ( bool $show ): bool {
    return current_user_can( 'edit_posts' ) ? $show : false;
}, 1000 );

No declare( strict_types ), no if ( ! defined( 'ABSPATH' ) ) guard, no class. A must-use plugin is included by WordPress, not evaluated by anything else; the header is what puts it on the Must-Use list with a readable name, and the rest is the three lines from above.

Aside — disable the admin bar for non-admins instead. If the rule on your site is “only administrators see the bar”, the one-line variant is the same filter with a different capability:

add_filter( 'show_admin_bar', fn ( bool $show ): bool => current_user_can( 'manage_options' ) ? $show : false, 1000 );

manage_options is the capability that marks an administrator. Your editors lose the bar too, so they lose Edit Page too — decide that on purpose.

How to verify it

  1. As a subscriber. Open a private window, log in with a subscriber (or customer, or member) account, load the home page. No bar, and no thirty-two-pixel gap at the top — core only adds that spacer when the bar is showing, so it goes with it.
  2. As an editor. Another private window, an editor account, the same page. Bar present, Edit Page in it.
  3. On wp-admin, as either. Visit /wp-admin/profile.php with each account. Bar present both times. That is the safety property, seen rather than believed.
  4. The logout link. As the subscriber, find the log-out link you gave them and use it. If you cannot find it, neither can they.

If step one still shows the bar, the usual reasons are that the file is in a subfolder of mu-plugins/, that a page cache served the logged-in view from before the change, or that the account you are testing with holds a role that carries edit_posts after all — which, as above, is the test doing its job.

The other half: hiding it for the editors too

I should say where this piece comes from. My own plugin, Freshet Edit Jump, does the opposite: it hides the admin bar for the people who can edit — the same filter, current_user_can( 'edit_posts' ) the other way round — and gives them Cmd/Ctrl+E to jump to the edit screen of whatever they are looking at, which was the only thing they used the bar for anyway. It deliberately leaves the bar alone for everyone else, because that was never its job. Install both and nobody sees the bar at all: editors get a shortcut, members get their thirty-two pixels back. That is a choice, not a collision — the two filters pass each other’s answer straight through — and on a members’ site it is usually the right one.

Common questions

How do I hide the WordPress admin bar for subscribers without a plugin?

A show_admin_bar filter that returns false unless the user has edit_posts. Ten lines in wp-content/mu-plugins/, or in the theme’s functions.php, or in a snippets plugin you already run. The complete script is above.

Does hiding the admin bar lock users out of wp-admin?

No. is_admin_bar_showing() checks is_admin() before it runs the filter and always shows the bar inside wp-admin. Every logged-in user still reaches /wp-admin/profile.php with the bar, and Log Out, in place.

Why check a capability instead of the user’s role?

Because WordPress does. Roles are names for bundles of capabilities, and the names change: a shop plugin’s customer, a membership plugin’s member, a custom role, a user with two roles, a super admin on a multisite. current_user_can( 'edit_posts' ) is true for exactly the people who can edit, whatever the role is called this year.

Where do users log out if the admin bar is hidden?

From a link the theme gives them — wp_logout_url() in a menu, or the log-out link on their account page — and, failing both, from /wp-admin/profile.php, where the bar still shows.


More of the same, from the jobs that made me build things, on the blog.