Log1x / navi

A developer-friendly alternative to the WordPress NavWalker.
https://github.com/Log1x/navi
MIT License
315 stars 30 forks source link

Navigations placed in widgets #40

Closed davidwebca closed 1 year ago

davidwebca commented 3 years ago

Hi!

This is more of a feedback/idea than an issue. I wanted to share how I managed to have navi working with widgets, so that maybe you could include it somewhere in your examples.

First, to separate the logic as much as possible within my view composer, I'm including my views with a "menu" property. It's using Navi's standard which is to either receive a menu location or a menu object (WP_term).

<?php

namespace App\View\Composers;

use Roots\Acorn\View\Composer;
use Log1x\Navi\Facades\Navi;

class Navigation extends Composer
{
    /**
     * List of views served by this composer.
     *
     * @var array
     */
    protected static $views = [
        'partials.navigation',
    ];

    /**
     * Data to be passed to view before rendering.
     *
     * @return array
     */
    public function with()
    {
        $data = $this->view->getData();

        return [
            'navigation' => $this->navigation($data['menu']),
        ];
    }

    /**
     * Returns the primary navigation.
     * 
     * @param  int|string|WP_Term $menu
     * 
     * @return array
     */
    public function navigation($menu_or_location = 'primary_navigation')
    {
        if (Navi::build($menu_or_location)->isEmpty()) {
            return;
        }

        return Navi::build($menu_or_location)->toArray();
    }
}

Of course, when I'm including my navigation, I now need to pass in the location, for example, the primary nav.

@include('partials.navigation', ['menu' => 'primary_navigation'])

But after this step, it's easy to add some simple filters to functions.php or filters.php if using sage.

To make sure I don't conflict with weird nav_menus being used by some plugins and page builders, I pass a 'navi' attribute to 'widget_nav_menu_args' to make sure I really only ever target menus in widgets. I'm also forcing "echo" to true, even though it should already be true, because the 'pre_wp_nav_menu' filter needs echo to be true to process the output of our shortcircuit.

The beauty of 'pre_wp_nav_menu', if you look at the code, is really that nothing gets further processed by WordPress and that the execution of wp_nav_menu is stopped right there.

use function Roots\view;

/**
 * Use Navi for widget menus
 */
add_filter('widget_nav_menu_args', function($nav_menu_args, $nav_menu, $args, $instance) {
    $nav_menu_args['navi'] = true;
    $nav_menu_args['echo'] = true;
    return $nav_menu_args;
}, 10, 4);

add_filter('pre_wp_nav_menu', function($shortcircuit, $args) {

    if(isset($args->navi) && $args->navi) {
        $shortcircuit = view('partials.navigation', ['menu' => $args->menu])->render();
    }

    return $shortcircuit;
}, 10, 2);

Widget away! 🥳