11 Hacks for the WordPress Admin Bar (Toolbar)

Since version 3.1, WordPress has introduced the "Admin Bar," the purpose of which was to provide quick access to the admin panel pages. And as of version 3.3, it slightly changed its purpose and became known as the "Toolbar." Externally and in the code, nothing has changed, but the approach has changed: now it fully supports the frontend of the site.

In this note, I will gather various techniques for modifying this toolbar: adding, modifying, removing elements, etc.

To create a toolbar in WordPress, there is a separate class WP_Admin_Bar and a number of functions. Essentially, the work of the entire toolbar is described in these two files. If you cannot find something in this article, you can try to figure it out there.

To insert code, you can use a plugin: Code Snippets

See more examples in the description of WP_Admin_Bar.

Convenient hiding of the Toolbar

I don't like how the admin toolbar is positioned at the top in the frontend. It often doesn't harmonize with the design, but I can live with that. However, when it starts to interfere with scrolling or additional floating panels, something definitely needs to be done.

In my opinion, the most versatile solution is to make this panel collapsible. This way, it won't interfere when it's not needed.

I searched for plugins on this matter, but found some monsters. So, I had to write my own code. I like what I've come up with; in some cases, it's very convenient: not only does the panel not interfere, it can also accommodate more elements. The essence is that the panel appears when hovering over the icon in the upper left corner and it appears in a vertical view, rather than a horizontal one. It's a kind of collapsing of the admin bar.

Here's how it looks on the Twenty Twenty-One theme:

The code that makes these transformations:

<?php

/**
 * Сollapse ADMIN-BAR (Toolbar) into left-top corner.
 *
 * @version 1.0
 */
final class Kama_Collapse_Toolbar {

	public static function init(){
		add_action( 'admin_bar_init', [ __CLASS__, 'hooks' ] );
	}

	public static function hooks(){

		// remove html margin bumps
		remove_action( 'wp_head', '_admin_bar_bump_cb' );

		add_action( 'wp_head', [ __CLASS__, 'collapse_styles' ] );
	}

	public static function collapse_styles(){

		// do nothing for admin-panel.
		// Remove this if you want to collapse admin-bar in admin-panel too.
		if( is_admin() ){
			return;
		}

		ob_start();
		?>
		<style id="kama_collapse_admin_bar">
			#wpadminbar{ background:none; float:left; width:auto; height:auto; bottom:0; min-width:0 !important; }
			#wpadminbar > *{ float:left !important; clear:both !important; }
			#wpadminbar .ab-top-menu li{ float:none !important; }
			#wpadminbar .ab-top-secondary{ float: none !important; }
			#wpadminbar .ab-top-menu>.menupop>.ab-sub-wrapper{ top:0; left:100%; white-space:nowrap; }
			#wpadminbar .quicklinks>ul>li>a{ padding-right:17px; }
			#wpadminbar .ab-top-secondary .menupop .ab-sub-wrapper{ left:100%; right:auto; }
			html{ margin-top:0!important; }

			#wpadminbar{ overflow:hidden; width:33px; height:30px; }
			#wpadminbar:hover{ overflow:visible; width:auto; height:auto; background:rgba(102,102,102,.7); }

			/* the color of the main icon */
			#wp-admin-bar-<?= is_multisite() ? 'my-sites' : 'site-name' ?> .ab-item:before{ color:#797c7d; }

			/* hide wp-logo */
			#wp-admin-bar-wp-logo{ display:none; }
			/* #wp-admin-bar-search{ display:none; } */

			/* edit for twentysixteen */
			body.admin-bar:before{ display:none; }

			/* for almin panel --- */
			@media screen and ( min-width: 782px ) {
				html.wp-toolbar{ padding-top:0 !important; }
				#wpadminbar:hover{ background:rgba(102,102,102,1); }
				#adminmenu{ margin-top:48px !important; }
			}

			/* Gutenberg */
			#wpwrap .edit-post-header{ top:0; }
			#wpwrap .edit-post-sidebar{ top:56px; }
		</style>
		<?php
		$styles = ob_get_clean();

		echo preg_replace( '/[\n\t]/', '', $styles ) ."\n";
	}

}

Now you need to copy this code into a file, include that file in functions.php, and start the class like this:

Kama_Collapse_Toolbar::init();

Another simple implementation option:

<?php

final class Jackky_Collapse_Admin_Bar
{
	public static function init()
	{
		add_action( 'admin_bar_init', [ __CLASS__, 'hooks' ] );
	}

	public static function hooks()
	{
		// remove html margin bumps
		remove_action( 'wp_head', '_admin_bar_bump_cb' );

		add_action( 'wp_enqueue_scripts', [ __CLASS__, 'collapse_styles' ] );
		add_action( 'admin_bar_menu', [ __CLASS__, 'remove_nodes' ], 999 );
	}

	public static function collapse_styles()
	{
		$styles = "
			#wpadminbar
			{
				transition: clip-path .3s ease 1s, background-color .2s ease 1s;

				clip-path: polygon( 0 0, 32px 0, 32px 100%, 0 100% );
			}

			#wpadminbar:not( :hover )
			{
				background-color: rgba( 29, 35, 39, 0 );
			}

			#wpadminbar:not( :hover ) .ab-item::before
			{
				color: #1d2327;

				transition-delay: 1s;
			}

			#wpadminbar .ab-item
			{
				position: relative;
			}

			#wpadminbar #wp-admin-bar-site-name > .ab-item::after
			{
				content: '';
				position: absolute;
				top: 7px;
				left: 7px;
				z-index: -1;

				width: 20px;
				height: 20px;

				border-radius: 50%;

				background-color: #fff;

				opacity: .8;

				transition: opacity .2s ease 1s;
			}

			#wpadminbar:hover #wp-admin-bar-site-name > .ab-item::after
			{
				opacity: 0;

				transition-delay: 0s;
			}

			#wpadminbar:not( :hover ) > *
			{
				pointer-events: none;
			}

			#wpadminbar:hover
			{
				transition-delay: 0s;

				clip-path: polygon( 0 0, 100% 0, 100% 100vh, 0 100vh );
			}

			@media screen and ( max-width: 782px )
			{
				#wpadminbar
				{
					clip-path: polygon( 0 0, 50px 0, 50px 100%, 0 100% );
				}
			}
		";

		wp_register_style( 'collapse-admin-bar', false );
		wp_add_inline_style( 'collapse-admin-bar', $styles );
		wp_enqueue_style( 'collapse-admin-bar' );
	}

	public static function remove_nodes( $wp_admin_bar )
	{
		$wp_admin_bar->remove_node( 'wp-logo' );
		$wp_admin_bar->remove_node( 'search' );
	}
}

add_action( 'init', [ Jackky_Collapse_Admin_Bar::class, 'init' ] );

You need to insert this code into functions.php, or create a plugin from it if you frequently change templates.

To make the code work, the wp_footer() function must be called in the theme's footer.php.

Removing basic elements (links) from the toolbar

I've seen a solution to this task on the internet - it's slightly incorrect everywhere because the items are removed after they have been added to the panel. It would be preferable not to add them there at all. This is done as follows:

## Removing Basic Elements (Links) from the Toolbar
add_action( 'add_admin_bar_menus', function(){
	/* available for removal:

	remove_action( 'admin_bar_menu', 'wp_admin_bar_my_account_menu', 0 );  // Internal profile menu links
	remove_action( 'admin_bar_menu', 'wp_admin_bar_search_menu', 4 );      // Search
	remove_action( 'admin_bar_menu', 'wp_admin_bar_my_account_item', 7 );  // Entire profile menu

	// Site-related
	remove_action( 'admin_bar_menu', 'wp_admin_bar_sidebar_toggle', 0 );   //
	remove_action( 'admin_bar_menu', 'wp_admin_bar_wp_menu', 10 );         // WordPress links (WordPress logo)
	remove_action( 'admin_bar_menu', 'wp_admin_bar_my_sites_menu', 20 );   // My sites
	remove_action( 'admin_bar_menu', 'wp_admin_bar_site_menu', 30 );       // Sites
	remove_action( 'admin_bar_menu', 'wp_admin_bar_customize_menu', 40 );  // Customize theme
	remove_action( 'admin_bar_menu', 'wp_admin_bar_updates_menu', 50 );    // Updates

	// Content related.
	if ( ! is_network_admin() && ! is_user_admin() ) {
		// Comments
		remove_action( 'admin_bar_menu', 'wp_admin_bar_comments_menu', 60 );
		// Add post, page, media, etc.
		remove_action( 'admin_bar_menu', 'wp_admin_bar_new_content_menu', 70 );
	}
	// Edit
	remove_action( 'admin_bar_menu', 'wp_admin_bar_edit_menu', 80 );

	// The additional group (search and account) is located on the right in the menu
	remove_action( 'admin_bar_menu', 'wp_admin_bar_add_secondary_groups', 200 );
	*/

	// Remove
	remove_action( 'admin_bar_menu', 'wp_admin_bar_customize_menu', 40); // Customize theme
	remove_action( 'admin_bar_menu', 'wp_admin_bar_search_menu', 4 );    // Search
	remove_action( 'admin_bar_menu', 'wp_admin_bar_wp_menu', 10 );      // WordPress links (WordPress logo)
});

The commented lines indicate the panel items that can be removed. In this example, the following items have been removed: "Customize", "Search", and the main WordPress links item.

Removing/Disabling the Toolbar

First of all, the toolbar can be disabled on the profile page and in the admin panel: Users > Profile.

But when you need to disable it globally, use the function show_admin_bar().

See also:

Examples of different disabling options:

Soft Disabling

Suppose we need to disable the "Toolbar" on the front end of the site. However, we need to allow plugins to enable the toolbar through the show_admin_bar filter.

To do this, insert the following line into the theme's functions.php file:

show_admin_bar( false );

Completely Disable the Toolbar

On the front end and in the admin panel:

// Disable admin bar on the front end
add_filter( 'show_admin_bar', '__return_false' );

// Disable admin bar in the admin panel
remove_action( 'in_admin_header', 'wp_admin_bar_render', 0 );

Disable the Toolbar for Everyone Except Administrators (on the front end)

In this example, the toolbar is not disabled in the admin panel.

add_filter( 'show_admin_bar', 'admin_bar_for_admin_only', 99 );

function admin_bar_for_admin_only( $show_admin_bar ) {

	if ( $show_admin_bar && ! current_user_can( 'manage_options' ) ) {
		$show_admin_bar = false;
	}

	return $show_admin_bar;
}

Similarly, you can disable the toolbar for any role. Instead of the capability 'manage_options', specify the appropriate capability for the role, see the list of capabilities here. Here are some of them:

  • publish_posts - author
  • edit_others_posts - editor

Disable the Toolbar for Network Administrators

add_filter( 'show_admin_bar', 'admin_bar_for_admin_only', 99 );

function admin_bar_for_admin_only( $show_admin_bar ) {

	if ( $show_admin_bar && ! is_network_admin() ) {
		$show_admin_bar = false;
	}

	return $show_admin_bar;
}

And similarly, you can disable the toolbar using conditional tags or other checks.

Removing any elements (links) from the toolbar

It is better to remove basic elements using the method described above (however, this is not essential). This method can be used to remove additional elements added by non-WordPress plugins.

To remove, use the remove_menu() or remove_node() method — they are absolutely identical methods (aliases).

Suppose a plugin adds an item with the ID mymenu to the menu, and we need to remove this item:

// Remove item from the toolbar
add_action( 'wp_before_admin_bar_render', 'delete_item_from_toolbar', 99 );
function delete_item_from_toolbar() {
	global $wp_admin_bar;
	$wp_admin_bar->remove_menu('mymenu');
}

Adding elements (links) to the toolbar

To add links, use the WP_Admin_Bar::add_menu() method, also known as WP_Admin_Bar::add_node(). The addition should be done on the admin_bar_menu hook.

You can add both top-level links and child links. For example, let's add a link and a child link to the toolbar:

// Adds a link to the admin bar
add_action( 'admin_bar_menu', 'my_admin_bar_menu', 30 );
function my_admin_bar_menu( $wp_admin_bar ) {
	$wp_admin_bar->add_menu( array(
		'id'    => 'menu_id',
		'title' => 'External Link',
		'href'  => 'http://example.com',
	) );

	// child link
	$wp_admin_bar->add_menu( array(
		'parent' => 'menu_id', // id parameter from the first link
		'id'     => 'some_id', // your id to be able to add child links
		'title'  => 'Child Link',
		'href'   => 'http://example.com/subpage',
	) );
}

As a result, we will get:

To change the position of the entire block of links, (put it before or after a certain block), change the number 30 — the larger the number, the closer to the end.

Another example: a child link in the site menu to the plugins page

// child link in the site menu to the plugins page
if( ! is_admin() ){
	add_action( 'admin_bar_menu', function ( $wp_admin_bar ) {
		$wp_admin_bar->add_menu( array(
			'parent' => 'site-name', // id of the parent element
			'id'     => 'plugins_link', // your id to be able to add child links
			'title'  => 'Plugins',
			'href'   => admin_url('plugins.php'),
		) );
	}, 100 );
}

See the list of all possible parameters in WP_Admin_Bar::add_menu().

Icon (dashicon) for admin bar

For doing this you need additional to dashicons class add ab-icon class to HTML element specified in title attribute. Let's look at such example:

add_action( 'admin_bar_menu', 'add_toolbar_link', 70 );

function add_toolbar_link( $wp_admin_bar ){

	$wp_admin_bar->add_menu( [
		'id'    => 'chartlink',
		'title' => '<span class="ab-icon dashicons-visibility"></span><span class="ab-label">Views</span>',
		'href'  => '#',
	] );
}

As a result, we will get:

How to find the $id of an existing toolbar element

To find the $id of an existing panel element in order to remove it or to add a child element to it, look at this ID in the source code: it is added as a suffix in the id attribute of the LI tag: wp-admin-bar-{ID}:

You can also find the element in the code of WordPress or a plugin, but this is more difficult.

Removing only the top margin from the toolbar

To ensure that the toolbar is displayed correctly, WordPress adds a 28px margin to the HTML and BODY tags. If this margin needs to be removed for some purposes, use this code:

add_action( 'admin_bar_init', function(){
	remove_action( 'wp_head', '_admin_bar_bump_cb' ); // html margin bumps
} );

This option removes the function that adds CSS styles.

Adding a custom menu to the toolbar

This feature can be practically indispensable because, in addition to convenience, it also adds functionality.

By using the following code, we register the navigation menu wp_nav_menu and add items from this menu to the toolbar.

/**
 * toolbar nav menu - навигационное меню в тулбаре
 * v0.3
 */
add_action( 'after_setup_theme', function() {
	register_nav_menu( 'toolbar', 'Toolbar' );
} );

add_action( 'admin_bar_menu', 'kama_add_toolbar_menu', 999 );
function kama_add_toolbar_menu( $toolbar ) {
	$locations = get_nav_menu_locations();

	if( ! isset( $locations['toolbar'] ) ){
		return;
	}

	$items = wp_get_nav_menu_items( $locations['toolbar'] );

	if( ! $items ){
		return;
	}

	foreach( $items as $item ){
		$args = [
			'parent' => $item->menu_item_parent ? 'id_' . $item->menu_item_parent : false,
			'id'     => 'id_' . $item->ID,
			'title'  => $item->title,
			'href'   => $item->url,
			'meta'   => [
				'class'  => implode( ' ', $item->classes ),
				'title'  => esc_attr( $item->description ),
				'target' => $item->target,
			],
		];

		$toolbar->add_node( $args );
	}
}

How it works.

You add the code to functions.php. Then go to the admin panel: Appearance > Menus and create a menu, add any links to it, and attach the menu to the "Toolbar" area. You can use multiple levels, then the top level will be the main in the toolbar, and the additional ones will become a dropdown list.

Link to delete a post in the toolbar

The link to edit a post is always in the toolbar. But if posts are often deleted on the site, it is convenient to have a link for deletion, so you don't have to navigate to the post editing page for deletion.

add_action( 'admin_bar_menu', 'kama_delete_toolbar_link', 90 );
function kama_delete_toolbar_link() {
	global $wp_admin_bar;

	if ( ! is_super_admin() || ! is_admin_bar_showing() ){
		return;
	}

	$obj = get_queried_object();

	if ( ! $obj || ! isset( $obj->post_type ) ){
		return;
	}

	$dellink = get_delete_post_link( $obj->ID );

	if( $dellink ){
		$wp_admin_bar->add_menu( array(
			'id'    => 'delete',
			'title' => EMPTY_TRASH_DAYS ? 'Move to Trash' : 'Delete Post',
			'href'  => $dellink,
		) );
	}
}

Here, 90 means after the edit link (which is 80).

Always show the toolbar

A rare case, but such a need may arise. This code will always display the toolbar, even when the user is not logged in. But in this case, only the "Login" link will be displayed. It is specified in the code. By analogy, you can add some other links there:

// Always show the admin bar
add_filter( 'show_admin_bar', '__return_true' , 1000 );
add_action( 'admin_bar_menu', 'pjw_login_adminbar', 0 );

function pjw_login_adminbar( $wp_admin_bar) {
	if ( is_user_logged_in() ){
	  return;
	}

	$wp_admin_bar->add_menu( [
		'title' => 'Login',
		'href'  => wp_login_url()
	] );

	remove_action( 'admin_bar_menu', 'wp_admin_bar_wp_menu', 10 );
}

Replace "Hello" with "Greetings" in the toolbar

The informal word "Hello" displayed in the admin bar may not be suitable for all sites. Sometimes it needs to be replaced, let's do it:

add_action( 'admin_bar_menu', 'replace_wordpress_howdy', 25 );

/**
 * Replaces "Hello" with "Greetings" in the toolbar.
 *
 * @param WP_Admin_Bar $wp_admin_bar
 */
function replace_wordpress_howdy( $wp_admin_bar ) {
  $my_account = $wp_admin_bar->get_node( 'my-account' );

  if ( isset( $my_account->title ) ) {
	$newtext = str_replace( 'Hello,', 'Greetings,', $my_account->title ?? '' );

	$wp_admin_bar->add_node( [
	  'id'    => 'my-account',
	  'title' => $newtext,
	] );
  }

}

Multisite: move out sub-sites menu to the main menu of the Admin bar

If you have a multisite with only a few sub-sites, it is much more convenient to put all sub-sites in the main toolbar menu.

GitHub
/**
 * Сutomize multisite admin bar.
 * Moves default nested multisite menu to main toolbar menu.
 */
class Multisite_Admin_Bar {

	public static function init(): void {
		add_action( 'admin_bar_menu', [ __CLASS__, 'cutomize_toolbar' ], 31 ); // 31 - after `wp_admin_bar_site_menu()`
		add_action( 'wp_head', [ __CLASS__, 'styles' ] );
		add_action( 'admin_head', [ __CLASS__, 'styles' ] );

		add_action( 'admin_bar_menu', [ __CLASS__, 'add_switch_node' ], 30 );
	}

	public static function styles(): void {
		?>
		<style id="cutomize_multisite_admin_bar">
			#wp-admin-bar-network-admin .ab-icon:before{ color:#797c7d; } /* the color of the main icon */
			#wpadminbar .hl-current-blog{ background-color: rgba(255 255 255 / 0.15); }
		</style>
		<?php
	}

	public static function cutomize_toolbar( \WP_Admin_Bar $toolbar ): void {
		// for multisite only
		if( ! $toolbar->get_node( 'site-name' ) ){
			return;
		}

		// remove Multisite Language Switcher hook
		remove_action( 'admin_bar_menu', [ \lloc\Msls\MslsPlugin::class, 'update_adminbar' ], 999 );

		// NOTE: the closure needed to access `WP_Admin_Bar->nodes` private property
		$callback = function(){
			/** @var \WP_Admin_Bar $this */

			/// remove nodes
			unset(
				$this->nodes['site-name'], // default current site node
				$this->nodes['my-sites-super-admin'],
				$this->nodes['my-sites'],
				$this->nodes['my-sites-list']
			);

			/// network-admin
			$net_admin = & $this->nodes['network-admin'];
			$net_admin->parent = '';
			$net_admin->title = '<span class="ab-icon dashicons-admin-multisite"></span><span class="ab-label">Network</span>';

			/// blogs
			foreach( $this->nodes as $key => $node ){

				preg_match( '/blog-(\d+)(?:-(\w+))?/', $node->id, $mm );
				$blog_id = (int) ( $mm[1] ?? 0 );
				$type    = $mm[2] ?? '';

				if( $blog_id ){
					// main: blog-1, blog-2
					if( ! $type ){
						// title
						preg_match( '~^<.*>~', $node->title, $mm );
						$lang = langdata()->blog_id_lang( $blog_id );
						$title_icon_html = $mm[0] ?? '';
						$flag_img = sprintf( '<img src="%s" alt="%s">', langdata()->flag_url( $lang ), $lang );
						$node->title = $title_icon_html . $flag_img . '&nbsp;' . strtoupper( $lang );

						$node->href = is_admin() ? get_home_url( $blog_id ) : $node->href;
						$node->parent = '';
						$node->meta['class'] = ( get_current_blog_id() === $blog_id ) ? 'hl-current-blog' : '';
					}

					// comments: blog-1-c, blog-2-c
					if( 'c' === $type ){
						unset( $this->nodes[ $key ] );
					}
				}

			}

		};

		$callback->call( $toolbar );
	}

	public static function add_switch_node( \WP_Admin_Bar $toolbar ): void {
		global $pagenow;
		$url = $_SERVER['REQUEST_URI'];

		$url = str_starts_with( $url, '/ru' ) ? preg_replace( '~^/ru~', '', $url ) : "/ru$url";

		if( 'post.php' === $pagenow && ( $post_id = (int) ( $_GET['post'] ?? 0 ) ) ){
			$other_post_id = is_ru() ? get_ru_en_post_id( $post_id ) : get_en_ru_post_id( $post_id );
			$url = $other_post_id
				? str_replace( "post=$post_id", "post=$other_post_id", $url )
				: '';
		}

		$toolbar->add_menu( [
			'id'    => 'switch_langs',
			'title' => '<span class="ab-icon dashicons-controls-repeat"></span>',
			'href'  => $url,
			'meta'  => [
				'title' => 'Switch Curent Page to Opposite Lang',
				'onclick' => 'alert("aaaaaaaaa")',
			],
		] );
	}

}

Plugins for the admin bar (toolbar)

  • Clicky by Yoast - integrates a web analytics service into the admin bar.

  • What The File - an excellent plugin for studying the template hierarchy. It shows which template file is responsible for displaying the current page you are on. The information is displayed in the admin bar.

  • Admin Bar Disabler - allows you to remove the bar for specified roles: white and black lists. Or for specified capabilities: the possibility can also be placed in white and black lists. In general, this is a plugin for total customization of the admin bar.

  • All other plugins

  • Menu item adding generator - service