romankondratev
@romankondratev
Специалист MOSSEO

Как показать подпункты только активного элемента меню WordPress?

Доброго времени суток.
Вопрос экспертам WordPress.
Пожалуйста, не пишите решения на основе CSS.

page.php
wp_nav_menu( array(
    'theme_location' => 'left-about',
    'menu'           => 'left',
    'container'      => false,
    'walker'         => new mainMenuWalker
) );

functions.php
class mainMenuWalker extends Walker_Nav_Menu
{
    function start_el( &$output, $item, $depth, $args )
    {
        $indent = ( $depth ) ? str_repeat( "\t", $depth ) : '';

        $classes = empty( $item->classes ) ? array() : (array) $item->classes;

        if (in_array( 'menu-item-has-children', $item->classes )) {
            $classes[] = 'parent';
        }

        /** Удаляем не нужные классы */
        $classes = array_diff( $classes, array( '', 'menu-item', 'menu-item-type-post_type', 'menu-item-object-page', 'page_item', 'current_page_item', 'page-item-' . $item->object_id, 'current-page-ancestor', 'current-page-parent', 'current_page_parent', 'current_page_ancestor' ) );

        $class_names = join( ' ', apply_filters( 'nav_menu_css_class', array_filter( $classes ), $item, $args ) );
        $class_names = $class_names ? ' class="' . esc_attr( $class_names ) . '"' : '';

        $id = apply_filters( 'nav_menu_item_id', 'menu-item-' . $item->ID, $item, $args );
        $id = $id ? ' id="' . esc_attr( $id ) . '"' : '';

        $output .= $indent . '<li' . $id . $class_names . '>';


        /** Назначаем атрибуты a-элементу */
        $attributes  = ! empty( $item->url )
            ? ' href="' . esc_attr( $item->url ) . '"'
            : '';
        $item_output = $args->before;


        /** Проверяем, на какой странице мы находимся */
        $current_url = ( is_ssl() ? 'https://' : 'http://' ) . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
        $item_url    = esc_attr( $item->url );
        if ($item_url != $current_url) {
            $item_output .= '<a' . $attributes . ' title="Перейти на страницу: ' . $item->title . '">' . $item->title . '</a>';
        } else {
            $item_output .= '<span>' . $item->title . '</span>';
        }


        /** Заканчиваем вывод элемента */
        $item_output .= $args->after;
        $output .= apply_filters( 'walker_nav_menu_start_el', $item_output, $item, $depth, $args );
    }
}

Результат (не подходящий):
<ul id="menu-levoe-menyu-o-kompanii" class="menu">
    <li id="menu-item-27" class="current-menu-item menu-item-has-children parent">
        <span>О компании</span>
        <ul class="sub-menu">
            <li id="menu-item-29" class="menu-item-has-children parent">
                <a href="/kontakty/">Контакты</a>
                <ul class="sub-menu">
                    <li id="menu-item-26">
                        <a href="/katalog/">Каталог</a>
                    </li>
                </ul>
            </li>
        </ul>
    </li>
    <li id="menu-item-25" class="menu-item-has-children parent">
        <a href="/klientam/">Клиентам</a>
        <ul class="sub-menu">
            <li id="menu-item-28"><a href="/akcii/">Акции</a></li>
        </ul>
    </li>
</ul>

Необходимо не выводить следущий код, тк активен пункт меню "О компании" (либо любой дочерний), а не "Клиентам" (либо любой дочерний).
<ul class="sub-menu">
    <li id="menu-item-28"><a href="/akcii/">Акции</a></li>
</ul>

Необходимо, чтобы получился код:
<ul id="menu-levoe-menyu-o-kompanii" class="menu">
    <li id="menu-item-27" class="current-menu-item menu-item-has-children parent">
        <span>О компании</span>
        <ul class="sub-menu">
            <li id="menu-item-29" class="menu-item-has-children parent">
                <a href="/kontakty/">Контакты</a>
                <ul class="sub-menu">
                    <li id="menu-item-26">
                        <a href="/katalog/">Каталог</a>
                    </li>
                </ul>
            </li>
        </ul>
    </li>
    <li id="menu-item-25" class="menu-item-has-children parent"><a href="/klientam/">Клиентам</a></li>
</ul>

Результат не подходящий, тк выводится подменю пункта "Клиентам".
17f6148a78724b72834eb479949561ab.png
Необходимо, чтобы выводились подпункты только активной ветки навигации, т.е. при любом активном пункте (О компании, Контакты, Каталог), по следующему алгоритму.
6f92cfc4bd5f4bb9a771690caf851ffb.pnga275c105e49647b4a8a2b77eb1bd7db2.png41126ea976e447b5b3d2766b20c3286d.png0487fbc83610447bb5fa8a8c8adf166b.png56961af455ce4045a0ee431da4e640ae.png

Уверен, найденное решение будет актуально для многих пользователей WordPress.
  • Вопрос задан
  • 3357 просмотров
Пригласить эксперта
Ответы на вопрос 2
@yes_body
в functions.php

function menu_childs_only( $items, $args ) {

if ( empty($args->childs_only) ) // если параметр не был передан
return $items; // обычный вывод меню
$newitems = array(); // подготовим пустые массивы
$ids = array(); // здесь будут id всех активных пунктов
foreach ( $items as $key => $item ) { // пробегаем по каждому элементу, этот
if ( $item->current ) { // если элемент активный

if ($item->menu_item_parent != 0) { // и если есть родительский элемент

$ids[] = $item->menu_item_parent; // пишем его в массив
}

}
}
foreach ( $items as $key => $item ) { // пробежим еще раз

if (in_array($item->menu_item_parent, $ids)) { // если id есть среди активных id
$newitems[] = $item; // пишем весь элемент в массив новых элементов
if ($item->current) { // если элемент активный
$ids[] = $item->ID;
}
}
}
return $newitems; // возвращаем отфильтрованные элементы меню
}

add_filter( 'wp_nav_menu_objects', 'menu_childs_only', 10, 2 ); // хук

в шаблоне

wp_nav_menu( array(
'childs_only' => 1, // тот самый параметр, который выводит отфильтрованное меню

) );
Ответ написан
Комментировать
rOOse
@rOOse
Frontend developer
хмм, а стоит ли? не проще в css решить эту проблему?
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы