Skip to content

Instantly share code, notes, and snippets.

@fitzhaile
Last active April 17, 2017 15:26
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save fitzhaile/064ac437fc6f265b67f3 to your computer and use it in GitHub Desktop.
Save fitzhaile/064ac437fc6f265b67f3 to your computer and use it in GitHub Desktop.
Alternative BEM-based lib/nav.php for Roots Theme
<?php
/**
* Cleaner, BEM-based walker for wp_nav_menu()
*
* (Attempts to adhere more to http://cssguidelin.es.)
*
* NOTE: This apprroach requires substitute arguments to be passed to wp_nav_menu().
*
* 'nav_class' - Class attached to the <nav> element that contains the menu.
* It is used to generate classes for the ul, li and anchor elements. For example,
* "site-nav" will generate ul.site-nav__list > li.site-nav__item > a.site-nav__link.
*
* Walker_Nav_Menu (WordPress default) example output:
* <ul id="menu-primary-navigation" class="menu">
* <li id="menu-item-8" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-8"><a href="/">Home</a></li>
* <li id="menu-item-9" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-9"><a href="/sample-page/">Sample Page</a></l
* </ul>
*
* Roots_Nav_Walker example output, assuming a <nav> class of "site-nav", passed to wp_nav_menu():
* e.g. wp_nav_menu( array( 'theme_location' => 'primary_navigation', 'nav_class' => 'site-nav' ) )
*
* <ul class="site-nav__list"
* <li class="site-nav__item"><a href="/" class="site-nav__link site-nav__home">Home</a></li>
* <li class="site-nav__item"><a href="/sample-page/" class="site-nav__link site-nav__sample-page">Sample Page</a></li>
* </ul>
*
* Deviations from Roots core:
*
* [1] Declare class attribute for $nav_class [a] that can be passed to a constructor [b]
*
* [2] Use the passed $nav_class class attribute to generate classes for menu item li > a's
*
* [3] Use the passed $nav_class class attribute to generate classes for menu item li's
*/
class Roots_Nav_Walker extends Walker_Nav_Menu {
// [1a]
public $nav_class;
// [1b]
public function __construct( $nav_class ) {
$this->nav_class = $nav_class;
}
function check_current( $classes ) {
return preg_match( '/(current[-_])|active|dropdown/', $classes );
} // end Roots_Nav_Walker::check_current()
function start_lvl( &$output, $depth = 0, $args = array() ) {
$output .= "\n<ul class=\"dropdown-menu\">\n";
} // end Roots_Nav_Walker::start_lvl()
function start_el( &$output, $item, $depth = 0, $args = array(), $id = 0 ) {
$item_html = '';
parent::start_el( $item_html, $item, $depth, $args );
if ( $item->is_dropdown && ( $depth === 0 ) ) {
$item_html = str_replace( '</a>', ' <b class="caret"></b></a>', $item_html );
}
// [2]
if ( $this->nav_class ) {
$slug = sanitize_title( $item->title );
$item_html = str_replace( '<a', "<a class=\"{$this->nav_class}__link {$this->nav_class}__{$slug}\"", $item_html );
}
$item_html = apply_filters( 'roots/wp_nav_menu_item', $item_html );
$output .= $item_html;
} // end Roots_Nav_Walker::start_el()
function display_element( $element, &$children_elements, $max_depth, $depth = 0, $args, &$output ) {
$element->is_dropdown = ( ( !empty( $children_elements[$element->ID] ) && ( ( $depth + 1 ) < $max_depth || ( $max_depth === 0 ) ) ) );
// [3]
$slug = sanitize_title( $element->title );
if ( $this->nav_class ) {
$element->classes[] = "{$this->nav_class}__item";
} else {
// Roots default
$element->classes[] = "menu-item-{$slug}";
}
if ( $element->is_dropdown ) {
$element->classes[] = "dropdown";
}
// [4]
$element->classes = preg_replace( '/(current(-menu-|[-_]page[-_])(item|parent|ancestor))/', "active", $element->classes );
parent::display_element( $element, $children_elements, $max_depth, $depth, $args, $output );
} // end Roots_Nav_Walker::display_element()
} // end class Roots_Nav_Walker
/**
* Cleanup li item markup spacing, strip out WP default classes
*
* Deviations from Roots core:
*
* [1] Add two spaces between classes
*
* [2] Move the active class to the bottom of the class array (to be displayed last)
*
* [3] Strip trailing spaces in class names
*
* Note: The genration of css menu item classes normally found in Roots core have been
* moved to to the Roots_Nav_Walker::display_element() in order to generate more customized
* menu item li classes.
*/
function roots_nav_menu_css_class( $classes, $item ) {
$classes = preg_replace( '/^((menu|page)[-_\w+]+)+/', '', $classes );
// [1]
$classes = preg_replace( '/(.+)/', "\$1 ", $classes );
$classes = array_unique( array_filter( $classes, 'is_element_empty' ) );
// [2]
if ( $active_array = preg_grep( '/active/', $classes ) ) {
$remainder_array = array_diff( $classes, $active_array );
$classes = array_merge( $remainder_array, $active_array );
}
// [3]
end( $classes ) && $classes[key( $classes )] = rtrim( $classes[key( $classes )] );
reset( $classes );
return $classes;
} // end roots_nav_menu_css_class()
add_filter( 'nav_menu_css_class', 'roots_nav_menu_css_class', 10, 2 );
add_filter( 'nav_menu_item_id', '__return_null' );
/**
* Clean up wp_nav_menu_args
*
* Deviations from Roots core:
*
* [1] Remove the container
*
* [2] Add the possibility for one additional arguments to be passed to
* wp_nav_menu() and rename the ul class (if 'menu_class' has not been passed)
*
* [3] Remove the id from the ul. Previous attempts to do this in the Roots core did not work.
* https://github.com/roots/roots/issues/1145#issuecomment-54639003
*
* [4] Use Roots_Nav_Walker() by default, pass the new 'nav_class' to the constructor.
*/
function roots_nav_menu_args( $args = '' ) {
// [1]
$roots_nav_menu_args['container'] = false;
// [2]
if ( ! $args['menu_class'] || $args['menu_class'] == 'menu' ) { // 'menu' is the wp_nav_menu() default
if ( $args['nav_class'] ) {
$roots_nav_menu_args['nav_class'] = $args['nav_class'];
$roots_nav_menu_args['menu_class'] = "{$args['nav_class']}__list";
}
} else {
$roots_nav_menu_args['menu_class'] = $args['menu_class'];
}
// [3]
if ( $args['items_wrap'] == '<ul id="%1$s" class="%2$s">%3$s</ul>' ) {
$roots_nav_menu_args['items_wrap'] = '<ul class="%2$s">%3$s</ul>';
}
if ( ! $args['depth'] ) {
$roots_nav_menu_args['depth'] = 2;
}
// [4]
if ( ! $args['walker'] ) {
$roots_nav_menu_args['walker'] = new Roots_Nav_Walker( $roots_nav_menu_args['nav_class'] );
}
return array_merge( $args, $roots_nav_menu_args );
} // end roots_nav_menu_args()
add_filter( 'wp_nav_menu_args', 'roots_nav_menu_args' );
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment