How to Customize Your Top-Level Admin Menu Label and Icon

Registering a top-level menu item in WordPress is easy. Getting it to look good is the hard part. Let’s go over the customizations you can achieve by some custom code and CSS. We’ll be customizing the admin label, and showing you how to change the icons, organize submenus, and adding a CSS class.

Table of Contents

Introducing add_menu_page

The add_menu_page function
The add_menu_page function

We’ll be making use of function add_menu_page. First, we need to use hook admin_menu to register the menu.

add_action( 'admin_menu', 'dlx_menu_customizations_add_menu_items' );
function dlx_menu_customizations_add_menu_items() {
	$parent_menu_slug = 'dlx-menu-customizations';
	add_menu_page(
		'Custom Menu',
		'Custom Menu',
		'manage_options',
		$parent_menu_slug,
		'dlx_menu_customizations_menu_page',
		'dashicons-admin-generic',
		20
	);
}
Code language: PHP (php)

The function add_menu_page takes several arguments:

  • page_title: This is the title of the admin panel options, although it’s only useful when using the Settings API.
  • menu_title: This is the title of the menu item in the sidebar.
  • capability: This is who can access the menu item as far as roles and capabilities.
  • menu_slug: This is the slug for your menu, and is used for any child menus to reference it. Make sure it is unique and dashed.
  • callback: Callable callback function to display your admin panel settings.
  • icon_url: This can be a dashicon or URL to an image.
  • position: Where in the left sidebar is it positioned?

One of the more important arguments regarding appearance is position. Where in the left hand side will it go? According to the developer docs, here are the default positions for a normal admin.

  • 2 – Dashboard
  • 4 – Separator
  • 5 – Posts
  • 10 – Media
  • 15 – Links
  • 20 – Pages
  • 25 – Comments
  • 59 – Separator
  • 60 – Appearance
  • 65 – Plugins
  • 70 – Users
  • 75 – Tools
  • 80 – Settings
  • 99 – Separator

You can place your menu wherever you see fit, but make it make sense as to its position. Since I placed my position at 20, it’ll show up under pages.

Lastly, I’ll add my callback function to show my admin panel:

add_action( 'admin_menu', 'dlx_menu_customizations_add_menu_items' );
function dlx_menu_customizations_add_menu_items() {
	$parent_menu_slug = 'dlx-menu-customizations';
	add_menu_page(
		'Custom Menu',
		'Custom Menu',
		'manage_options',
		$parent_menu_slug,
		'dlx_menu_customizations_menu_page',
		'dashicons-admin-generic',
		20
	);
}
function dlx_menu_customizations_menu_page() {
	?>
	<div class="wrap">
		<h1>My Custom Menu Options</h1>
	</div>
	<?php
}
Code language: PHP (php)

This allows me to have a viewable admin panel.

Custom Menu With Admin Panel Options
Custom Menu With Admin Panel Options

Customizing the menu icon with Dashicons

Dashicons Resource Site
Dashicons Resource Site

As shown in the code, we have an icon_url property we can specify. This can be a WordPress Dashicon or image URL.

When using the Dashicon, I would use the full dashicons name: dashicons-media-document

add_action( 'admin_menu', 'dlx_menu_customizations_add_menu_items' );
function dlx_menu_customizations_add_menu_items() {
	$parent_menu_slug = 'dlx-menu-customizations';
	add_menu_page(
		'Custom Menu',
		'Custom Menu',
		'manage_options',
		$parent_menu_slug,
		'dlx_menu_customizations_menu_page',
		'dashicons-media-document',
		20
	);
}
Code language: PHP (php)

Here’s how it would look in the admin.

Custom Menu With Dashicon
Custom Menu With Dashicon

You can use any Dashicon that is available.

Customizing the menu icon with a custom image png

As mentioned previously, the icon_url property can take a URL.

Let’s see what that a custom icon looks like in practice. Here’s my folder structure for a plugin:

.
└── dlx-menu-customizations/
    ├── dlx-menu-customizations.php
    └── icon.pngCode language: AsciiDoc (asciidoc)

I can add it to my menu using the icon_url param.

add_action( 'admin_menu', 'dlx_menu_customizations_add_menu_items' );
function dlx_menu_customizations_add_menu_items() {
	$parent_menu_slug = 'dlx-menu-customizations';
	$icon_url         = plugins_url( 'icon.png', __FILE__ );
	add_menu_page(
		'Custom Menu',
		'Custom Menu',
		'manage_options',
		$parent_menu_slug,
		'dlx_menu_customizations_menu_page',
		$icon_url,
		20
	);
}
Code language: PHP (php)

Here’s the result, with no need for custom CSS.

Custom Menu With a Shopping Cart Icon
Custom Menu With a Shopping Cart Icon

The main issue with a png file is it doesn’t respect the admin menu’s hover state, as shown in the screenshot. Let’s fix that with some CSS masking.

I’ll be adding in the icon via CSS and overriding a dashicon.

add_action( 'admin_menu', 'dlx_menu_customizations_add_menu_items' );
function dlx_menu_customizations_add_menu_items() {
	$parent_menu_slug = 'dlx-menu-customizations';
	$icon_url         = plugins_url( 'icon.png', __FILE__ );
	add_menu_page(
		'Custom Menu',
		'Custom Menu',
		'manage_options',
		$parent_menu_slug,
		'dlx_menu_customizations_menu_page',
		'dashicons-admin-generic', /* this is replaced by CSS */
		20
	);

	wp_add_inline_style(
		'wp-admin',
		'#adminmenu .toplevel_page_dlx-menu-customizations .wp-menu-image:before {
			content: \'\';
			display: block;
			margin-left: 8px;
			width: 20px;
			height: 20px;
			background-color: currentColor;
			-webkit-mask: url(' . $icon_url . ') no-repeat center / contain;
			mask: url(' . $icon_url . ') no-repeat center / contain;
		}'
	);
}Code language: PHP (php)

This allows you to use a PNG image and still have it respect the background color of the admin.

I had to use a bit of CSS to get the margins to line up, but here’s the result:

Custom Menu With PNG Image
Custom Menu With PNG Image

Customizing the menu icon with an SVG

For an SVG, we’ll need to encode it. Make sure your SVG has a width/height of 20px and any path parameters have fill="currentColor". Here’s an example:


add_action( 'admin_menu', 'dlx_menu_customizations_add_menu_items' );
function dlx_menu_customizations_add_menu_items() {
	$parent_menu_slug = 'dlx-menu-customizations';
	$svg_base         = 'data:image/svg+xml;base64,' . base64_encode( '<svg viewBox="0 0 24 24" width="20" height="20" xmlns="http://www.w3.org/2000/svg"><path fill="currentColor" d="m1 1c-.55228475 0-1 .44771525-1 1s.44771525 1 1 1h1.7792969a.69367162.69367162 35.784145 0 1 .65808707.47435058l3.2969911 9.8928369c.14641172.43923517.16502704.91215746.05273437 1.3613281l-.27148437 1.0878906c-.39834445 1.5933778.84195876 3.1835938 2.484375 3.1835938h12c.55228475 0 1-.44771525 1-1s-.44771525-1-1-1h-12c-.38938619 0-.6393619-.31950554-.54492188-.69726562l.20473297-.81770594a.64062109.64062109 142.02823 0 1 .6214389-.48502844h10.71875c.43057012.00022511.81295428-.27515444.94921875-.68359375l2.6660156-8c.21596464-.64778704-.26638007-1.3167178-.94921876-1.3164062h-16.111328a.69371294.69371294 35.782526 0 1 -.65811388-.47434165l-.94735487-2.8420646c-.13626447-.40843931-.51864863-.68381886-.94921875-.68359375zm7 19c-1.1045695 0-2 .8954305-2 2s.8954305 2 2 2 2-.8954305 2-2-.8954305-2-2-2zm12 0c-1.1045695 0-2 .8954305-2 2s.8954305 2 2 2 2-.8954305 2-2-.8954305-2-2-2z" /></svg>' );
	add_menu_page(
		'Custom Menu',
		'Custom Menu',
		'manage_options',
		$parent_menu_slug,
		'dlx_menu_customizations_menu_page',
		$svg_base,
		20
	);
}Code language: PHP (php)

Here’s how it would look in the menu.

Custom Menu With a Custom SVG Icon
Custom Menu With a Custom SVG Icon

It matches up nicely without having to use custom CSS. The downside of this approach is that you can’t adjust the SVG’s color, but it does blend in nicely with the current color system in the admin.

Adding a CSS class to the menu item

You may need to do some extra customizations, so you may want to target the menu item via CSS. There’s already a CSS class you can target for your top-level item. In my case, the class is: toplevel_page_dlx-menu-customizations.

The prefix, toplevel_page_ will be followed by your menu’s slug. You’re able to target this via CSS, but what if you need an extra class, how would you do that?

It requires a bit of hackery and using WordPress globals, but here’s how you would add an additional class to a menu.

add_action( 'admin_menu', 'dlx_menu_customizations_add_menu_items' );
function dlx_menu_customizations_add_menu_items() {
	$parent_menu_slug = 'dlx-menu-customizations';
	add_menu_page(
		'Custom Menu',
		'Custom Menu',
		'manage_options',
		$parent_menu_slug,
		'dlx_menu_customizations_menu_page',
		'dashicons-media-document',
		20
	);

	// Modify the global menu.
	global $menu;
    // do custom conditional logic
	foreach ( $menu as $index => $menu_item ) {
		if ( isset( $menu_item[2] ) && $parent_menu_slug === $menu_item[2] ) {
			// $menu_item[4] contains the CSS classes.
			$menu[ $index ][4] .= ' dlx-menu-customizations-menu-item has-item'; // custom class.
			break;
		}
	}
}
Code language: PHP (php)

Using WordPress global $menu, we can modify the menu classes and add our own. Just know the caveat that it is not a best practice to modify WordPress globals.

Modifying WordPress globals is a big no-no. But if you have to, you have to. It’s WordPress.

You can now target it via CSS or using wp_add_inline_style.

Adding a badge to a top-level menu item

Add a Numbered Badge Next to Your Post Type

You can add a numbered badge by adding CSS class awaiting-mod to a span.

Here’s a code example renaming the menu to Products:

add_action( 'admin_menu', 'dlx_menu_customizations_add_menu_items' );
function dlx_menu_customizations_add_menu_items() {
	$parent_menu_slug = 'dlx-menu-customizations';
	$icon_url         = plugins_url( 'icon.png', __FILE__ );

	$some_count = 10;
	$menu_class = 'awaiting-mod';
	if ( 0 === $some_count ) {
		$menu_class = 'not-awaiting-mod';
	}
	$menu_title = sprintf(
		/* Translators: %s is the number of products */
		_n( '<span class="menu-item-products">Products</span> <span class="%1$s">%2$s</span>', '<span class="menu-item-products">Products</span> <span class="%1$s">%2$s</span>', $some_count, 'your-text-domain' ),
		esc_attr( $menu_class ),
		number_format_i18n( $some_count )
	);

	add_menu_page(
		'Products',
		$menu_title,
		'manage_options',
		$parent_menu_slug,
		'dlx_menu_customizations_menu_page',
		'dashicons-admin-generic', /* this is replaced by CSS */
		20
	);

	wp_add_inline_style(
		'wp-admin',
		'#adminmenu .toplevel_page_dlx-menu-customizations .wp-menu-image:before {
			content: \'\';
			display: block;
			margin-left: 8px;
			width: 20px;
			height: 20px;
			background-color: currentColor;
			-webkit-mask: url(' . $icon_url . ') no-repeat center / contain;
			mask: url(' . $icon_url . ') no-repeat center / contain;
		}'
	);
}
Code language: PHP (php)

Say you want to add something like “Update Available.” I’ll change the spans to divs and update the CSS a bit.

add_action( 'admin_menu', 'dlx_menu_customizations_add_menu_items' );
function dlx_menu_customizations_add_menu_items() {
	$parent_menu_slug = 'dlx-menu-customizations';
	$icon_url         = plugins_url( 'icon.png', __FILE__ );

	$some_condition = true;
	if ( $some_condition ) {
		$menu_title = '<div class="menu-item-products">Products</div><div class="awaiting-mod">Update Available</div>';
	} else {
		$menu_title = '<div class="menu-item-products">Products</div>';
	}

	add_menu_page(
		'Products',
		$menu_title,
		'manage_options',
		$parent_menu_slug,
		'dlx_menu_customizations_menu_page',
		'dashicons-admin-generic', /* this is replaced by CSS */
		20
	);

	wp_add_inline_style(
		'wp-admin',
		'#adminmenu .toplevel_page_dlx-menu-customizations .awaiting-mod {
			display: block;
			width: 100;
			margin-top: 8px;
		}
		#adminmenu .toplevel_page_dlx-menu-customizations .wp-menu-image:before {
			content: \'\';
			display: block;
			margin-left: 8px;
			width: 20px;
			height: 20px;
			background-color: currentColor;
			-webkit-mask: url(' . $icon_url . ') no-repeat center / contain;
			mask: url(' . $icon_url . ') no-repeat center / contain;
		}'
	);
}Code language: PHP (php)

Here’s the result:

Menu Showing Larger Pill Shaped Like a Badge

I used inline CSS two customize the badge, but you can get really creative.

Customize the menu title when nesting sub-menus

Showing a Settings Screen and All Products Shortcut
Showing a Settings Screen and All Products Shortcut

If you need sub-items, you would use function add_submenu_page. The first trick is to create a sub-menu that points to your existing top-level menu. This way you can keep the top-level menu item the same, but override what’s shown as the first menu item.

add_action( 'admin_menu', 'dlx_menu_customizations_add_menu_items' );
function dlx_menu_customizations_add_menu_items() {
	$parent_menu_slug = 'dlx-menu-customizations';
	$icon_url         = plugins_url( 'icon.png', __FILE__ );

	add_menu_page(
		'Products',
		'Products',
		'manage_options',
		$parent_menu_slug,
		'dlx_menu_customizations_menu_page',
		'dashicons-admin-generic', /* this is replaced by CSS */
		20
	);
	add_submenu_page(
		$parent_menu_slug,
		'All Products',
		'All Products',
		'manage_options',
		$parent_menu_slug,
		'dlx_menu_customizations_menu_page'
	);
	add_submenu_page(
		$parent_menu_slug,
		'Settings',
		'Settings',
		'manage_options',
		'dlx-menu-customizations-settings',
		'dlx_menu_customizations_menu_page'
	);

	wp_add_inline_style(
		'wp-admin',
		'#adminmenu .toplevel_page_dlx-menu-customizations .awaiting-mod {
			display: block;
			width: 100;
			margin-top: 8px;
		}
		#adminmenu .toplevel_page_dlx-menu-customizations .wp-menu-image:before {
			content: \'\';
			display: block;
			margin-left: 8px;
			width: 20px;
			height: 20px;
			background-color: currentColor;
			-webkit-mask: url(' . $icon_url . ') no-repeat center / contain;
			mask: url(' . $icon_url . ') no-repeat center / contain;
		}'
	);
}Code language: PHP (php)

The trick is that for the first sub-menu item, you’ll want to use the same slug as the parent.

add_submenu_page(
	$parent_menu_slug,
	'All Products',
	'All Products',
	'manage_options',
	$parent_menu_slug,
	'dlx_menu_customizations_menu_page'
);Code language: PHP (php)

You’ll notice that $parent_menu_slug is the same for both the parent argument, and slug.

Other sub-menus would use a different slug, but the same parent as the top-level item.

add_submenu_page(
	$parent_menu_slug,
	'Settings',
	'Settings',
	'manage_options',
	'dlx-menu-customizations-settings',
	'dlx_menu_customizations_menu_page'
);Code language: PHP (php)

In all these examples I point to a callback function of dlx_menu_customizations_menu_page, which exists separately. You’d want to modify these per-submenu as necessary.

Conclusion

In this short tutorial I demonstrated how to customize a top-level admin menu item in several ways. This includes adding a badge, organizing sub-menus, and changing the icon. If you would like to know more about admin menus, please read my detailed article on creating admin menus. If you would like to customize admin menus without code, you can try out Admin Menu Editor.

Do you have any extra tips? Please share them below in the comments.

This tutorial was written with the help of these plugins

Like the tutorial you just read? There's more like it.

There's more where that came from. Enter your email and I'll send you more like it.

This field is for validation purposes and should be left unchanged.

Ask a Question or Leave Feedback

Your email address will not be published. Required fields are marked *