Как удалить элемент из пользовательского Walker_Nav_Menu

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

У меня есть пользовательское меню на сайте 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 и фильтры. Убедитесь, что вы тестируете изменения на локальной среде перед тем, как внедрять их на живой сайт, чтобы избежать ошибок. Если у вас остались вопросы, не стесняйтесь обращаться за помощью.

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

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