/ / /

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