Wordpress - wp_get_nav_menu_items() not working with slug

Since nobody has really explained why the function doesn't work the way you thought it did, I shall take a stab at explaining it in detail as I just fell for the same trap as you did.

This is where the docs aren't really clear as to what the slug is referring to. Most people would assume its the slug of the registered menu but thats not correct. Its actually the slug of the term for the taxonomy nav_menu.

Lets dive into the source code to see how the Wordpress core interprets the slug of the menu.

function wp_get_nav_menu_items( $menu, $args = array() ) {
    $menu = wp_get_nav_menu_object( $menu );
....

The first line shows that it uses a function named wp_get_nav_menu_object() to retrieve the menu. It passes the $menu as the first parameter to this function. Since this is what we use for our slug we will have to dive into the source for wp_get_nav_menu_object().

function wp_get_nav_menu_object( $menu ) {
    $menu_obj = false;

    if ( is_object( $menu ) ) {
            $menu_obj = $menu;
    }

    if ( $menu && ! $menu_obj ) {
            $menu_obj = get_term( $menu, 'nav_menu' );

            if ( ! $menu_obj ) {
                    $menu_obj = get_term_by( 'slug', $menu, 'nav_menu' );
            }

            if ( ! $menu_obj ) {
                    $menu_obj = get_term_by( 'name', $menu, 'nav_menu' );
            }
    }
....

we can see that this function uses the get_term_by function to retrieve the $menu_obj. This is where we get our menu.

When you create a menu in the Wordpress admin area, it creates a new term. Terms, have slugs based off of their name. So if you have a menu name of "My Awesome Menu" Wordpress will generate a slug named "my-awesome-menu". You may have registered the menu as "primary" but that is not the slug these functions refer to. Its actually the menus term slug.

So to be clear, lets just say you registered a menu like so:

register_nav_menu('primary', 'my primary nav');

primary is not the slug. my-primary-nav is also not the slug.

Since we created a menu named "My Awesome Menu" (as an example), and the slug is 'my-awesome-menu', you can retrieve it like so:

$awesome_menu = wp_get_nav_menu_items( 'my-awesome-menu' );

You can see for yourself what the slug is just by checking the database in the wp_terms (or whatever your prefix is) table and look for your menu name in there.

Since you are using a multilingual site or even a multisite, this method won't be the best way to go about it. Since the name and slug could possibly be different.

So the best method is to get the all the menu locations with get_nav_menu_locations() which will return an associative array where the key is the slug of the registered menu and the value is the id of the menu term selected for its location.

With the term id, we can get that terms info and then return the proper slug the function is requiring.

Below is a function that utilizes the wp_get_nav_items() function but you would pass in the registered menu slug. In your case this would be 'primary'.

Code Solution

// kind of a long function name but whatevs
function get_menu_items_by_registered_slug($menu_slug) {

    $menu_items = array();

    if ( ( $locations = get_nav_menu_locations() ) && isset( $locations[ $menu_slug ] ) ) {
        $menu = get_term( $locations[ $menu_slug ] );

        $menu_items = wp_get_nav_menu_items($menu->term_id);


    }

    return $menu_items;

}

Small modification to the accepted answer

After removing a menu from menu location, $locations[ $menu_slug ] returns 0, so it's good to add this check:

function get_menu_items_by_registered_slug($menu_slug) {
  $menu_items = array();

  if ( ($locations = get_nav_menu_locations()) && isset($locations[$menu_slug]) && $locations[$menu_slug] != 0 ) {
    $menu = get_term( $locations[ $menu_slug ] );
    $menu_items = wp_get_nav_menu_items($menu->term_id);
  }

  return $menu_items;
}

Tags:

Menus