Update: Menu items now have the class “menu-item-has-children” that can be used for styling thank to this core ticket. So, the menu walker is no longer needed.
I think it’s important to give users a visual cue when menu items have a drop down menu.
One way I’ve handled this in the past is to use the Superfish jQuery plugin, which adds a class to any list items with children. This allows them to be styled differently- with a background image of a down arrow (for instance).
However, I just saw a new theme released by Paul de Wouters called Spine. Instead of using javascript to apply the class- he uses a custom Walker_Nav_Menu so that the class is added to the markup directly.
I think this is a much better way to do it, and solves an issue I’ve seen in some themes where the menu items shift a bit when the new classes and styling are applied with javascript.
Custom Walker Code
I’ve adapted Paul’s code a little bit so it just adds a “has-children” css class to any top level “li” that has a “ul” contained within it:
class Custom_Nav_Walker extends Walker_Nav_Menu { function display_element( $element, &$children_elements, $max_depth, $depth=0, $args, &$output ) { $id_field = $this->db_fields['id']; if ( !empty( $children_elements[$element->$id_field] ) && ( depth == 0 ) ) { $element->classes[] = 'has-children'; // Use any classname you like } Walker_Nav_Menu::display_element( $element, $children_elements, $max_depth, $depth, $args, $output ); } }
Then, when you call the menu in the theme, make sure to include the walker:
<?php wp_nav_menu( array( 'theme_location' => 'primary', 'walker' => new Visual_Nav_Walker(), 'depth' => '2' ) ); ?>
However, for some reason the above code does not fall back to wp_page_menu properly when no menu is set. So, this is my workaround:
if ( has_nav_menu( 'primary' ) ) { wp_nav_menu( array( 'theme_location' => 'primary', 'walker' => new Visual_Nav_Walker(), 'depth' => '2' ) ); } else { wp_page_menu(); }
Menu Filter (Updated 3/20/13)
Chip Bennet posted an alternative approach using a filter on wp_nav_menu_objects to the WordPress Theme Reviewers List. This approach seems a bit more straightforward than a walker, so it’s also worth checking out.
Styling the List Item
There’s many ways you could go about styling this list item with the “has-children” class. For a new theme I’ve been working on, I already use glyphs from the Entypo icon font– and I think the “chevron-small-down” from this collection works great as a drop down menu indicator.
To use it with my menu (.main-navigation) I just needed to add this CSS:
.main-navigation li { float: left; position: relative; } .main-navigation li.has-children a { padding-right:40px; } .main-navigation li.has-children > a:after { content:'\e760'; font-family: 'entypo'; position: absolute; right:20px; speak: none; }
(For more about using icon fonts, see this post)
I’ve also been thinking a “has-children” class might be a good core feature. Any thoughts?
+1 to pushing this as a patch back to core. I think that’s a great idea.
I’ve always used superfish for my drop-downs which ads the sub item indicator via JS, but this is much better and perfect for CSS only menus – slick!
Thanks for the share ;)
Thanks for mentioning Spine Devin!
What I did is adapt the code from the Zurb Foundation framework to work with WordPress custom menus
http://foundation.zurb.com/docs/components/top-bar.html
And I think that particular Walker code I used came from here
http://stackoverflow.com/questions/3558198/php-wordpress-add-arrows-to-parent-menus
Credit given where it’s due :)
The custom Nav Walker is really useful. I’ve been using it when creating a WP theme with Bootstrap framework. And not only Bootstrap, but almost every CSS library (like Foundation in Spine theme), they require custom HTML markup for its element, e.g. nav menu.
This is a good technique, and I think it should be the “official” way to customize the menu.
Hi Devin,
Thanks for turning me on to this patch. This is a much better solution than superfish.
Looks much better, thanks for sharing this patch.
It’s not work for me.
This css work for me.
#navwrap li a:not(:last-child):after {
content: “\e760”;
font-family: ‘entypo’;
padding-left: 0.5em;
speak: none;
}
#navwrap ul ul li a:not(:last-child):after {
content:’\e762′;
font-family: ‘entypo’;
position: absolute;
right:20px;
speak: none;
}
Note: #navwrap is my menu id.
Thanks for share code. I was looking how to create a drop down menu. Thanks
Hey there,
Is there a way to do this but instead wrap the parent link in a ‘parent’ div IF it has children, and also include a description to the parent if it has one?
Likely. I’d ask the question in the support forums: http://wordpress.org/support/
The custom Nav Walker is really useful.
I just updated this post. Check the notice up top!
Is it not easier to just use wordpress class menu-item-has-children and apply css directly?
Yep, that’s the very first sentence in this post.
I think the CSS solution is better than using the PHP code.
Thanks for sharing. This Nav Walker is really useful. But I think the CSS solution is better than PHP code.