有没有办法运行特定的add_filter
每当特定Walker_Nav_Menu
课程运行?该函数总是需要在walker运行时运行,我希望它们共享变量,尤其是$column_limit
. 该函数应该在walker中所有其他内容之前运行,以便在生成类之前向li添加类。
这整套PHP的目的是在WordPress中启用mega菜单功能。本质上,如果我有这样的标记:
<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
和
widget
作为用户在WordPress菜单编辑器中添加的类,walker和函数会输出以下内容:
<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>
在上述代码中。所有其他的变化都是由步行者进行的。所有这些都可以,但我希望它能以较少的配置工作;本质上,我希望能够设置一次列限制,而不必设置
theme_location
在函数中。如果我设置了一个使用walker的菜单,我希望所有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