Plugin Directory

Test out the new Plugin Directory and let us know what you think.

Nav Menu Roles

Hide custom menu items based on user roles. PLEASE READ THE FAQ IF YOU ARE NOT SEEING THE SETTINGS.

I don't see the Nav Menu Roles options in the admin menu items?

This is because you have another plugin (or theme) that is also trying to alter the same code that creates the Menu section in the admin.

WordPress does not have sufficient hooks in this area of the admin and until they do plugins are forced to replace everything via custom admin menu Walker, of which there can be only one. There's a trac ticket for this, but it has been around a while.

A non-exhaustive list of known conflicts:

  1. UberMenu 2.x Mega Menus plugin (UberMenu 3.x supports NMR!)
  2. Add Descendants As Submenu Items plugin
  3. Navception plugin
  4. Suffusion theme
  5. BeTheme
  6. Yith Menu
  7. Jupiter Theme
  8. iMedica theme
  9. Prostyler EVO theme
  10. Mega Main Plugin

Workaround #1

Shazdeh had the genius idea to not wait for a core hook and simply add the hook ourselves. If all plugin and theme authors use the same hook, we can make our plugins play together.

Therefore, as of version 1.6 I am modifying my admin nav menu Walker to only adding the following lines (right after the description input):

// Place this in your admin nav menu Walker
do_action( 'wp_nav_menu_item_custom_fields', $item_id, $item, $depth, $args );
// end added section 

Ask your conflicting plugin/theme's author to add this code to his plugin or theme and our plugins will become compatible.

Instructions for Patching Your Plugin/Theme

Should you wish to attempt this patch yourself, you can modify your conflicting plugin/theme's admin menu Walker class.

Reminder: I do not provide support for fixing your plugin/theme. If you aren't comfortable with the following instructions, contact the developer of the conflicting plugin/theme!

1. Find the class that extends the Walker_Nav_Menu. The fastest way to do this is to search your whole plugin/theme folder for extends Walker_Nav_Menu. When you find the file that contains this text you willl know which file you need to edit. Once you find it here's what the beginning of that class will look like:

class YOUR_THEME_CUSTOM_WALKER extends Walker_Nav_Menu {}

2. Find the start_el() method

In that file you will eventually see a class method that looks like:

function start_el( &$output, $item, $depth = 0, $args = array(), $id = 0 ) {
  // some stuff truncated for brevity

3. Paste my action hook somewhere in this method!

In Nav Menu Roles, I have placed the hook directly after the description, like so:

<p class="field-description description description-wide">
  <label for="edit-menu-item-description-<?php echo $item_id; ?>">
    <?php _e( 'Description' ); ?><br />
    <textarea id="edit-menu-item-description-<?php echo $item_id; ?>" class="widefat edit-menu-item-description" rows="3" cols="20" name="menu-item-description[<?php echo $item_id; ?>]"><?php echo esc_html( $item->description ); // textarea_escaped ?></textarea>
    <span class="description"><?php _e('The description will be displayed in the menu if the current theme supports it.'); ?></span>

// Add this directly after the description paragraph in the start_el() method
do_action( 'wp_nav_menu_item_custom_fields', $item_id, $item, $depth, $args );
// end added section 

Workaround #2

As a workaround, you can switch to a default theme (or disable the conflicting plugin), edit the Nav Menu Roles, for each menu item, then revert to your original theme/ reenable the conflicting plugin. The front-end functionality of Nav Menu Roles will still work.

Workaround #3

Download and install this tiny plugin. Activate it when you need to make the NMR options appear and then disable it when you are done editing.

I'm using XYZ Membership plugin and I don't see its "levels"?

There are apparently a few membership plugins out there that don't use traditional WordPress roles/capabilities. My plugin will list any role registered in the traditional WordPress way. If your membership plugin is using some other system, then Nav Menu Roles won't work with it out of the box. Since 1.3.5 I've added a filter called nav_menu_roles_item_visibility just before my code decides whether to show/hide a menu item. There's also always been the nav_menu_roles filter which lets you modify the roles listed in the admin. Between these two, I believe you have enough to integrate Nav Menu Roles with any membership plugin.

Here's an example where I've added a new pseudo role, creatively called "new-role". The first function adds it to the menu item admin screen. The second function is pretty generic and won't actually do anything because you need to supply your own logic based on the plugin you are using. Nav Menu Roles will save the new "role" info and add it to the item in an array to the $item->roles variable.

Adding a new "role"

 * Add custom roles to Nav Menu Roles menu list
 * param: $roles an array of all available roles, by default is global $wp_roles 
 * return: array
function kia_new_roles( $roles ){
  $roles['new-role-key'] = 'new-role';
  return $roles;
add_filter( 'nav_menu_roles', 'kia_new_roles' );

Note, if you want to add a WordPress capability the above is literally all you need. Because Nav Menu Roles checks whether a role has permission to view the menu item using current_user_can($role) you do not need to right a custom callback for thenav_menu_roles_item_visibility` filter.

In case you do need to check your visibility status against something very custom, here is how you'd go about it:

 * Change visibilty of each menu item
 * param: $visible boolean
 * param: $item object, the complete menu object. Nav Menu Roles adds its info to $item->roles
 * $item->roles can be "in" (all logged in), "out" (all logged out) or an array of specific roles
 * return boolean
function kia_item_visibility( $visible, $item ){
  if( isset( $item->roles ) && is_array( $item->roles ) && in_array( 'new-role-key', $item->roles ) ){
  /*  if ( // your own custom check on the current user versus 'new-role' status ){
        $visible = true;
      } else {
        $visible = false;
  */  }
  return $visible;
add_filter( 'nav_menu_roles_item_visibility', 'kia_item_visibility', 10, 2 );

Note that you have to generate your own if/then logic. I can't provide free support for custom integration with another plugin. You may contact me to discuss hiring me, or I would suggest using a plugin that supports WordPress' roles, such as Justin Tadlock's Members.

The menu exploded? Why are all my pages displaying for logged out users?

If every item in your menu is configured to display to logged in users (either all logged in users, or by specific role), then when a logged out visitor comes to your site there are no items in the menu to display. wp_nav_menu() will then try check its fallback_cb argument... which defaults to wp_page_menu.

Therefore, if you have no items to display, WordPress will end up displaying ALL your pages!!

If you don't want this, you must set the fallback argument to be a null string.

wp_nav_menu( array( 'theme_location' => 'primary-menu', 'fallback_cb' => '' ) );

What happened to my menu roles on import/export?

The Nav Menu Roles plugin stores 1 piece of post meta to every menu item/post. This is exported just fine by the default Export tool.

However, the Import plugin only imports certain post meta for menu items. As of version 1.3, I've added a custom Importer to Nav Menu Roles as a work around.

How Do I Use the Custom Importer?

  1. Go to Tools>Export, choose to export All Content and download the Export file
  2. Go to Tools>Import on your new site and perform your normal WordPress import
  3. Return to Tools>Import and this time select the Nav Menu Roles importer.
  4. Use the same .xml file and perform a second import
  5. No duplicate posts will be created but all menu post meta (including your Nav Menu Roles info) will be imported

Requires: 4.5.0 or higher
Compatible up to: 4.7.0
Last Updated: 2 months ago
Active Installs: 90,000+


4.9 out of 5 stars


2 of 11 support threads in the last two months have been marked resolved.

Got something to say? Need help?


Not enough data

1 person says it works.
0 people say it's broken.

100,2,2 100,2,2 100,1,1
100,1,1 100,1,1
67,3,2 100,2,2
100,1,1 100,1,1
67,3,2 100,1,1 100,1,1
100,3,3 100,3,3
67,6,4 100,5,5
100,3,3 100,3,3
50,2,1 100,1,1
100,2,2 100,1,1
100,1,1 100,1,1 100,3,3