I’ve wanted to use a walker class for my header, and footer.
I’ve started with a header, got the walker class code in, modified it to my needs, HTML/CSS wise - it worked, all good.
Now, the walker class seemed to apply to both, header and footer by default.
So I created a new walker class ‘footer-walker’ same code just different name, and it broke.
I’ve then modified the footer walker HTML class to have different visual effects and…
I’ve deleted the ‘nav-walker’ class. The footer-walker has worked, so there isn’t an issue with it, however, once I put the ‘nav-walker’ class again, it broke! I have no idea what am doing wrong!
Functions:
}, ['helpers', 'setup', 'filters',
Preformatted text'admin', 'footer-walker', 'nav-walker']);
This is my header:
@if (has_nav_menu('primary_navigation'))
{!! wp_nav_menu([
'theme_location' => 'primary_navigation',
'menu_class' => 'flex',
'walker' => new \App\NavWalker()
]) !!}
@endif
Footer:
@if (has_nav_menu(‘secondary_navigation’))
{!! wp_nav_menu([
‘theme_location’ => ‘secondary_navigation’,
‘menu_class’ => ‘flex’,
‘walker’ => new \App\FooterWalker()
]) !!}
@endif
And the walker class for the nav, which is almost identical to footer walker class, except the name and different css classes.
<?php
namespace App;
/**
* Class NavWalker
*
* Bootstrap 4 walker with cleaner markup for wp_footer_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 FooterWalker 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( 'footer_menu_css_class', array( $this, 'cssClasses' ), 10, 2 );
add_filter( 'footer_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-toggle="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 tracking-three py-2 px-3 text-sm hover:text-white"', $item_html );
}
$item_html = apply_filters( 'wp_footer_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 font-semibold';
// 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_footer_menu_args
*
* Remove the container
* Remove the id="" on nav menu items
*
* @param string $args
*
* @return array
*/
function footer_menu_args( $args = '' ) {
$footer_menu_args = [];
$footer_menu_args['container'] = false;
if ( is_array($args) && !$args['items_wrap'] ) {
$footer_menu_args['items_wrap'] = '<ul class="%2$s">%3$s</ul>';
}
if ( ! $args['walker'] ) {
$footer_menu_args['walker'] = new NavWalker();
}
return array_merge( $args, $footer_menu_args );
}
add_filter( 'wp_footer_menu_args', __NAMESPACE__ . '\\footer_menu_args' );
add_filter( 'footer_menu_item_id', '__return_null' );
I got no idea how to make this work, so the walker classes don’t get ovveriden.
If I have two walker classes, only the nav will get used for both of them.