As far as the WordPress community is concerned, developers tend to be divided on how plugins and themes should insert themselves into the WordPress menu.

On one hand, some feel that because WordPress offers the ability to insert custom menu items into existing menus, then plugin and theme content should follow suit and exist only in the predefined menu; however, others feel that because WordPress offers the ability to define custom menu items, then they should take advantage of it.

In fact, opinionated plugins have been written specifically for on this.

I don’t have a hard stance on this issue – though I tend to lean in the direction of adding new functionality to existing menus, I think that there are perfectly suitable cases for defining custom menus.

But if you’re going to define a custom menu item, then you should place it logically among the existing menu items: If you’re writing a theme, its menu should be placed near the ‘Appearance’ options rather than, say, the ‘Dashboard’ options. Then again, there are times where makes sense to isolate a menu item to its own section. In order to do this, a custom separator may need to be added in addition to the menu.

Adding a separator to the WordPress menu isn’t difficult and though there are a variety of ways to do it, the easiest way to do about doing so is using a couple of custom functions registered with the WordPress API.

Below, I give a working example for how to add a separator to the WordPress menu. I also look at how the default menu is structured, the proper way to add your own separator, and an example plugin for doing just that. If you’re an advanced developer, it may be more beneficial (and quicker!) for you to refer to the source code on GitHub.

Understanding The Default Menu

Before adding a separator to the WordPress menu, it’s important to understand how the default menu is structured. So, assuming that you’re looking at a default installation, the default menu is structured like this:

Array
(
    [2] => Array
        (
            [0] => Dashboard
            [1] => read
            [2] => index.php
            [3] =>
            [4] => menu-top menu-top-first menu-icon-dashboard menu-top-last
            [5] => menu-dashboard
            [6] => div
        )

    [4] => Array
        (
            [0] =>
            [1] => read
            [2] => separator1
            [3] =>
            [4] => wp-menu-separator
        )

    [5] => Array
        (
            [0] => Posts
            [1] => edit_posts
            [2] => edit.php
            [3] =>
            [4] => open-if-no-js menu-top menu-icon-post menu-top-first
            [5] => menu-posts
            [6] => div
        )

    [10] => Array
        (
            [0] => Media
            [1] => upload_files
            [2] => upload.php
            [3] =>
            [4] => menu-top menu-icon-media
            [5] => menu-media
            [6] => div
        )

    [15] => Array
        (
            [0] => Links
            [1] => manage_links
            [2] => link-manager.php
            [3] =>
            [4] => menu-top menu-icon-links
            [5] => menu-links
            [6] => div
        )

    [20] => Array
        (
            [0] => Pages
            [1] => edit_pages
            [2] => edit.php?post_type=page
            [3] =>
            [4] => menu-top menu-icon-page
            [5] => menu-pages
            [6] => div
        )

    [25] => Array
        (
            [0] => Comments <span class="awaiting-mod count-0"><span class="pending-count">0</span></span>
            [1] => edit_posts
            [2] => edit-comments.php
            [3] =>
            [4] => menu-top menu-icon-comments menu-top-last menu-top-last
            [5] => menu-comments
            [6] => div
        )

    [59] => Array
        (
            [0] =>
            [1] => read
            [2] => separator2
            [3] =>
            [4] => wp-menu-separator
        )

    [60] => Array
        (
            [0] => Appearance
            [1] => switch_themes
            [2] => themes.php
            [3] =>
            [4] => menu-top menu-icon-appearance menu-top-first
            [5] => menu-appearance
            [6] => div
        )

    [65] => Array
        (
            [0] => Plugins <span class="update-plugins count-0"><span class="plugin-count">0</span></span>
            [1] => activate_plugins
            [2] => plugins.php
            [3] =>
            [4] => menu-top menu-icon-plugins
            [5] => menu-plugins
            [6] => div
        )

    [70] => Array
        (
            [0] => Users
            [1] => list_users
            [2] => users.php
            [3] =>
            [4] => menu-top menu-icon-users
            [5] => menu-users
            [6] => div
        )

    [75] => Array
        (
            [0] => Tools
            [1] => edit_posts
            [2] => tools.php
            [3] =>
            [4] => menu-top menu-icon-tools
            [5] => menu-tools
            [6] => div
        )

    [80] => Array
        (
            [0] => Settings
            [1] => manage_options
            [2] => options-general.php
            [3] =>
            [4] => menu-top menu-icon-settings menu-top-last
            [5] => menu-settings
            [6] => div
        )

)

Simply put, the menu is an array of arrays. Looking at the code, it’s easy to see how the menu is organized. The key takeaway from this is that there are certain positions that are reserved for default menu items.

Specifically, the following positions are reserved:

  • 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

When adding a separator to the WordPress menu, avoid using any of the positions listed above.

Add a Separator To The WordPress Menu

A couple of functions will need to be written in order to add a custom separator. These can either be written within a theme’s functions.php file or a plugin file.

Registering a Custom Action

For adding a custom separator to the WordPress menu, a custom function will need to be registered with the WordPress API. This can be done using add_action. Below, I’m defining a custom action called ‘init_custom_menu_separator’ and a custom function named ‘add_admin_menu_separator.’

add_action( 'admin_init', 'add_admin_menu_separator' );

The function itself looks like this:

function add_admin_menu_separator( $position ) {

	global $menu;

	$menu[ $position ] = array(
		0	=>	'',
		1	=>	'read',
		2	=>	'separator' . $position,
		3	=>	'',
		4	=>	'wp-menu-separator'
	);

}

Some points about the code:

  • The function accepts a single parameter – the position – this value represents where to insert the separator
  • The WordPress menu is defined at the global level so, in order to manipulate it, we must scope it within our function
  • We create our own array representing a separator. This is based on how existing menu separators are defined in the WordPress menu
  • We insert it into the WordPress menu using the position reference passed into the function

For those that are curious, you can learn more about what each index of the array represents by taking a look at the source code of the plugin on GitHub.

Running The Custom Action

At this point, the custom hook and functionality are defined for adding a custom separator to the WordPress menu, but there’s nothing invoking the actual function. To do this, one more action has to be defined.

So, I’ll register a new function using add_action and the WordPress admin_menu hook, thanks to a suggestion from Jamie.

My function is called ‘set_admin_separator.’ The add_action call is simple:

add_action( 'admin_menu', 'set_admin_menu_separator' );

At this point, all that’s left is to define the actual function. It’s a single line:

function set_admin_menu_separator() {
	do_action( 'admin_init', 79 );
} // end set_admin_menu_separator

This function uses WordPress’ do_action method for invoking the custom action that I defined earlier in the code. The second argument – 79 – is the value that’s passed into the function.

Basically, this function is telling WordPress to call the function that I’ve registered with the ‘admin_init’ hook (which is the ‘add_menu_separator’ function) and pass it the value of 79 (which will, in turn, be used as the position).

Once executed, this will add a custom menu separator above WordPress’ ‘Settings’ menu.

WordPress Custom Menu Separator Plugin

I’ve written a plugin that demonstrates all of the above code. You can grab it on GitHub. Once it’s installed, you can activate it in your Plugin’s dashboard page.

Just after activation (and assuming it’s a vanilla install of WordPress or no other plugins are interfering with the process) you should see a new separator appear above the ‘Settings’ menu.