Roots Discourse

Multiple walker classes

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.