How to Output Custom HTML in WordPress Menus Using a Custom Nav Walker

We’ve recently received requests to develop websites for clients that have Mega Menus, and to make those menus manageable from within the WordPress Menu System. Mega Menus are a style of menu that allow you to provide the visitor with much more information about a menu item – and they help to turn drab drop downs into exciting, graphical elements.

I spent a little while looking into the right way to implement this and came up with a solution that I thought I’d share.

Most of this process involves putting together a custom Nav Walker – you can read more on the Nav Walker class here.

We will customize 3 parts of the nav walker:

  • the start of the sub-menu output
  • the end of the sub-menu output
  • the link output

We want to wrap the sub-menu in custom HTML, mostly because this gives us a bit more control over the styling of the menu than the standard WordPress menu HTML will. The first two functions in the class will output the custom wrapping HTML while the third function outputs the actual link – we’ve updated that to output the Description text as well.

To create a custom nav walker in WordPress, paste the following code into your theme’s functions.php:

class ik_walker extends Walker_Nav_Menu{
	//start of the sub menu wrap
	function start_lvl(&$output, $depth) {
		$output .= '<div class="drop">
						<div class="holder">
							<div class="container">
								<ul class="list">';
	//end of the sub menu wrap
	function end_lvl(&$output, $depth) {
		$output .= '
			<div class="bottom"></div>
	//add the description to the menu item output
	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		) .'"' : '';
		$item_output = $args->before;
		$item_output .= '<a'. $attributes .'>';
		$item_output .= $args->link_before . apply_filters( 'the_title', $item->title, $item->ID ) . $args->link_after;
		if(strlen($item->description)>2){ $item_output .= '<br /><span class="sub">' . $item->description . '</span>'; }
		$item_output .= '</a>';
		$item_output .= $args->after;
		$output .= apply_filters( 'walker_nav_menu_start_el', $item_output, $item, $depth, $args );

Once you have that code in place and formatted the way you like, using any custom HTML you need, you’ll just need to use the following wp_nav_menu call to be sure you’re using the walker we just made:

wp_nav_menu( array(
	'container' => false,
	'menu_id' => 'nav',
	'depth' => 0,
	'theme_location' => 'primary',
	//this is the important part, we tell it to use the nav walker we just wrote
	'walker' => new ik_walker())

With all of the above code in place, you can start outputting your custom menus now. You can achieve similar results by passing your desired wrapping HTML to the wp_nav_menu function, but this example also includes the Description output as well as provides a great entry point for further customization of thewp_nav_menu output.

You’ll still have to write all of your CSS but hopefully this gets you down the right path!

Facebook Comments