Improve your WordPress Navigation Menu Output
WordPress 3 has gone gold and ships with an amazing new menu manager that can be used to control the navigation menus of your website. This tutorial will teach you how to change the default output of this manager, since getting a custom output can heavily improve the style of your themes. So first of all here is an example of the wordpress menu we want to build.
How to display the content of the wordpress menu description field
As you can see, instead of a simple list we got the menu item name and below that name is a small description of that menu item. This is currently a rather popular style that unfortunatley can’t be done out of the box by wordpress.
As you may already know, once you have created a menu at your wordpress backend at Appearance > Menus you can use a wordpress function called wp_nav_menu() within your template files to display those menus.
The problem is, the basic output would look something like this:
<ul id="menu-main"> <li><a href="#">Home</a></li> <li><a href="#">About</a></li> <li><a href="#">Contact</a></li> <li><a href="#">Blog</a></li> </ul>
With a basic unordered list like that its almost impossible to create such a menu. So we need to change the output to get this:
<ul id="menu-main"> <li><a href="#"><strong>Home</strong><span>Starting the journey</span></a></li> <li><a href="#"><strong>About</strong><span>What to expect</span></a></li> <li><a href="#"><strong>Contact</strong><span>Get in touch!</span></a></li> <li><a href="#"><strong>Blog</strong><span> Latest storys</span></a></li> </ul>
The <strong> tags wrap arround the title whereas the description is put into the <span> tags. Those can be styled easily with CSS later on to create this special menu style.
Preparing the backend
The first thing we need to do is to setup the menu properly in our backend. WordPress already comes with the option to add a description to each menu item, but it is hidden by default.
When you are at the Appearance > Menus Site you need to look at the top right and you will notice a “Screen Option” tab. Click it and you will get the option to display several other input fields for each menu item, among them a checkbox to show the description.
Once that is done, if you start editing your items you will notice that you can now enter a description for each menu item.
By default wordpress adds a rather long description to menu items that are created by pages, I would recommend to just delete those enourmous novels and just add a few words just like I did.
Now that we have setup the data to display in our backend, its time to prepare the frontend to show that data.
Editing the output by using a custom walker
WordPress uses a special “Walker” class that iterates over each data record and then displays this record accordingly. The cool thing about that is that we can simply create our own custom walker extending that PHP class. That way we dont need to care about fetching the stuff from the database or preparing the data arrays. We only need to extend the part of the wordpress code that outputs the list. So open your functions.php file and add the following code:
class description_walker extends Walker_Nav_Menu { function start_el(&$output, $item, $depth, $args) { global $wp_query; $indent = ( $depth ) ? str_repeat( "\t", $depth ) : ''; $class_names = $value = ''; $classes = empty( $item->classes ) ? array() : (array) $item->classes; $class_names = join( ' ', apply_filters( 'nav_menu_css_class', array_filter( $classes ), $item ) ); $class_names = ' class="'. esc_attr( $class_names ) . '"'; $output .= $indent . '<li id="menu-item-'. $item->ID . '"' . $value . $class_names .'>'; $attributes = ! empty( $item->attr_title ) ? ' title="' . esc_attr( $item->attr_title ) .'"' : ''; $attributes .= ! empty( $item->target ) ? ' target="' . esc_attr( $item->target ) .'"' : ''; $attributes .= ! empty( $item->xfn ) ? ' rel="' . esc_attr( $item->xfn ) .'"' : ''; $attributes .= ! empty( $item->url ) ? ' href="' . esc_attr( $item->url ) .'"' : ''; $prepend = '<strong>'; $append = '</strong>'; $description = ! empty( $item->description ) ? '<span>'.esc_attr( $item->description ).'</span>' : ''; if($depth != 0) { $description = $append = $prepend = ""; } $item_output = $args->before; $item_output .= '<a'. $attributes .'>'; $item_output .= $args->link_before .$prepend.apply_filters( 'the_title', $item->title, $item->ID ).$append; $item_output .= $description.$args->link_after; $item_output .= '</a>'; $item_output .= $args->after; $output .= apply_filters( 'walker_nav_menu_start_el', $item_output, $item, $depth, $args ); } }
So what does this Class do? This is basically the walker that wordpress is using (I just copied the source code) and added a few lines in the lower third for a better output: The walker now checks if a description is set, and if thats the case it wraps the description into a span tag and appends it to the navigation title.
The walker also checks if we are currently iterating over a sub menu item or a top level item, since our sub menu items do not need to display a description.
The Function Call
Now that we have created a custom walker we only need to tell wordpress that it should use our walker instead of its own. This can be easily done by calling the wp_nav_menu() with the walker parameter set:
wp_nav_menu( array( 'container' =>false, 'menu_class' => 'nav', 'echo' => true, 'before' => '', 'after' => '', 'link_before' => '', 'link_after' => '', 'depth' => 0, 'walker' => new description_walker()) );
Thats it. Once that is done your menu will be output with a completly different code structure that you can easily style with CSS to fit your needs. Here is a short snippet to get you startet:
.nav{ height:50px; padding-left:13px; margin:0; padding:0; list-style-type:none; list-style-position:outside; position:relative; } .nav a{ display:block; float:left; line-height:18px; outline:medium none; padding:2px 10px; text-decoration:none; width:95px; min-height: 35px; } .nav li a strong { display:block; font-size:14px; font-weight:normal; } .nav li a span { display:block; font-size:10px; line-height:14px; }
I hope you can utilize this knowledge to push the boundaries of beautiful wordpress generated menus ;)
Hi,thanks for the post but I am having little problem I don’t know whether this is the right place to post the problem night be it is not related to it..I have created a custom menu to show the page in the navigation bar from WordPress but it does not show in the navigation bar..What to do?
I have the same problem, some one there to guide?
Sounds awesome, wish it wasn’t over my head, lol.
It was very wonderful article …. exactly what i need :)
thnx to the author ….
Right on the money, thank you for a great tut. I’ll definitely have a look on the other articles here too :)
Thanks! Finally able to figure out how to identify the first and last menu item with this tutorial.
To add a class to the first menu item:
if ($item->menu_order == 1) {
$classes[] = 'first';
}
To add a class to the last menu item:
if ($item->ID == get_theme_mod('lastmenuitem')) {
$classes[] = 'last';
}
and add this function to functions.php
function mytheme_options() {
global $wpdb;
$topmenuid = get_theme_mod('nav_menu_locations');
if ($topmenuid['top-menu'] != '0') {
$menutermtax = $wpdb->get_var("SELECT term_taxonomy_id FROM $wpdb->term_taxonomy WHERE term_id = " . $topmenuid['top-menu']);
$menuitem_post_ids = $wpdb->get_var("
SELECT posts.ID
FROM " . $wpdb->prefix . "posts AS posts
INNER JOIN (
SELECT object_id
FROM " . $wpdb->prefix . "term_relationships
WHERE term_taxonomy_id = " . $menutermtax . "
) AS termid ON termid.object_id = posts.ID
ORDER BY posts.menu_order DESC
LIMIT 1
");
set_theme_mod('lastmenuitem',$menuitem_post_ids);
}
}
add_action('init', 'mytheme_options')
?>
This is great, but what if I want to use a “Custom Menu” widget… how do you make the function call in that case?
Great tut, thanks for sharing, I was just wondering if it’s possible to use this in personal and commercial template?
PS. I love all your work, keep it up!
Use it wherever you need it :)
Excellent tutorial. I was using a theme that implements this walker menu but the output was all wrong. Finally realized there are description options in the wordpress menu backend after reading your tutorial. You saved me a lot of trouble. Just wondering if I can use this code in one of my upcoming themes.
Same here, use it wherever you need it :)
Hi Kriesi,
It works for me,
But I’m having an issue, I can’t re order the menu items in the Menu Administration,
Any ideas ?
Many thanks.
Thanks for providing this tutorial.can you provide a tutorial with high quality drop down menu?
it seems that $item->description=” ” by default (” ” and no “”)
There is a space
So, you write :
$description = ! empty( $item->description ) ? ”.esc_attr( $item->description ).” : ”;
but $item->description is never empty
i’m adding :
if ($item->description==” “) $item->description=””;
you write : start_el(&$output
the & must be removing, no ?
arf, sorry, it’s a reference variable, isn’t it ?
Thanks Kriesi, I remembered reading this a while back and came in real handy today.
i have a problem activating the jQuery Lightbox this is the error:
Plugin could not be activated because it triggered a fatal error.
Parse error: syntax error, unexpected T_STATIC, expecting T_OLD_FUNCTION or T_FUNCTION or T_VAR or ‘}’ in /home/content/r/o/g/rogerplasencia/html/newsite/wp-content/plugins/jquery-lightbox-balupton-edition/jquery-lightbox.php on line 13
i really appreciatte ur help. thanks
im working with AVISIO templates, i need to change the portfolio template because i want to eliminate a columm that i dont need at all but i dont know how to do it. Could anybody help with this.
thanks in advance.