How To

Custom Admin and Tool Bar Icons

Messing with toolbars and icons.

When you’re making a plugin, sometimes you need a sidebar icon. And adding those in is relatively simple, depending on how you do it. But when you’re adding in something to the toolbar, things get a little messier…

Dashicons and the Admin Sidebar Dashicons and the Admin Sidebar

The easiest way to add in an icon is to use a Dashicon – part of a set of icons developed by WordPress itself. These are designed to just work with WordPress, and you can include it in your call to add a menu page like so:

add_menu_page( 'HalfElf', 'HalfElf', 'manage_options', 'varnish-page', 'halfelf_settings_page', 'dashicons-carrot', 75 );

These will automatically change colors for you when people change their profile colors.

Top ↑

Dashicons and the Toolbar Dashicons and the Toolbar

But what if you want to add a menu to the toolbar? Well this is a little bit more complicated, due to the fact that there just isn’t a built in way to add that icon.

When you add in a toolbar menu, it looks like this:

add_action( 'admin_bar_menu', 'halfelf_add_admin_bar_menu', 999 );
function halfelf_add_admin_bar_menu( $wp_admin_bar ) {
	$args = array(
		'id'    => 'halfelf_add_admin_bar_menu',
		'title' => 'HalfElf',
		'href'  => '',
	$wp_admin_bar->add_node( $args );

While I think the array should accept ‘icon’, it doesn’t, which means you have two choices to add in your icon:

1) Put <span class="dashicons dashicons-carron"></span> in front of the ‘HalfElf’ on the title line
2) Use some CSS

Personally I pick option 2, because that will allow the icon to show when the screen is in mobile view, and all you see are the icons.

For that to work, I have the following custom CSS:

#wpadminbar #wp-admin-bar-purge-varnish-cache .ab-icon:before {
	content: '\f511'; 
	top: 4px;

@media screen and (max-width: 782px) {
	#wpadminbar li#wp-admin-bar-purge-varnish-cache{
		display: block!important;

I call it on the front and back end, and this works pretty well.

Top ↑

Adding a Custom SVG Adding a Custom SVG

But. What happens when your coworker doesn’t like your joke about the carrot? Well now we’re into the weird land of “I want to use a Custom SVG for my admin bar and my toolbar.” And this is strange because while you can just echo out the SVG, the color can be a bit of a mess. Unlike a font-icon, SVGs don’t always play nicely with the sidebar. You have to define their colors in order for the fill replacement to work, and even then I found out that it doesn’t go well with the toolbar!

I lifted a page from Yoast SEO, who uses a function get_icon_svg() and calls it in place of 'dashicons-carrot', making my menu this:

add_menu_page( 'HalfElf', 'HalfElf', 'manage_options', 'varnish-page', 'halfelf_settings_page', get_icon_svg( true, '#82878c' ), 75 );

Yoasties, if you’re wondering why I have the extra variable, let me explain.

In their default, they have a one parameter, the true/false, and it defaults to true, so they just use get_icon_svg() and call it a day. But I had cases where I wanted things to have specific colors, so I added in a parameter for the color. In addition, I put in some extra checks on how to determine the color based on what admin colors the user had selected:

function get_icon_svg( $base64 = true, $icon_color = false ) {
	global $_wp_admin_css_colors;

	$fill = ( false !== $icon_color )? sanitize_hex_color( $icon_color ) : '#82878c';

	if ( is_admin() && false === $icon_color  ) {
		$admin_colors  = json_decode( json_encode( $_wp_admin_css_colors ), true ) ;
		$current_color = get_user_option( 'admin_color' );
		$fill          = $admin_colors[$current_color]['icon_colors']['base'];

	$svg = '<svg version="1.1" xmlns="" xml:space="preserve" width="100%" height="100%" style="fill:' . $fill . '" viewBox="0 0 36.2 34.39" role="img" aria-hidden="true" focusable="false"><g id="Layer_2" data-name="Layer 2"><g id="Layer_1-2" data-name="Layer 1"><path fill="' . $fill . '" d="M24.41,0H4L0,18.39H12.16v2a2,2,0,0,0,4.08,0v-2H24.1a8.8,8.8,0,0,1,4.09-1Z"/><path fill="' . $fill . '" d="M21.5,20.4H18.24a4,4,0,0,1-8.08,0v0H.2v8.68H19.61a9.15,9.15,0,0,1-.41-2.68A9,9,0,0,1,21.5,20.4Z"/><path fill="' . $fill . '" d="M28.7,33.85a7,7,0,1,1,7-7A7,7,0,0,1,28.7,33.85Zm-1.61-5.36h5V25.28H30.31v-3H27.09Z"/><path fill="' . $fill . '" d="M28.7,20.46a6.43,6.43,0,1,1-6.43,6.43,6.43,6.43,0,0,1,6.43-6.43M26.56,29h6.09V24.74H30.84V21.8H26.56V29m2.14-9.64a7.5,7.5,0,1,0,7.5,7.5,7.51,7.51,0,0,0-7.5-7.5ZM27.63,28V22.87h2.14v2.95h1.81V28Z"/></g></g></svg>';

	if ( $base64 ) {
		return 'data:image/svg+xml;base64,' . base64_encode( $svg );

	return $svg;

Personally I find it pretty crazy, and the icon on the toolbar doesn’t reflect the changes until the page is reloaded, but that’s a small price to pay since it doesn’t happen all that often.