web-dev-qa-db-ja.com

歩行者が走ったときにフィルタを走らせる

特定のadd_filterクラスが実行されるたびに特定のWalker_Nav_Menu関数を実行する方法はありますか?この関数は、ウォーカーが移動したときには必ず実行する必要があります。それらの変数、特に$column_limitを共有したいのですが。それらが生成される前にliにクラスを追加するために、関数はwalkerの他のすべてのものの直前に実行されるべきです。

この一連のPHPの目的は、WordPressのメガメニュー有効化機能です。基本的に、このようなマークアップがあるとします。

<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>

breakwidgetはWordPressのメニューエディタでユーザーによって追加されたクラスで、ウォーカーと関数はこれを出力します。

<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>

この関数は、上記のコードのmega-menu-columns-#<li>を追加しています。他のすべての変更は、Walkerによって行われています。これはすべてうまくいきますが、もっと少ない設定でうまくいくことを望みます。基本的に私は一度カラム制限を設定できるようにしたいと思います、そして関数の中でtheme_locationを設定する必要はありません。ウォーカーを使用するようにメニューを設定した場合は、自分のPHPすべてを自動的に実行します。これで十分明確でない場合は、さらに説明を求めてください。

これが私の現在のコードです:

// 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

そのすべてがあなた自身のコードであれば、それをwalkerの一部として実装するのが妥当でしょう。

サードパーティのwalkerの実行中にフィルタを追加する必要がある場合は、おそらく次のようにします。

walkerが次のように設定されているか確認しながら、wp_nav_menu_argsフックに追加します。

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

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

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

    return $args;
} );

メニューマークアップが完全に生成されたら、wp_nav_menuフックでそれを削除します。

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

    remove_filter( 'wp_nav_menu_objects', 'callback_name_here' );

    return $nav_menu;
} );
2
Rarst