Created
August 4, 2017 19:42
-
-
Save mikedoubintchik/deca86f0d1f7df80c252d3754e0bbed4 to your computer and use it in GitHub Desktop.
Navwalker class for Sage 9
This file contains 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 | |
namespace App; | |
/** | |
* Class NavWalker | |
* | |
* Bootstrap 4 walker with cleaner markup for wp_nav_menu() | |
* For use with Sage >= 8.5 | |
* | |
* Based on Soil NavWalker | |
* @url https://github.com/roots/soil | |
* | |
* | |
* Walker_Nav_Menu (WordPress default) example output: | |
* <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> | |
* | |
* NavWalker example output: | |
* <li class="nav-item menu-item menu-home"><a class="nav-link" href="/">Home</a></li> | |
* | |
* @package Roots\Sage\Nav | |
*/ | |
class NavWalker extends \Walker_Nav_Menu | |
{ | |
/** | |
* @var bool | |
*/ | |
private $cpt; // Boolean, is current post a custom post type | |
/** | |
* @var false|string | |
*/ | |
private $archive; // Stores the archive page for current URL | |
/** | |
* NavWalker constructor. | |
*/ | |
public function __construct() | |
{ | |
add_filter('nav_menu_css_class', array($this, 'cssClasses'), 10, 2); | |
add_filter('nav_menu_item_id', '__return_null'); | |
$cpt = get_post_type(); | |
$this->cpt = in_array($cpt, get_post_types(array('_builtin' => false))); | |
$this->archive = get_post_type_archive_link($cpt); | |
} | |
/** | |
* Check item classes for current or active | |
* | |
* @param $classes | |
* | |
* @return int | |
*/ | |
public function checkCurrent($classes) | |
{ | |
return preg_match('/(current[-_])|active/', $classes); | |
} | |
// @codingStandardsIgnoreStart | |
/** | |
* Add dropdown menu class to dropdown UL | |
* | |
* @param string $output | |
* @param int $depth | |
* @param array $args | |
*/ | |
function start_lvl(&$output, $depth = 0, $args = []) | |
{ | |
$output .= "\n<ul class=\"dropdown-menu\" aria-labelledby=\"navbarDropdownMenuLink\">\n"; | |
} | |
/** | |
* Add required Bootstrap 4 classes to anchor links. | |
* | |
* @param string $output | |
* @param \WP_Post $item | |
* @param int $depth | |
* @param array $args | |
* @param int $id | |
*/ | |
function start_el(&$output, $item, $depth = 0, $args = [], $id = 0) | |
{ | |
$item_html = ''; | |
parent::start_el($item_html, $item, $depth, $args); | |
if ($item->is_subitem) { | |
$item_html = str_replace('<a', '<a class="nav-link dropdown-toggle" data-hover="dropdown" aria-haspopup="true" aria-expanded="false"', $item_html); | |
$item_html = str_replace('</a>', ' <b class="caret"></b></a>', $item_html); | |
} else { | |
$item_html = str_replace('<a', '<a class="nav-link"', $item_html); | |
} | |
$item_html = apply_filters('wp_nav_menu_item', $item_html); | |
$output .= $item_html; | |
} | |
/** | |
* Add active classes to active items & sub items | |
* | |
* @param object $element | |
* @param array $children_elements | |
* @param int $max_depth | |
* @param int $depth | |
* @param array $args | |
* @param string $output | |
*/ | |
public function display_element($element, &$children_elements, $max_depth, $depth = 0, $args, &$output) | |
{ | |
$element->is_subitem = ((!empty($children_elements[$element->ID]) && (($depth + 1) < $max_depth || ($max_depth === 0)))); | |
if ($element->is_subitem) { | |
foreach ($children_elements[$element->ID] as $child) { | |
if ($child->current_item_parent || $this->url_compare($this->archive, $child->url)) { | |
$element->classes[] = 'active'; | |
} | |
} | |
} | |
$element->is_active = (!empty($element->url) && strpos($this->archive, $element->url)); | |
if ($element->is_active) { | |
$element->classes[] = 'active'; | |
} | |
parent::display_element($element, $children_elements, $max_depth, $depth, $args, $output); | |
} | |
// @codingStandardsIgnoreEnd | |
/** | |
* Clean up css classes | |
* | |
* @param $classes | |
* @param $item | |
* | |
* @return array | |
*/ | |
public function cssClasses($classes, $item) | |
{ | |
$slug = sanitize_title($item->title); | |
// Fix core `active` behavior for custom post types | |
if ($this->cpt) { | |
$classes = str_replace('current_page_parent', '', $classes); | |
if ($this->url_compare($this->archive, $item->url)) { | |
$classes[] = 'active'; | |
} | |
} | |
// Remove most core classes | |
$classes = preg_replace('/(current(-menu-|[-_]page[-_])(item|parent|ancestor))/', 'active', $classes); | |
$classes = preg_replace('/^((menu|page)[-_\w+]+)+/', '', $classes); | |
// Add `menu-item` class & re-add core `menu-item` class | |
$classes[] = 'nav-item menu-item'; | |
// Add `dropdown` class & re-add core `menu-item-has-children` class on parent elements | |
if ($item->is_subitem) { | |
$classes[] = 'dropdown menu-item-has-children'; | |
} | |
// Add `menu-<slug>` class | |
$classes[] = 'menu-' . $slug; | |
$classes = array_unique($classes); | |
$classes = array_map('trim', $classes); | |
return array_filter($classes); | |
} | |
/** | |
* Make a URL relative | |
* | |
* Utility function, from soil | |
* @url https://github.com/roots/soil | |
* | |
* @param $input | |
* | |
* @return string | |
*/ | |
public function root_relative_url($input) | |
{ | |
if (is_feed()) { | |
return $input; | |
} | |
$url = parse_url($input); | |
if (!isset($url['host']) || !isset($url['path'])) { | |
return $input; | |
} | |
$site_url = parse_url(network_home_url()); // falls back to home_url | |
if (!isset($url['scheme'])) { | |
$url['scheme'] = $site_url['scheme']; | |
} | |
$hosts_match = $site_url['host'] === $url['host']; | |
$schemes_match = $site_url['scheme'] === $url['scheme']; | |
$ports_exist = isset($site_url['port']) && isset($url['port']); | |
$ports_match = ($ports_exist) ? $site_url['port'] === $url['port'] : true; | |
if ($hosts_match && $schemes_match && $ports_match) { | |
return wp_make_link_relative($input); | |
} | |
return $input; | |
} | |
/** | |
* Compare URL against relative URL | |
* | |
* Utility function, from Soil | |
* @url https://github.com/roots/soil | |
* | |
* @param $url | |
* @param $rel | |
* | |
* @return bool | |
*/ | |
public function url_compare($url, $rel) | |
{ | |
$url = trailingslashit($url); | |
$rel = trailingslashit($rel); | |
return ((strcasecmp($url, $rel) === 0) || $this->root_relative_url($url) == $rel); | |
} | |
} | |
/** | |
* Clean up wp_nav_menu_args | |
* | |
* Remove the container | |
* Remove the id="" on nav menu items | |
* | |
* @param string $args | |
* | |
* @return array | |
*/ | |
function nav_menu_args($args = '') | |
{ | |
$nav_menu_args = []; | |
$nav_menu_args['container'] = false; | |
if (is_array($args) && !$args['items_wrap']) { | |
$nav_menu_args['items_wrap'] = '<ul class="%2$s">%3$s</ul>'; | |
} | |
if (!$args['walker']) { | |
$nav_menu_args['walker'] = new NavWalker(); | |
} | |
return array_merge($args, $nav_menu_args); | |
} | |
add_filter('wp_nav_menu_args', __NAMESPACE__ . '\\nav_menu_args'); | |
add_filter('nav_menu_item_id', '__return_null'); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment