Вопрос или проблема
Я в настоящее время создал довольно простой инструмент для создания мега-меню. Я добавляю флажок к элементам моего меню в разделе Внешний вид > Меню, за которым следует раскрывающееся меню, включающее шаблонные файлы в рамках темы.
Вот как работает (или не работает) моя текущая функция:
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 является нежелательным из-за возможности конфликтов с темами, есть несколько альтернативных подходов.
Решения:
-
Использование CSS:
Можно временно скрыть подменю с помощью CSS. Это просто в реализации, но неэффективно, если задача заключается в полном удалении элемента с точки зрения структуры кода..sub-menu { display: none !important; }
-
Ограничение глубины при вызове
wp_nav_menu
:
Один из самых простых способов избежать показа подменю без изменения бэкенд-логики — это использовать параметрdepth
.wp_nav_menu(array( 'menu_id' => 'nav', 'theme_location' => 'header-menu', 'depth' => 1 ));
-
Использование фильтра
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
.
Эти методы не только решат вашу текущую задачу, но и позволят сохранить гибкость для возможных будущих изменений темы или логики структуры меню.