Как удалить подменю, используя хуки/фильтры walker, без использования пользовательского walker?

Вопрос или проблема

Я в настоящее время создал довольно простой инструмент для создания мега-меню. Я добавляю флажок к элементам моего меню в разделе Внешний вид > Меню, за которым следует раскрывающееся меню, включающее шаблонные файлы в рамках темы.

Вот как работает (или не работает) моя текущая функция:

function mega_menu_start_el( $output, $item, $depth, $args, $id = 0 ) {

$is_mega = FALSE;
$in_mega = FALSE;

if( $depth > 0 ) {

    $parent_ID = get_post_meta( $item->ID, '_menu_item_menu_item_parent', TRUE );

    if( $parent_ID ) {
        while( $parent_ID ) { //получить корневого родителя
            $current_ID = $parent_ID; //на поздней итерации current_ID будет содержать коренного родителя
            $parent_ID = get_post_meta( $parent_ID, '_menu_item_menu_item_parent', TRUE );
        }
        $in_mega = get_post_meta( $current_ID, 'menu-item-make-mega', TRUE );
    }
}
else {
    $is_mega = get_post_meta( $item->ID, 'menu-item-make-mega', TRUE );
}

if( $in_mega ) {
    return;
}
elseif( !$is_mega ) {
    return $output;
}
else {      
    $template = get_post_meta( $item->ID, 'menu-item-mega-tpl', TRUE );

    if( file_exists( $template ) ) {

        $mega_menu = '%s<div id="mega-menu-%s" class="mega-menu mega-menu-%s">%s</div>';

        ob_start();             
        include( $template );
        $mega_menu_output = ob_get_clean();
        return sprintf( $mega_menu,
                $output,
                $item->ID,
                basename( str_replace( '.', '-', $template ) ),
                $mega_menu_output
            );
    }
}

}

Теперь это как бы работает, потому что если элемент меню не является мега-меню, он просто возвращает исходный сгенерированный вывод; если он находится в мега-меню, оно очищает вывод, а если это мега-меню, оно загружает шаблон и добавляет его рядом с ссылкой, как подменю.

Проблема в том, что, поскольку я не могу найти, где генерируется стандартное подменю, у меня все еще остается разметка пустого подменю (потому что очистка вывода очищает только тег якоря и все, что задано в аргументах “before” и “after”):

<ul class="sub-menu">
    <li id="menu-item-105" class="menu-item menu-item-type-post_type menu-item-object-product menu-item-105"></li>
    <li id="menu-item-106" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-106"></li>
    <li id="menu-item-107" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-107"></li>
</ul>

Так что по сути я хотел бы подключиться к уровню выше этого и проверить, нахожусь ли я в мега-меню, и если это так, то просто уничтожить его.

Я боролся с этим какое-то время, поэтому любые советы будут очень полезны.

Спасибо

Редактировать: Хорошо, кажется, сделать это с помощью фильтров невозможно, потому что нет фильтра для start_lvl (только start_el). Это значит, что мне нужно создать настраиваемый обходчик, чтобы достичь этого, чего я хотел избежать, чтобы обойти возможные конфликты с темами, которые могут уже использовать настраиваемый обходчик для своего меню.

Я смог достичь того, что хотел, с помощью обходчика, который расширяет класс Nav_Menu_Walker по умолчанию. Для тех, кому интересно, я изменил вышеуказанную функцию так, чтобы она добавляла в переменную $output, а не возвращала что-либо.

Я также добавил частную переменную, чтобы удерживать, находимся ли мы в данный момент в мега-меню, поскольку метод walk будет проходить через дерево от корневого родителя и затем до его потомков. Это значит, я могу установить $this->_in_mega одновременно с $is_mega. Затем, когда я нахожусь в start_lvl() и end_lvl(), я вызываю parent::start_lvl() или parent::end_lvl(), если мы не находимся в данный момент в мега-меню.

Я оставлю свой вопрос открытым, так как надеялся на другое решение (и кто-то мог бы его предложить), но на данный момент это для меня достаточно хорошо работает.

лучший и простой способ скрыть подменю – использовать css

.sub-menu {
   display: none !important;
}

Или вы можете использовать ‘depth’=>1

   `wp_nav_menu( array( 'menu_id'=>'nav', 'theme_location'=>'header-menu' , 'depth' => 1) );

или создать функцию для установки ‘depth’=>1 для конкретного меню. разместите этот код в вашем theme function.php

  add_filter( 'wp_nav_menu_args', 'remove_my_header_dropdown', 1, 1 );
  function remove_my_header_dropdown( $args )
   {
    //поиск theme_location, например, top-menu
    if ( isset( $args['theme_location'] ) && 'top-menu' == 
    $args['theme_location'] ) {
    $args['depth'] = 1; //уровни иерархии для включения
    }

    return $args;
}

`
Надеюсь, это вам поможет

.

Ответ или решение

Чтобы удалить подменю с использованием хукеров/фильтров без необходимости в пользовательском классе Walker, необходимо прежде всего понять, как работает система генерации меню в WordPress. В данном случае цель — убрать пустую разметку подменю, которая всё ещё отображается, даже если содержимое анкоров было очищено.

Пошаговое руководство:

Анализ проблемы

Ваш текущий подход к созданию мегаменю в WordPress основывается на работе с мета-полями элементов меню. Основная проблема заключается в том, что даже если элементы подменю скрыты, разметка <ul class="sub-menu"> остаётся, создавая ненужные пустые элементы списка. Если использование кастомного класса Walker является нежелательным из-за возможности конфликтов с темами, есть несколько альтернативных подходов.

Решения:

  1. Использование CSS:
    Можно временно скрыть подменю с помощью CSS. Это просто в реализации, но неэффективно, если задача заключается в полном удалении элемента с точки зрения структуры кода.

    .sub-menu {
      display: none !important;
    }
  2. Ограничение глубины при вызове wp_nav_menu:
    Один из самых простых способов избежать показа подменю без изменения бэкенд-логики — это использовать параметр depth.

    wp_nav_menu(array(
      'menu_id' => 'nav',
      'theme_location' => 'header-menu',
      'depth' => 1
    ));
  3. Использование фильтра wp_nav_menu_args:
    Если необходимо распространить это решение только на конкретные места использования меню, вы можете прописать фильтр, который изменяет параметр depth для заданного локатора темы меню.

    add_filter('wp_nav_menu_args', 'remove_my_header_dropdown', 10, 1);
    function remove_my_header_dropdown($args) {
      if (isset($args['theme_location']) && 'top-menu' == $args['theme_location']) {
         $args['depth'] = 1;
      }
      return $args;
    }

Заключение

Указанные выше решения помогут вам эффективно управлять отображением подменю без необходимости в пользовательском классе Walker. Выбор подхода зависит от ваших конкретных требований и предпочтений. Если проблемой является только отображение пустой структуры, CSS может быть быстрым решением. Для более глубокого контроля отображения используйте фильтры для настройки аргументов wp_nav_menu.

Эти методы не только решат вашу текущую задачу, но и позволят сохранить гибкость для возможных будущих изменений темы или логики структуры меню.

Оцените материал
Добавить комментарий

Капча загружается...