web-dev-qa-db-fra.com

Lancer un filtre quand un marcheur court

Existe-t-il un moyen d'exécuter une fonction add_filter particulière chaque fois qu'une classe Walker_Nav_Menu spécifique est exécutée? La fonction doit toujours être exécutée lorsque le marcheur s'en va, et j'aimerais qu'il partage des variables, en particulier $column_limit. La fonction devrait être exécutée juste avant tous les autres éléments du lecteur, afin d’ajouter des classes aux liens avant qu’ils ne soient générés.

Cet ensemble de PHP a pour but d'activer la fonctionnalité d'activation de méga-menus dans WordPress. Essentiellement, si j'ai un balisage comme ceci:

<ul>
    <li><a href="#">Example</a></li>
    <li class="widget">
        <a href="#">Example</a>
        <ul>
            <li><a href="#">Example</a></li>
            <li><a href="#">Example</a></li>
            <li><a href="#">Example</a></li>
            <li class="break"><a href="#">Example</a></li>
            <li><a href="#">Example</a></li>
            <li><a href="#">Example</a></li>
        </ul>
    </li>
    <li><a href="#">Example</a></li>
    <li><a href="#">Example</a></li>
    <li><a href="#">Example</a></li>
</ul>

break et widget étant des classes ajoutées par l'utilisateur dans l'éditeur de menu WordPress, le walker et la fonction affichent ceci:

<ul>
    <li><a href="#">Example</a></li>
    <li class="widget mega-menu-columns-3">
        <a href="#">Example</a>
        <section>
            <ul>
                <li><a href="#">Example</a></li>
                <li><a href="#">Example</a></li>
                <li><a href="#">Example</a></li>
            </ul>
            <ul class="sub-menu">
                <li class="break"><a href="#">Example</a></li>
                <li><a href="#">Example</a></li>
                <li><a href="#">Example</a></li>
            </ul>
            <aside>
                <h1>Widget Title</h1>
                <p>Widget text</p>
            </aside>
        </section>
    </li>
    <li><a href="#">Example</a></li>
    <li><a href="#">Example</a></li>
    <li><a href="#">Example</a></li>
</ul>

La fonction ajoute mega-menu-columns-# au <li> dans le code ci-dessus. Tous les autres changements sont apportés par le Walker. Tout cela fonctionne, mais j'aimerais que cela fonctionne avec moins de configuration; Essentiellement, je veux pouvoir définir la limite de colonne une fois, sans avoir à définir le theme_location dans la fonction. Si je mets un menu pour utiliser le navigateur, je veux que tous mes PHP s'exécutent automatiquement. Si cela n’est pas assez clair, demandez simplement des éclaircissements supplémentaires.

Voici mon code actuel:

// mega menu walker
class megaMenuWalker extends Walker_Nav_Menu {
    private $column_limit = 3; // used to how many columns can be generated (</ul><ul class="sub-menu"> and the widgets)
    private $show_widget = false; // used to determine weather or not to show a widget in the drop down
    private $column_count = 0; // for counting how many columns are in a drop down
    static $li_count = 0; // for counting how many lis are in a drop down, used only to check if the li is first in its list
    function start_el(&$output, $item, $depth = 0, $args = array(), $id = 0) {
        $classes = empty($item->classes) ? array() : (array) $item->classes; // retrive array of classes for each li
        $item_id = $item->ID; // retrieve item id for each li, not really used, keeping it to maintain standard WP menu structure
        if ($depth == 0) {
            self::$li_count = 0; // reset the li counter when we return to the top level in the menu
        }
        if ($depth == 0 && in_array("widget", $classes)) {
            $this->show_widget = true; // show the widget if the top level li has a class of "widget"
            $this->column_count++; // if the widget is shown, increase the column counter by one
        }
        if ($depth == 1 && self::$li_count == 1) {
            $this->column_count++; // if there's anything in a drop down, increase the column counter by one
        }
        if ($depth == 1 && in_array("break", $classes) && self::$li_count != 1 && $this->column_count < $this->column_limit) {
            // if we're in ul ul, and an li has a class of break, and it's not the first in its list, and we haven't met the column limit...
            $output .= "</ul><ul class=\"sub-menu\">"; // add a break in the list
            $this->column_count++; // increase the column count by one
        }
        $class_names = join(" ", apply_filters("nav_menu_css_class", array_filter($classes), $item)); // set up the classes array to be added as classes to each li
        $class_names = " class=\"" . esc_attr($class_names) . "\""; // set up class HTML
        $output .= sprintf(
            "<li id=\"menu-item-%s\"%s><a href=\"%s\">%s</a>", // output li structure
            $item_id, // not really used, keeping it for standard WP menu structure
            $class_names, // add the class names
            $item->url, // add the URL
            $item->title // add the title
        );
        self::$li_count++; // increase the li counter. Not used except if == 1
    }
    function start_lvl(&$output, $depth = 0, $args = array()) {
        if ($depth == 0) {
            $output .= "<section>"; // if a drop down exists, wrap it in <section>. I'm not sure why $depth == 0 and not 1, but it works, so I'm not complaining.
        }
        $output .= "<ul class=\"sub-menu\">"; // output standard WP menu UL for drop downs
    }
    function end_lvl(&$output, $depth = 0, $args = array()) {
        $output .= "</ul>"; // close UL for drop downs
        if ($depth == 0) {
            if ($this->show_widget) {
                // if the parent li has a class of widget...
                ob_start();
                dynamic_sidebar("Navigation Callout"); // show the widget
                $widget = ob_get_contents(); // retrieve the widget's HTML as a variable
                ob_end_clean(); // clear the shown widget
                $output .= $widget; // show the widget
                $this->show_widget = false; // reset the widget variable to false so the next li doesn't get one unless indicated.
                // I know this section is complicated, but it was the only way to correctly display the widget
            }
            $output .= "</section>"; // end the <section> that contains the drop downs.
        }
    }
    function end_el(&$output, $item, $depth = 0, $args = array(), $id = 0) {
        if ($depth == 0 && $this->column_count > 0) {
            $this->column_count = 0; // reset the column counter when a drop down ends.
        }
        $output .= "</li>"; // close the li of each menu item
    }
}

// add mega-menu-columns-# classes
// I didn't write this, but I'll do my best to explain it
add_filter("wp_nav_menu_objects", function($items, $args) {
    if ("first" !== $args->theme_location) {
        return $items; // don't run the function if it's not a specific menu. This should really be a check if the walker is set to a menu, not the menu's location.
    }
    static $post_id = 0; // set up the post id variable
    static $x_key = 0; // not sure what this is
    static $column_count = 1; // set the initial column count to 1
    static $column_limit = 3; // set the column limit to 3. Ideally would pull from the walker.
    static $li_count = 0; // set up the li counter
    $tmp = array(); // not sure waht this is
    foreach($items as $key => $item) {
        if (0 == $item->menu_item_parent) {
            $x_key = $key; // not sure...
            $post_id = $item->ID; // set the post ID to the item's ID
            $column_count = 1; // reset the column count
            $li_count = 0; // reset the li count
            if (in_array("widget", $item->classes, 1)) {
                $column_count++; // if widget is in the li class, add 1 to the column count
            }
        }
        if ($post_id == $item->menu_item_parent) {
            $li_count++; // if an item has children, increase the li count by one
            if (in_array("break", $item->classes, 1) && $li_count > 1 && $column_count < $column_limit) {
                $column_count++; // if break is in the item's classes, and the li count isn't one, and the column count is'nt equal to the column limit, increase the counter by one
            }
            $tmp[$x_key] = $column_count; // not sure what this is.
        }
    }
    foreach($tmp as $key => $value) {
        $items[$key]->classes[] = sprintf("mega-menu-columns-%d", $value); // adding the new class based on column count to the lis
    }
    unset($tmp); // not sure
    return $items; // ending the filter
}, PHP_INT_MAX, 2); // not sure
1
JacobTheDev

Si tout cela est votre propre code, il serait raisonnable de simplement l'implémenter en tant que partie intégrante de walker.

Si vous avez besoin d’ajouter un filtre pendant l’exécution d’un programme tiers, vous pouvez probablement:

Ajoutez-le au crochet wp_nav_menu_args, en vérifiant si walker est défini sur celui-ci:

add_filter( 'wp_nav_menu_args', function( $args ) {

    if ( $args['walker'] instanceof megaMenuWalker ) {

        add_filter( 'wp_nav_menu_objects', 'callback_name_here' );
    }

    return $args;
} );

Supprimez-le au crochet wp_nav_menu une fois que le balisage du menu est complètement généré:

add_filter( 'wp_nav_menu', function( $nav_menu ) {

    remove_filter( 'wp_nav_menu_objects', 'callback_name_here' );

    return $nav_menu;
} );
2
Rarst