I need to add something after each title of a specific menu called by wp_nav_menu()

I tried

add_filter('wp_nav_title', 'testing_stuff');


function testing_stuff() {
$item->title = $item->title . ' testing';
return $item->title;


without any success, i'm not familiar enough with hooking.

My purpose :

  • when I called menu ID = 4;
  • for each title of each item
  • i pull out data from current page meta with $meta_value = get_post_meta( $post->ID, $meta_key, true );
  • I add this data after the anchor text in a

So every item of the menu will have a specific data added to its content, data I could manipulate from custom field.

I would appreciate any clue that get me on the right path.

Thank you.

  • wp_nav_manu comes with options to allow you append/preprend text onto the links - is there a particular reason why you can't use them? Jan 26, 2012 at 11:18
  • Yes, the reason is that I have to get the value of the metadata key 'packaging' from each item, and I couldn't run a function from wp_nav_menu (correct me if i'm wrong)
    – Simon
    Jan 26, 2012 at 12:02
  • Simon - add this as a separate answer, and feel free to accept it. It'll make it more obvious for others who have a similar question. Jan 26, 2012 at 18:37
  • Thanks Stephen. I did as you said, for others to pick it up.
    – Simon
    Jan 26, 2012 at 22:31

2 Answers 2


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' );
        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;
  • Hi Stephen, thank you ; That's very close but not quite : the $item->ID is not ID of the page, but ID of the item menu [nav_menu_item] ; and cannot be used to get meta data. The method is allright, but either we're starting at the wrong hook (wp_setup_nav_menu_item) or I will need to find the ID of the post using the permalink (which is the right one in the object $item.
    – Simon
    Jan 26, 2012 at 14:27
  • Sorry, try object_id instead :D Jan 26, 2012 at 14:40
  • This is how I finally got it : damn, where do I put that code ? (the ID of the post each item refers to isn't part of the $item object. Should be somewhere in the $nav object maybe ; and the ID of the menu is in the $args object. So to create a filter that only works in a specific menu the hook must be placed in another place. See wordpress.stackexchange.com/questions/2143/…
    – Simon
    Jan 26, 2012 at 14:43
  • See my comment above. As for the other hook you mentioned - that was the obvious one, but it filters the html of the menu, so it's not the easiest to add classes into. Jan 26, 2012 at 14:50
  • I will add the answer to you, as your code was the starting point of my solution, but do I need to create another answer to place the working code ? (object_id wasn't working either, I checked to whole object with print_r to see is there was any reference to the ID of the post. There isn't).
    – Simon
    Jan 26, 2012 at 14:51

Thanks to Stephen : this is the working form of the code (i removed options I don't use from original proposition). I just test if there is non-empty value to meta value so I don't spread empty to the html.

function packaging_setup($item) {
//Alter the title:
$ala_page = get_page_by_title( $item->title ); // getting the page itself
$ala_page_id = $ala_page->ID; // the page ID the item is refering to
$pack_meta_key = 'box_packaging_meta'; // my meta key
$pack_meta_value = get_post_meta($ala_page_id, $pack_meta_key, true ); // getting data
    if (!empty($pack_meta_value)) { //so I do not add empty spans
    $item->title = $item->title.'<span>' . $pack_meta_value . '</span>'; //altering
    return $item; 

add_filter('wp_setup_nav_menu_item', 'packaging_setup');

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.