Как добавить класс на последний ul.sub-menu в Walker_Nav_Menu?
Всем привет. Возник такой вопрос: как можно с помощью Walker_Nav_Menu добавить класс на последний ul с дочерними элементами в каждой ветке?
Вложенность элементов в меню абсолютно разная. В первой ветке может быть только 1 ul.sub-menu, во второй уже 3 и т.д.
Пример двух веток из 3 и 1 вложенности:
<ul class="menu">
<li class="menu-item"> <!-- Начало 1 ветки -->
<ul class="sub-menu">
<li class="menu-item">
<ul class="sub-menu"> <!-- Последний ul в ветке 1 -->
...
</ul>
</li>
</ul>
</li>
<li class="menu-item"> <!-- Начало 2 ветки-->
<ul class="sub-menu"> <!-- Последний ul в ветке 2 -->
...
</ul>
<li>
</ul>
Прилагаю код самого расширения Walker'а, где есть запрос на поиск дочерних элементов и добавление класса к самому верхнему элементу. Может кто-то сможет подсказать как можно найти максимальную вложенность ветки и я думаю, что через if уже можно будет проверить $depth == $max_depth
class ESD_Walker_Nav extends Walker_Nav_Menu{
/**
* Starts the list before the elements are added.
*
* @since 3.0.0
*
* @see Walker::start_lvl()
*
* @param string $output Used to append additional content (passed by reference).
* @param int $depth Depth of menu item. Used for padding.
* @param stdClass $args An object of wp_nav_menu() arguments.
*/
public function start_lvl( &$output, $depth = 0, $args = null ) {
if ( isset( $args->item_spacing ) && 'discard' === $args->item_spacing ) {
$t = '';
$n = '';
} else {
$t = "\t";
$n = "\n";
}
$indent = str_repeat( $t, $depth );
// Default class.
//$classes = array( 'children' );
if ($args->walker->has_children) { if (0 === $depth) { $classes = array( 'children' ); }else {$classes = array( '' );} }
/**
* Filters the CSS class(es) applied to a menu list element.
*
* @since 4.8.0
*
* @param string[] $classes Array of the CSS classes that are applied to the menu `<ul>` element.
* @param stdClass $args An object of `wp_nav_menu()` arguments.
* @param int $depth Depth of menu item. Used for padding.
*/
$class_names = join( ' ', apply_filters( 'nav_menu_submenu_css_class', $classes, $args, $depth ) );
$class_names = $class_names ? ' class="' . esc_attr( $class_names ) . '"' : '';
$output .= "{$n}{$indent}<ul$class_names>{$n}";
}
}
Возможно скриншот будет более наглядным.
0 - ul-контейнер и начало ветки. Он объявляется на моменте вызова wp_nav_menu()
1,2,3 - уровни вложенности
Сама структура ветки со скриншота:
<ul class="menu"> <!-- Начало Уровня 0 -->
<li class="menu-item">
<a href="#">Заголовок 0</a>
<ul class="sub-menu"> <!-- Начало Уровня 1 -->
<li class="menu-item">
<a href="#">Заголовок 1</a>
<ul class="sub-menu"> <!-- Начало Уровня 2 -->
<li class="menu-item">
<a href="#">Заголовок 2</a>
<ul class="sub-menu"> <!-- Начало Уровня 3 -->
<li class="menu-item">
<a href="#">Заголовок 3</a>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
Ответы (1 шт):
нужно проходить рекурсивно по всем элементам меню и сохранять максимальную вложенность
class example_walker extends Walker_Nav_Menu {
// в этом свойстве сохраняем значение максимального вложения
public $last_sub_menu_depth = 0;
public function start_lvl( &$output, $depth = 0, $args = null ) {
if ( isset( $args->item_spacing ) && 'discard' === $args->item_spacing ) {
$t = '';
$n = '';
} else {
$t = "\t";
$n = "\n";
}
$indent = str_repeat( $t, $depth );
// Default class.
$classes = array( 'sub-menu' );
// сравниваем текущее значение рекурсии с максимальным
if ( $depth === $this->last_sub_menu_depth ) {
array_push( $classes, 'last-sub-menu' );
}
$class_names = join( ' ', apply_filters( 'nav_menu_submenu_css_class', $classes, $args, $depth ) );
$class_names = $class_names ? ' class="' . esc_attr( $class_names ) . '"' : '';
$output .= "{$n}{$indent}<ul$class_names>{$n}";
}
function display_element( $element, &$children_elements, $max_depth, $depth=0, $args, &$output ) {
// обнуляем значение для текущего элемента и запускаем метод на подсчет максимального вложения, только когда элемент имеет дочерние элементы
if ( ! empty( $children_elements[ $element->{$this->db_fields['id']} ] ) ) {
$this->last_sub_menu_depth = 0;
$this->get_last_depth( $element, $children_elements, $max_depth, $depth );
}
return parent::display_element( $element, $children_elements, $max_depth, $depth, $args, $output );
}
// метод для рекурсивного прохода по дочерним пунктам меню
public function get_last_depth( $element, $children_elements, $max_depth, $depth ) {
if ( ! $element ) {
return;
}
$id_field = $this->db_fields['id'];
$id = $element->$id_field;
if ( ( 0 == $max_depth || $max_depth > $depth + 1 ) && isset( $children_elements[ $id ] ) ) {
foreach ( $children_elements[ $id ] as $child ) {
$this->last_sub_menu_depth = $depth;
$this->get_last_depth( $child, $children_elements, $max_depth, $depth + 1 );
}
}
}
}
