Categories
Foundation Past Tutorials WordPress

WordPress Menu Walker Class for Foundation 5

I’ve been using Foundation for the past few years. Nearly all of my custom WordPress themes have been built on Foundation. However, it’s not without it’s minor faults. In this instance, the fault could be split in half, starting with WordPress’s default wp_page_menu menu function. If you’re developing a theme for a client, this isn’t an issue since you’re going to immediately attach them menu to a theme location on the menu panel page. But what if you are creating a theme for general use?

What I noticed upon activating my Foundation built theme was that the Top Bar was completely empty upon theme activation.

Why is this a problem?

From my observations, quite a few WordPress users DO NOT attach their navigation menus to a theme location, instead they just let the pages automatically add themselves to the top level menu. What you don’t want to hear/read is, “Dude, where is my menu”. Most don’t want to hear explanations about how Foundation’s Top Bar is incompatible with WordPress’s fallback wp_page_menu, so let’s apply a workaround instead.

Foundation 5 Menu Walker Class

/**
 * Foundation 5 Top Bar Menu Walker Class for WordPress 3.9+
 */
 
class F5_TOP_BAR_WALKER extends Walker_Nav_Menu
{ 
	function display_element( $element, &$children_elements, $max_depth, $depth=0, $args, &$output ) 
	{
        $element->has_children = !empty( $children_elements[$element->ID] );
        
        if(!empty($element->classes)){
        	$element->classes[] = ( $element->current || $element->current_item_ancestor ) ? 'active' : '';
        	$element->classes[] = ( $element->has_children ) ? 'has-dropdown' : '';	        
        }
		
        parent::display_element( $element, $children_elements, $max_depth, $depth, $args, $output );
    }
    
	function start_lvl( &$output, $depth = 0, $args = array() ) {
		$indent = str_repeat("\t", $depth);
		$output .= "\n$indent<ul class=\"sub-menu dropdown\">\n";
	}
    
	function start_el(&$output, $item, $depth = 0, $args = array(), $id = 0)
	{
		$item_output = '';
		$indent = ( $depth ) ? str_repeat( "\t", $depth ) : '';
		$output .= ( $depth == 0 ) ? '<li class="divider"></li>' : '';
		$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="' . esc_attr( $class_names ) . '"';
		$output.= $indent.'<li id="menu-item-'. $item->ID.'" '.$class_names.'>';
		
		if ( empty( $item->title ) && empty( $item->url )) 
		{
			$item->url = get_permalink($item->ID);
			$item->title = $item->post_title;
			
			$attributes = $this->attributes($item);

            $item_output .= '<a'. $attributes .'>';
			$item_output .= apply_filters( 'the_title', $item->title, $item->ID );
			$item_output .= '</a>';
		}
		else
		{
			$attributes = $this->attributes($item);
	
			$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;
		}
		
		$output .= apply_filters( 'walker_nav_menu_start_el', $item_output, $item, $depth, $args, $id );
	}
	
	private function attributes($item)
	{
		$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        ) .'"' : '';
		
		return $attributes;
	}
	
	public static function items_default_wrap($menu_text) {
		/**
		 * Set default menu for menus not yet linked to theme location
		 * Method courtesy of robertomatute - https://github.com/roots/roots/issues/939
		 */
		return str_replace('<ul>', '<ul class="right">', $menu_text);
	}
      
	public static function items_remove_defaut_wrapper() 
	{
		/**
		 * Remove default div wrapper around ul element
		 */
		?>
		<script type="text/javascript">
			jQuery(document).ready(function($){
				var default_nav = $(".top-bar-section > div > ul");
				if(default_nav.parent("div").hasClass("right") === true){
		  		default_nav.unwrap();
				}
			});
		</script>
		<?php
	}
}

add_filter('wp_page_menu', array('F5_TOP_BAR_WALKER','items_default_wrap'));
add_action('wp_head', array('F5_TOP_BAR_WALKER','items_remove_defaut_wrapper'));

And the Top Bar markup

<nav class="top-bar" data-topbar>
	<ul class="title-area">
		<li class="name">
			<h1><a href="<?php echo home_url(); ?>"><?php bloginfo('name'); ?></a></h1>
		</li>
		<li class="toggle-topbar menu-icon"><a href="#"><span>Menu</span></a></li>
	</ul>

	<section class="top-bar-section">
	<?php
	wp_nav_menu(array(
    	'container' => false,
    	'menu_class' => 'right',
    	'theme_location' => '<-- your registered menu -->',
        'walker' => new F5_TOP_BAR_WALKER(),
	));
	?>
	</section>
</nav>

And that’s it. I hope this helps. You can also fork this on my Github: https://github.com/wlcdesigns/foundation

And check out Ingleside, a Foundation based theme