I’ve also written a Custom Comment Walker function, after 3 hours of searching, I’m convinced it may be the only one out there lol…
If you’re trying to make a fancy navigation menu with CSS, you might have found the default IDs and classes applied by WordPress to the nav menu elements to be quite lacking. However, you can fix that by adding a custom walker function to add your own conditional classes. The custom nav walker function I made below will add the following CSS classes:
CSS Classes
- .main-menu to top menu
- .sub-menu to menus inside the main-menu
- .menu-item to all <li>’s
- .main-menu-item to all <li>’s in the main menu
- .sub-menu-item to all <li>’s in a sub-menu
- .sub-sub-menu to all menus inside a sub-menu
- .menu-even/.menu-odd for <ul>’s (alternating)
- .menu-depth-# to tell you how deep each menu is
- .menu-item-even or .menu-item-odd (alternating)
- .menu-item-depth-# to tell you which level menu the <li> is in
- .menu-link to links
Optional Features
These requested features were can also be added to the code below. Click on each to be taken to the comment on this page describing how to integrate it.
This should make styling your Navigation Menus MUCH simpler.
Code
You call the function by supplying the name in the $args when you call the wp_nav_menu function in you theme. So for example, to enable our walker, we would call the menu with this:
Print Registered Nav Menu
wp_nav_menu( array(
'theme_location' => 'navigation_menu_primary',
'container' => 'div',
'container_id' => 'top-navigation-primary',
'conatiner_class' => 'top-navigation',
'menu_class' => 'menu main-menu menu-depth-0 menu-even',
'echo' => true,
'items_wrap' => '<ul id="%1$s" class="%2$s">%3$s</ul>',
'depth' => 10,
'walker' => new themeslug_walker_nav_menu
) ); // thanks nick
This would create the nav menu for the location “navigation_menu_secondary” give it a div wrapper with an id and class, and the first level menu will get the added classes main-menu, menu-depth-0, and menu-even. Now on to our custom walker function:
Custom Nav Menu Walker Function
class themeslug_walker_nav_menu extends Walker_Nav_Menu {
// add classes to ul sub-menus
function start_lvl( &$output, $depth ) {
// depth dependent classes
$indent = ( $depth > 0 ? str_repeat( "\t", $depth ) : '' ); // code indent
$display_depth = ( $depth + 1); // because it counts the first submenu as 0
$classes = array(
'sub-menu',
( $display_depth % 2 ? 'menu-odd' : 'menu-even' ),
( $display_depth >=2 ? 'sub-sub-menu' : '' ),
'menu-depth-' . $display_depth
);
$class_names = implode( ' ', $classes );
// build html
$output .= "\n" . $indent . '<ul class="' . $class_names . '">' . "\n";
}
// add main/sub classes to li's and links
function start_el( &$output, $item, $depth, $args ) {
global $wp_query;
$indent = ( $depth > 0 ? str_repeat( "\t", $depth ) : '' ); // code indent
// depth dependent classes
$depth_classes = array(
( $depth == 0 ? 'main-menu-item' : 'sub-menu-item' ),
( $depth >=2 ? 'sub-sub-menu-item' : '' ),
( $depth % 2 ? 'menu-item-odd' : 'menu-item-even' ),
'menu-item-depth-' . $depth
);
$depth_class_names = esc_attr( implode( ' ', $depth_classes ) );
// passed classes
$classes = empty( $item->classes ) ? array() : (array) $item->classes;
$class_names = esc_attr( implode( ' ', apply_filters( 'nav_menu_css_class', array_filter( $classes ), $item ) ) );
// build html
$output .= $indent . '<li id="nav-menu-item-'. $item->ID . '" class="' . $depth_class_names . ' ' . $class_names . '">';
// link attributes
$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 ) .'"' : '';
$attributes .= ' class="menu-link ' . ( $depth > 0 ? 'sub-menu-link' : 'main-menu-link' ) . '"';
$item_output = sprintf( '%1$s<a%2$s>%3$s%4$s%5$s</a>%6$s',
$args->before,
$attributes,
$args->link_before,
apply_filters( 'the_title', $item->title, $item->ID ),
$args->link_after,
$args->after
);
// build html
$output .= apply_filters( 'walker_nav_menu_start_el', $item_output, $item, $depth, $args );
}
}
I hope this was helpful! If you have an improvement of this code, let me know and I’ll incorporate your changes (with credit, of course).

You have syntax error in first block of code. You are closing the array but not the function.
Thanks, will fix this.
Hello, thanks for sharing this code snippet.
I am wondering if it’s possible to exclude one menu item based on its ID
Thanks in advance.
Sure, on the second line of the
start_el()function (on the line right afterglobal $wp_query;) insert the following code to skip a particular menu item:$id_to_skip = 44; if( $item->ID == $id_to_skip ) return $output;If you want to skip multiple IDs, use this slightly more complicated version:
$ids_to_skip = array( 44, 45, 46 ); foreach( $ids_to_skip as $id_to_skip ) if( $item->ID == $id_to_skip ) return $output;Hope this helps!
Use K.I.S.S. everywhere…
$ids_to_skip = array( 44, 45, 46 ); if( in_array($item->ID, $ids_to_skip)) return $output;
Thanks bitacre, works like a charm!
I was wondering if there some way to pass the ID through the
wp_nav_menuarray.Thanks again!
I’m trying to figure out the best solution to display the featured image (as a background) of each post, if the post doesn’t have a feature image it will set a default one. I can see it achievable using the walkers, any hints from where I should start?
Thanks
I can definetly give you a place to start:
Anywhere in the
start_el()function, you can determine if the current menu item has an associated thumbnail by using$bool = has_post_thumbnail( $item->ID);.That will return a boolean which you can craft into an
if()statement to display the post thumbnail. I can’t get any more specific than that without knowing exactly how you want it displayed, but I’m sure you can figure it out using the post thumbnail functions, and item->ID to specify the post’s ID.Let me know if you get stuck and what you’re solution is, I may add this to the list of advanced options on this tutorial! Thanks!
A couple Questions:
I’m wanting to add classes to the sub-menus. this seems like what I need…
Is the Custom Nav Menu Walker Function supposed to be copied into the nav-menu-template.php?
It’s a function, so it belongs in functions.php or in whatever sub-file is appropriate if you break down your functions into several different files and include them in functions.php. If you put it anywhere else, there’s no guarantee that template file will be loaded.
Hi,
I’m trying to modify this with a function end_lvl to add a div to the end of the ul. The problem is that the div needs to contain unique content in each dropdown, so I’m trying to use $item->ID to find it! Here is my code:
// add div to sub-menu function end_lvl( &$output, $item, $depth ) { global $wp_query; $indent = str_repeat(“\t”, $depth);
}
I can’t seem to use $item or the global query to add the item ID at any point. Do you have any suggestions?
Sorry the code didn’t paste very well:
}
How I can add a class only to the top level parent?
try using if($depth === 0) $classes[] = ‘nameOfYourClass’; below the definition of $classes in the start_lvl method
Pingback: Navigation Menus | Anand Verma
thanks dude..
your snippet code make my life easier lol