Instantly share code, notes, and snippets.
Last active
April 17, 2017 15:26
-
Star
2
(2)
You must be signed in to star a gist -
Fork
0
(0)
You must be signed in to fork a gist
-
Save fitzhaile/064ac437fc6f265b67f3 to your computer and use it in GitHub Desktop.
Alternative BEM-based lib/nav.php for Roots Theme
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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