Adding custom text in items titles from wp_nav_menu()

The following works, but with the following caveats. It will run for every menu, but it will not run for wp_page_menu, a usuall default callback if a menu can’t be found.

Finally, menu items aren’t necessary pages – so you may want to do some logic to check that the menu item you are dealing with is a page/post from which you want to obtain the metadata.

Here’s the code:

add_filter( 'wp_setup_nav_menu_item','my_item_setup' );
function my_item_setup($item) {
    //Use the following to conduct logic;
    $object_id = (int) $item->object_id; //object ID.
    $object_type = $item->type; //E.g. 'post_type'
    $object_type_label = $item->type_label; //E.g. 'post' or 'page';

    //You could, optionally add classes to the menu item.
    $item_class = $item->classes;

    //Make sure $item_class is an array.
    //Alter the class:
    $item->classes= $item_class;

    //Alter the title:
    $pack_meta_value = get_post_meta($object_id, 'test', true );
     if($pack_meta_value ){
         $item->title = $item->title.'<span>' . $pack_meta_value . '</span>'; 
     }

    return $item;
}

I would be interested to see if there was a better way of doing this, preferably a method which allowed you to check for which menu these items are for…


I’ve moved this from the comments. If you wish to restrict this function to a particular menu, you could try the following. This has not been tested.

First remove the add_filter from the code above. Instead insert into a function which is added onto an earlier hook, and conditionally adds the filter (say when the menu is ‘primary’):

add_filter( 'wp_nav_menu_args','add_my_setup_function' );
    function add_my_setup_function($args) {
        if( $args['theme_location'] == 'primary' ):
         add_filter( 'wp_setup_nav_menu_item','my_item_setup' );
        endif;      
        return $args;
    }

Finally remove the filter, once the items have been loaded, so that it isn’t called for secondary menus:

add_filter('wp_nav_menu_items','remove_my_setup_function', 10, 2);
function remove_my_setup_function( $nav, $args ) {
   remove_filter( 'wp_setup_nav_menu_item', 'my_item_setup' );
    return $nav;
}