Take the 2-minute tour ×
WordPress Development Stack Exchange is a question and answer site for WordPress developers and administrators. It's 100% free, no registration required.

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');

with

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.

share|improve this question
    
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? –  Stephen Harris Jan 26 '12 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 '12 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. –  Stephen Harris Jan 26 '12 at 18:37
    
Thanks Stephen. I did as you said, for others to pick it up. –  Simon Jan 26 '12 at 22:31
add comment

2 Answers 2

up vote 3 down vote accepted

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;
}
share|improve this answer
    
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 '12 at 14:27
    
Sorry, try object_id instead :D –  Stephen Harris Jan 26 '12 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 '12 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. –  Stephen Harris Jan 26 '12 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 '12 at 14:51
show 3 more comments

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');
share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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