WordPress Nav Menu Separator

WordPress for some ridiculous reason does not make it easy to implement a nav separator between each of your custom menu nav items. After searching around there were couple of good suggestions that I came across, some CSS based and others that hook in to the wp_nav_menu call.

However none of them really worked very well I thought, so here is my solution to this problem. It basically involves utilising the Custom Walker Function param of wp_nav_menu, which  is a PHP class used when WordPress builds up menu items.

So first of all you should have already defined your custom menu and integrated it in to your theme, i.e:

functions.php

// Allows menus to be created in Wp-Admin -> Appearance -> Menus
register_nav_menu( 'footer', 'The footer menu' );

Theme file

<?php
	wp_nav_menu(array(
		'theme_location'	=> 'footer',
		'menu_class'		=> 'clearfix',
		'container'			=> false 
	));
?>

Next you need to actually add the menu separator in to those places in the menu where you would like it to appear. In my menu I opted for the | separator, you won’t be able to add a menu item without a link so just use #.

Wordpress-Custom-Menu

Unfortunately WordPress will still place anchor HTML tags around these separator items, which isn’t ideal as it really isn’t a link – plus it also may look weird, depending on your CSS styling. What we need to do is place an exception for when the menu code reaches our separators.

What you will need to do is open the Walker_Nav_Menu class file located in wp-includes/nav-menu-template.php and copy the start_el method, it should look something like below – note this was taken from Worpdress 3.5.1, I recommend you copy the method from your copy of the Walker_Nav_Menu class as it may change in the future.

You then need to create a new PHP class that extends Walker_Nav_Menu and override the method with our own, in my example I’ve placed the code at the bottom of my functions.php.

functions.php

class Walker_Function extends Walker_Nav_Menu {

    /**
     * @see Walker::start_el()
     * @since 3.0.0
     *
     * @param string $output Passed by reference. Used to append additional content.
     * @param object $item Menu item data object.
     * @param int $depth Depth of menu item. Used for padding.
     * @param int $current_page Menu item ID.
     * @param object $args
     */
    function start_el( &$output, $item, $depth = 0, $args = array(), $id = 0 ) {
        $indent = ( $depth ) ? str_repeat( "\t", $depth ) : '';

        $class_names = $value = '';

        $classes = empty( $item->classes ) ? array() : (array) $item->classes;
        $classes[] = 'menu-item-' . $item->ID;

        $class_names = join( ' ', apply_filters( 'nav_menu_css_class', array_filter( $classes ), $item, $args ) );
        $class_names = $class_names ? ' class="' . esc_attr( $class_names ) . '"' : '';

        $id = apply_filters( 'nav_menu_item_id', 'menu-item-'. $item->ID, $item, $args );
        $id = $id ? ' id="' . esc_attr( $id ) . '"' : '';

        $output .= $indent . '<li' . $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;
        if($item->title == '|'){
            $item_output .= $args->link_before . apply_filters( 'the_title', $item->title, $item->ID ) . $args->link_after;
        } else {
            $item_output .= '<a'. $attributes .'>';
            $item_output .= $args->link_before . apply_filters( 'the_title', $item->title, $item->ID ) . $args->link_after;
            $item_output .= '</a>';
        }
        $item_output .= $args->after;

        $output .= apply_filters( 'walker_nav_menu_start_el', $item_output, $item, $depth, $args );
    }

}

Note the differences between lines 34 and 42. In this example I’ve used the | separator, but if you want you can use any character you wish.

Before

	$item_output = $args->before;
	$item_output .= '<a'. $attributes .'>';
	$item_output .= $args->link_before . apply_filters( 'the_title', $item->title, $item->ID ) . $args->link_after;
	$item_output .= '</a>';
	$item_output .= $args->after;

After

	$item_output = $args->before;
	if($item->title == '|'){
		$item_output .= $args->link_before . apply_filters( 'the_title', $item->title, $item->ID ) . $args->link_after;
	} else {
		$item_output .= '<a'. $attributes .'>';
		$item_output .= $args->link_before . apply_filters( 'the_title', $item->title, $item->ID ) . $args->link_after;
		$item_output .= '</a>';
	}
	$item_output .= $args->after;

It is then a simple case of invoking our custom walker method instead of the default one, change your menu code in your theme to something like the following

Theme file

<?php
	wp_nav_menu(array(
		'theme_location'	=> 'footer',
		'menu_class'		=> 'clearfix',
		'container'			=> false,
		'walker'			=> new Walker_Function
	));
?>

Your menu output should then look like so

<ul class="clearfix" id="menu-footer">
	<li class="menu-item menu-item-type-post_type menu-item-object-page current-menu-item page_item page-item-2 current_page_item menu-item-36" id="menu-item-36">
		<a href="http://example.com/">Home</a>
	</li>
	<li class="menu-item menu-item-type-custom menu-item-object-custom menu-item-37" id="menu-item-37">|</li>
	<li class="menu-item menu-item-type-post_type menu-item-object-page menu-item-35" id="menu-item-35">
		<a href="http://example.com/about/">About</a></li>
	<li class="menu-item menu-item-type-custom menu-item-object-custom menu-item-38" id="menu-item-38">|</li>
	<li class="menu-item menu-item-type-post_type menu-item-object-page menu-item-34" id="menu-item-34">
		<a href="http://example.com/services/">Services</a>
	</li>
	<li id="menu-item-39" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-39">|</li>
	<li class="menu-item menu-item-type-post_type menu-item-object-page menu-item-33" id="menu-item-33">
		<a href="http://example.com/contact-us/">Contact Us</a>
	</li>
</ul>

Voilà!