Задать вопрос

Как добавить класс на последний ul.sub-menu в Walker_Nav_Menu?

Всем привет.
Возник такой вопрос: как можно с помощью Walker_Nav_Menu добавить класс на последний ul с дочерними элементами в каждой ветке?
Вложенность элементов в меню абсолютно разная. В первой ветке может быть только 1 ul.sub-menu, во второй уже 3 и т.д.
Пример двух веток из 2 и 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}";
	}
}
  • Вопрос задан
  • 320 просмотров
Подписаться 2 Средний 4 комментария
Решения вопроса 1
ElizavetaKrasova
@ElizavetaKrasova Автор вопроса
На другом ресурсе получила решение через Walker, возможно кому-то пригодится. Надеюсь, что автор кода будет не против если я выложу и тут :)

Комментарий к коду: нужно было проходить рекурсивно по всем элементам меню и сохранять максимальную вложенность
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 );
            }
        }
    }
}
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы