Как показать только подменю используя wp_nav_menu()
Я использую этот код для отображения подстраниц пользовательского меню, когда находимся на родительской странице. Но этот код также показывает родительскую страницу на странице без подменю, которую я хотел бы скрыть. По сути, нужно использовать этот код только если мы находимся на странице, у которой есть подстраницы.
class Selective_Walker extends Walker_Nav_Menu
{
function walk( $elements, $max_depth) {
$args = array_slice(func_get_args(), 2);
$output = '';
if ($max_depth < -1) // неверный параметр
return $output;
if (empty($elements)) // нечего обходить
return $output;
$id_field = $this->db_fields['id'];
$parent_field = $this->db_fields['parent'];
// плоское отображение
if ( -1 == $max_depth ) {
$empty_array = array();
foreach ( $elements as $e )
$this->display_element( $e, $empty_array, 1, 0, $args, $output );
return $output;
}
/*
* необходимо отображать в иерархическом порядке
* разделяем элементы на два массива: элементы верхнего уровня и дочерние элементы
* children_elements - это двумерный массив, например
* children_elements[10][] содержит все подэлементы, родителем которых является 10.
*/
$top_level_elements = array();
$children_elements = array();
foreach ( $elements as $e) {
if ( 0 == $e->$parent_field )
$top_level_elements[] = $e;
else
$children_elements[ $e->$parent_field ][] = $e;
}
/*
* когда ни один из элементов не является элементом верхнего уровня
* предполагаем, что первый должен быть корнем подэлементов
*/
if ( empty($top_level_elements) ) {
$first = array_slice( $elements, 0, 1 );
$root = $first[0];
$top_level_elements = array();
$children_elements = array();
foreach ( $elements as $e) {
if ( $root->$parent_field == $e->$parent_field )
$top_level_elements[] = $e;
else
$children_elements[ $e->$parent_field ][] = $e;
}
}
$current_element_markers = array( 'current-menu-item', 'current-menu-parent', 'current-menu-ancestor' ); // добавлено continent7
foreach ( $top_level_elements as $e ){ // изменено continent7
// спускаемся только по текущему дереву
$descend_test = array_intersect( $current_element_markers, $e->classes );
if ( !empty( $descend_test ) )
$this->display_element( $e, $children_elements, 2, 0, $args, $output );
}
/*
* если мы отображаем все уровни, и оставшиеся children_elements не пусты,
* значит у нас есть orphans, которые следует отобразить в любом случае
*/
/* удалено continent7
if ( ( $max_depth == 0 ) && count( $children_elements ) > 0 ) {
$empty_array = array();
foreach ( $children_elements as $orphans )
foreach( $orphans as $op )
$this->display_element( $op, $empty_array, 1, 0, $args, $output );
}
*/
return $output;
}
}
использование в шаблоне:
wp_nav_menu(
array(
'theme_location'=>'primary',
'walker'=>new Selective_Walker()
)
);
Я неоднократно сталкивался с этой проблемой в WordPress. В других CMS, которыми я пользовался, в меню всегда была опция start_depth, что значительно упрощало реализацию вторичного или третичного меню (разделенного меню).
WordPress не включает эту функцию; многие решения в интернете используют wp_list_pages, что полностью игнорирует иерархию менеджера меню.
После проб различных walker'ов и виджетов я наконец решил просто написать собственный плагин с опцией start_depth.
Использовать его можно так:
wp_nav_menu(array('theme_location' => 'primary_navigation', 'start_depth' => 1));
Для всех заинтересованных: плагин доступен бесплатно в репозитории WordPress: https://wordpress.org/plugins/wp-nav-plus/

Я создал бесплатный плагин, который решает эту проблему!
https://wordpress.org/plugins/wp-nav-menu-extended/
Этот плагин расширяет стандартную функцию wp_nav_menu и добавляет дополнительные параметры:
- level : (integer) (обязательный для работы плагина) Уровень навигационного меню для отображения. Если не передан параметр child_of, показывает все элементы этого уровня
- child_of : (string|integer) (опционально) Заголовок или ID пункта меню, прямые потомки которого должны быть показаны
Пример использования:
$defaults = array( 'theme_location' => 'main_menu', 'level' => 2, 'child_of' => 'О нас', );
wp_nav_menu( $defaults );
