Добавьте класс ‘has_children’ к родительскому li при изменении Walker_Nav_Menu.

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

Я пишу настроенный класс walker для wp_nav_menu и хочу иметь возможность указывать, содержит ли элемент li подменю. Так что я хочу, чтобы мой размет был следующим:

<li class="has_children [другие-словари-wordpress]">
    <a class="parent-link">Некоторый элемент</a>
    <ul class="sub-menu">

Я знаю, как добавлять и удалять классы, но не могу найти ничего, что сказало бы мне, есть ли у текущего элемента дочерние элементы.

Есть идеи?

Спасибо заранее.

start_el() должен получать эту информацию в своем параметре $args, но похоже, что WordPress заполняет это только в том случае, если $args является массивом, в то время как для пользовательских меню навигации это объект. Это было зафиксировано в тикете Trac. Но ничего страшного, вы можете заполнить это сами, если также переопределите метод display_element() в вашем пользовательском walker (поскольку это самое простое место для доступа к массиву дочерних элементов):

class WPSE16818_Walker extends Walker_Nav_Menu
{
    function display_element( $element, &$children_elements, $max_depth, $depth=0, $args, &$output )
    {
        $id_field = $this->db_fields['id'];
        if ( is_object( $args[0] ) ) {
            $args[0]->has_children = ! empty( $children_elements[$element->$id_field] );
        }
        return parent::display_element( $element, $children_elements, $max_depth, $depth, $args, $output );
    }

    function start_el( &$output, $item, $depth, $args ) {
        if ( $args->has_children ) {
            // ...
        }
    }
}

Обновление: На данный момент WordPress 3.7 (октябрь 2013), CSS-классы были добавлены для указания дочерних элементов меню и страниц в темах — нет необходимости использовать пользовательский walker, так как это уже учтено в ядре WordPress.

CSS-классы называются menu-item-has-children и page_item_has_children.


Для полного решения для всех, кто спешит (благодарность предыдущему ответу Яна Фабри), смотрите полную реализацию ниже.

Выводите навигацию в шаблоне вашей темы:

wp_nav_menu( array(
    'theme_location' => 'navigation-primary',
    'container' => false,
    'container_class' => '',
    'container_id' => '',
    'menu_class' => '',
    'menu_id' => '',
    'walker' => new Selective_Walker(),
    'depth' => 2
    )
);

Затем включите следующее в вашем functions.php вашей темы:

class Selective_Walker extends Walker_Nav_Menu {
    function display_element( $element, &$children_elements, $max_depth, $depth=0, $args, &$output ) {
        $id_field = $this->db_fields['id'];

        if ( is_object( $args[0] ) ) {
            $args[0]->has_children = !empty( $children_elements[$element->$id_field] );
        }

        return parent::display_element( $element, $children_elements, $max_depth, $depth, $args, $output );
    }

    function start_el( &$output, $item, $depth, $args ) {
        if ( $args->has_children ) {
            $item->classes[] = 'has_children';
        }

        parent::start_el(&$output, $item, $depth, $args);
    }
}

Полученный HTML-код будет выглядеть следующим образом:

<ul>
    <li><a href="#">Главная</a></li>
    <li class="has_children"><a href="#">О нас</a>
        <ul class="sub-menu">
            <li><a href="#">Наша миссия</a></li>
        </ul>
    </li>
    <li><a href="#">Услуги</a></li>
    <li class="has_children"><a href="#">Продукты</a>
        <ul class="sub-menu">
            <li><a href="#">Lorem Ipsum</a></li>
            <li><a href="#">Lorem Ipsum</a></li>                
        </ul>
    </li>
    <li><a href="#">Связаться с нами</a></li>
</ul>

Для получения дополнительной информации о использовании класса walker в WordPress смотрите Понимание класса Walker.

Наслаждайтесь!

Эта функция именно то, что вам нужно. Она также показывает вам довольно эффективный способ модификации элементов меню навигации. Кроме того, вы можете открыть ее для более продвинутых (например, дочерние темы) функций через фильтр элементов:

/**
 * Классы для навигации под названием "Topnav" на расположении навигации "top".
 * Показывает примеры того, как изменить текущий элемент меню навигации
 * 
 * @param (object) $items
 * @param (object) $menu
 * @param (object) $args
 */
function wpse16818_nav_menu_items( $items, $menu, $args )
{
    # >>>> начните редактирование

    // примеры возможных целей
    $target['name'] = 'Topnav';
    // Целевой элемент меню/элементы
    $target['items'] = array( (int) 6 );

    # <<<< остановите редактирование

    // фильтр для дочерних тем: "config_nav_menu_topnav"
    $target = apply_filters( 'config_nav_menu_'.strtolower( $target['name'] ), $target );

    // Прекратите, если мы не в названном меню
    if ( $menu->name !== $target['name'] ) 
        return;

    foreach ( $items as $item )
    {
        // Проверьте, что содержит $item
        echo '<pre>'; print_r($item); echo '</pre>';

        // Первый реальный пример:
        $item->classes="span-4";

        // Второй реальный пример:
        // Добавьте этот класс, если мы находимся в одном из целевых элементов
        if ( in_array( (int) $item->menu_order, $target['items'] ) )
            $item->classes .= ' last';
    }

    return $items;
}
add_filter( 'wp_get_nav_menu_items', 'wpse16818_nav_menu_items', 10, 3 );

И да, в большинстве случаев – нет необходимости в пользовательском walker.

Если вы хотите сделать выпадающее меню, вы можете сделать это только с помощью CSS.
Создайте пользовательскую навигацию в WP с дочерними элементами, WordPress автоматически назначает класс .sub-menu для дочернего ul. Попробуйте этот CSS

    nav li {position:relative;}
   .sub-menu {display:none; position:absolute; width:300px;}
    nav ul li:hover ul {display:block;}

Вы можете добавить немного jQuery для улучшения, но это должно дать вам работающее выпадающее меню.

Предполагая, что вы автор темы The Magazine Theme 3.0.8 (magazine-basic-child: версия: 1.0), WP 6.6.2.

Ищу решение связанной проблемы.

Пакет выдает сообщение “Устарело: необязательный параметр $depth объявлен перед обязательным параметром $output, он неявно рассматривается как обязательный параметр в /…/…/wp-content/themes/magazine-basic/functions.php на строке 566”.

В файле functions.php имеется 5 вхождений $depth:
строка 351
строка 376
строка 378
строка 566
строка 571
В строке 566 установлен $depth=0
Может ли это быть причиной сообщения? решит ли изменение его просто на $depth проблему без повреждения сайта?
Спасибо!

if ( $this->has_children ) {
    $item_output .= 'has_children';
}

Ответ или решение

Чтобы добавить класс has_children к родительскому элементу <li> в кастомном классе Walker_Nav_Menu, необходимо правильно переопределить методы display_element и start_el. Этот подход позволит вам проверить наличие дочерних элементов и добавить соответствующий класс при рендеринге меню.

Шаг 1: Создание Кастомного Класса Walker

Следующий код демонстрирует, как можно создать кастомный класс Selective_Walker, который будет наследовать от Walker_Nav_Menu и добавлять класс has_children к родительским элементам, если у них есть дочерние элементы.

class Selective_Walker extends Walker_Nav_Menu {
    // Переопределяем метод display_element
    function display_element($element, &$children_elements, $max_depth, $depth = 0, $args, &$output) {
        $id_field = $this->db_fields['id'];

        // Проверяем, является ли $args объектом
        if (is_object($args[0])) {
            // Устанавливаем флаг has_children
            $args[0]->has_children = !empty($children_elements[$element->$id_field]);
        }

        return parent::display_element($element, $children_elements, $max_depth, $depth, $args, $output);
    }

    // Переопределяем метод start_el
    function start_el(&$output, $item, $depth, $args) {
        // Проверяем наличие дочерних элементов и добавляем класс has_children
        if ($args->has_children) {
            $item->classes[] = 'has_children';
        }

        // Генерируем выходной HTML для элемента
        parent::start_el($output, $item, $depth, $args);
    }
}

Шаг 2: Подключение Кастомного Walker к wp_nav_menu

Теперь, чтобы использовать этот кастомный класс вашего меню, необходимо передать его в параметрах функции wp_nav_menu. Если, например, у вас меню с проведением в области navigation-primary, вы можете использовать следующий код:

wp_nav_menu(array(
    'theme_location' => 'navigation-primary',
    'container' => false,
    'menu_class' => '',
    'walker' => new Selective_Walker(),
));

Шаг 3: Ожидаемый Результат

С учетом приведенного кода, HTML-выход будет выглядеть примерно так:

<ul>
    <li class="has_children"><a href="#">О нас</a>
        <ul class="sub-menu">
            <li><a href="#">Наши миссии</a></li>
        </ul>
    </li>
    <li><a href="#">Услуги</a></li>
    <li class="has_children"><a href="#">Продукты</a>
        <ul class="sub-menu">
            <li><a href="#">Товар 1</a></li>
            <li><a href="#">Товар 2</a></li>
        </ul>
    </li>
    <li><a href="#">Контакты</a></li>
</ul>

Каждый элемент <li>, который имеет дочерние пункты, будет содержать класс has_children, что делает его легко стилизуемым с помощью CSS.

Заключение

Создание кастомного класса Walker для меню в WordPress позволяет гибко настраивать разметку ваших навигационных меню. Используя метод display_element для установки состояния has_children, можно значительно улучшить возможности кастомизации и стилизации меню вашего сайта.

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

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