Вопрос или проблема
У меня есть пользовательское меню на сайте WordPress + WooCommerce, использующее класс Walker_Nav_Menu. Когда я скрываю записи (товары) на сайте, эти записи и категории все равно включены в пользовательское меню.
Мне нужно знать, как удалить либо конкретные записи товаров из этого меню, например, запись с ID = 6927, либо удалить категорию (и находящиеся в ней товары) из этого меню, например, категория с ID = 41. Категория, которую я хочу скрыть, — “End of range” на этом изображении:
Я пробовал много решений в течение последних 2 дней без успеха:
1)
function wpse31748_exclude_menu_items( $items, $menu, $args ) {
// Перебираем элементы, чтобы искать и удалять
foreach ( $items as $key => $item ) {
if ( $item->object_id == 6927 ) unset( $items[$key] );
}
return $items;
}
add_filter( 'wp_get_nav_menu_items', 'wpse31748_exclude_menu_items', null, 3 );
и различные вариации вышеуказанного.
Я не уверен, что у меня нет правильного подхода, но я подумал, что обновление файла template-parts/modules/module-category-menu.php для исключения категории может сработать, вот содержимое этого файла:
<?php
$orderby = 'date';
$order="desc";
$hide_empty = true ;
$cat_args = array(
'orderby' => $orderby,
'order' => $order,
'hide_empty' => $hide_empty,
);
$product_categories = get_terms( 'product_cat', $cat_args );
if( !empty($product_categories)) :
?>
<div class="row">
<div class="col-12 sec-menu">
<ul class=" nav nav-justified" id="sec-menu">
<?php
foreach ($product_categories as $key => $category):
?>
<li class="nav-item">
<h2>
<a class="nav-link collapsed top-menu" href="#cat<?php echo $category->term_id; ?>" data-toggle="collapse" data-target="#cat<?php echo $category->term_id; ?>">
<?php echo $category->name; ?>
</a>
</h2>
<?php
$args = array(
'posts_per_page' => '-1',
'post_type' => 'product',
'post_status' => 'publish',
'orderby' => 'date',
'order' => 'asc',
'tax_query' => array(
array(
'taxonomy' => 'product_cat',
'terms' => array($category->term_id),
'operator' => 'IN'
),
)
);
$products = new WP_Query($args);
if($products->have_posts()):
?>
<div class="collapse sub-menu" id="cat<?php echo $category->term_id; ?>" aria-expanded="false" data-parent="#sec-menu">
<ul class="flex-column nav">
<?php
while($products->have_posts()):
$products->the_post();
?>
<li class="nav-item">
<a class="nav-link sub-link" href="<?php the_permalink();?>" title="<?php the_title(); ?>">
<span><?php the_title(); ?></span>
</a>
</li>
<?php
endwhile;
wp_reset_query();
?>
</ul>
</div>
<?php
endif;
?>
</li>
<?php
endforeach;
?>
</ul>
</div>
</div>
<?php
endif;
?>
Любая помощь будет очень полезна.
ИЗМЕНЕНИЕ
Вот класс Walker_Nav_Menu из файла functions.php:
class Custom_Foundation_Nav_Menu extends Walker_Nav_Menu
{
private $curItem;
function display_element($element, &$children_elements, $max_depth, $depth = 0, $args, &$output)
{
$element->hasChildren = isset($children_elements[$element->ID]) && !empty($children_elements[$element->ID]);
return parent::display_element($element, $children_elements, $max_depth, $depth, $args, $output);
}
function start_el(&$output, $item, $depth = 0, $args = array(), $id = 0)
{
global $wp_query;
$new_class = array();
$this->curItem = $item;
$indent = ($depth) ? str_repeat("\t", $depth) : '';
$class_names = $value="";
$classes = empty($item->classes) ? array() : (array) $item->classes;
$new_class[] = 'nav-item';
if (in_array('current-menu-item', $classes) || in_array('current-menu-ancestor', $classes)) {
$new_class[] = 'active';
}
if ($item->hasChildren) {
$add_sub_class="nav-link collapsed";
} else {
$add_sub_class="nav-link";
}
if ($depth > 0) {
$add_sub_class .= ' sub-link ';
}
$new_class = implode(' ', $new_class);
// echo $new_class;
$class_names = join(' ', apply_filters('nav_menu_css_class', array_filter($classes), $item));
$class_names=" class="" . $new_class . ' ' . $class_names . '"';
$class_names = trim($class_names);
$output .= $indent . '<li id="menu-item-' . $item->ID . '" ' . $value . $class_names . '>';
$attributes = !empty($item->attr_title) ? ' title="' . esc_attr($item->attr_title) . '" ' : '';
if ($item->hasChildren && !is_page(6927)) {
$attributes .= ' href="#submenu' . $item->ID . '" ';
$attributes .= ' data-toggle="collapse" ';
$attributes .= ' data-target="#submenu' . $item->ID . '" ';
} else {
$attributes .= !empty($item->url) ? ' href="' . esc_attr($item->url) . '" ' : '';
}
$attributes .= !empty($add_sub_class) ? ' class="' . $add_sub_class . '" ' : '';
$item_output = $args->before;
$item_output .= '<a' . $attributes . ' ><span data-hover="' . $args->link_before . apply_filters('the_title', $item->title, $item->ID) . '">';
$item_output .= $args->link_before . apply_filters('the_title', $item->title, $item->ID);
$item_output .= '</span></a>';
$item_output .= $args->after;
$output .= apply_filters('walker_nav_menu_start_el', $item_output, $item, $depth, $args);
}
function start_lvl(&$output, $depth = 0, $args = array())
{
global $wp_query;
$thisItem = $this->curItem;
$indent = str_repeat("\t", $depth);
$output .= "\n$indent<div class="collapse" id='submenu$thisItem->ID' aria-expanded='false'><ul id='submenu-$thisItem->ID' class="flex-column nav sub-nav">\n";
}
}
Я всё еще не уверен, как вы вызываете меню или какие $args вы передаете для меню. Но могу предложить вам несколько способов разобраться.
Первый тест: вернуть пустой массив, если меню становится пустым, фильтр работает,
если нет, тогда ваш фильтр не работает, и нужно найти другой способ
function wpse31748_exclude_menu_items( $items, $menu, $args ) {
return [];
}
add_filter( 'wp_get_nav_menu_items', 'wpse31748_exclude_menu_items', null, 3 );
Предположим, что фильтр работает, тогда, вероятно, логика вашего теста имеет проблему
function wpse31748_exclude_menu_items( $items, $menu, $args ) {
// Перебираем элементы, чтобы искать и удалять
$found_key = null;
foreach ( $items as $key => $item ) {
if ( $item->object_id == 6927 ) {
// unset( $items[$key] ); // удалять из итеративного массива не очень хорошая идея и может привести к ошибкам
$found_key = $key; // обработаем это позже.
}
}
var_dump($found_key); // убедитесь, что что-то нашли
var_dump($items); // чтобы сравнить до и после удаления, если что-то нашли
unset( $items[$found_key] );
var_dump($items);
return $items;
}
add_filter( 'wp_get_nav_menu_items', 'wpse31748_exclude_menu_items', null, 3 );
Я решил эту проблему, отредактировав массив $cat_args, чтобы исключить ID категорий, которые я не хочу показывать ни в каком меню (внизу, например, 34 — это ID категории) — файл в моем случае находился в папке ‘modules’:
<?php
$orderby = 'date';
$order="desc";
$hide_empty = true ;
$cat_args = array(
'orderby' => $orderby,
'order' => $order,
'hide_empty' => $hide_empty,
'exclude' => '34',
);
Категория удалена из меню, но к конкретным записям все еще можно получить доступ и связаться с ними напрямую.
Ответ или решение
Чтобы удалить элемент из пользовательского меню, создаваемого с помощью класса Walker_Nav_Menu
в WordPress, можно использовать фильтры, такие как wp_get_nav_menu_items
. Ниже приведены пошаговые инструкции по удалению как отдельных объектов (например, продуктов с конкретным ID), так и целых категорий.
Удаление конкретного элемента по ID
Для начала, вам нужно использовать фильтр wp_get_nav_menu_items
, чтобы перебрать все элементы меню и удалить необходимые элементы. Вот пример функции, который удаляет элемент с ID 6927:
function wpse31748_exclude_menu_items( $items, $menu, $args ) {
foreach ( $items as $key => $item ) {
if ( $item->object_id == 6927 ) {
unset( $items[$key] ); // Удаляем элемент с ID 6927
}
}
return $items;
}
add_filter( 'wp_get_nav_menu_items', 'wpse31748_exclude_menu_items', null, 3 );
Удаление элементов из меню по категории
Если вы хотите исключить всю категорию, например, категорию с ID 41, вы можете изменить функцию следующим образом:
function wpse31748_exclude_menu_items( $items, $menu, $args ) {
foreach ( $items as $key => $item ) {
// Удаление по ID категории
if ( isset($item->object) && $item->object == 'category' && $item->object_id == 41 ) {
unset( $items[$key] ); // Удаляем элемент с ID категории 41
}
}
return $items;
}
add_filter( 'wp_get_nav_menu_items', 'wpse31748_exclude_menu_items', null, 3 );
Изменение $cat_args для исключения из меню
Если вам нужно управлять отображением категорий или продуктов, нужно изменить аргументы запроса, чтобы исключить определенные категории. Например, в месте, где вы устанавливаете $cat_args
, вы можете добавить аргумент exclude
:
$cat_args = array(
'orderby' => 'date',
'order' => 'desc',
'hide_empty' => true,
'exclude' => array( 34 ) // Замените 34 на ID категории, которую хотите исключить
);
Проверка работоспособности фильтра
Если вы не видите ожидаемых изменений, вам следует убедиться, что фильтр срабатывает. Для этого попробуйте вернуть пустой массив:
function test_filter( $items, $menu, $args ) {
return []; // Это должно привести к пустому меню
}
add_filter( 'wp_get_nav_menu_items', 'test_filter', null, 3 );
Если после этого меню станет пустым, значит ваш фильтр работает корректно. Затем вы можете продолжить отладку логики удаления.
Заключение
С помощью описанных методов вы можете эффективно управлять элементами вашего пользовательского меню на сайте, используя классы WordPress и фильтры. Убедитесь, что вы тестируете изменения на локальной среде перед тем, как внедрять их на живой сайт, чтобы избежать ошибок. Если у вас остались вопросы, не стесняйтесь обращаться за помощью.