Добавление класса 'has_children' к родительскому li при модификации Walker_Nav_Menu

10 мая 2011 г., 10:46:04
Просмотры: 38.8K
Голосов: 24

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

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

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

Есть идеи?

Заранее спасибо.

0
Все ответы на вопрос 4
3
27

Метод 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 ) {
            // ...
        }
    }
10 мая 2011 г. 11:45:58
Комментарии

Привет, Ян, можешь помочь с этим вопросом? Я пробовал твой код, но у меня не получилось заставить его работать. Можешь дать еще примеры кода?

PrivateUser PrivateUser
4 февр. 2012 г. 00:18:13

Смотри полный пример реализации ниже на этой странице.

rjb rjb
6 мар. 2013 г. 22:41:15

Большое спасибо, @Jan Fabry.. Я застрял со своим кастомным Walker'ом.. В конце концов твой сниппет помог мне.

Harish Kanakarajan Harish Kanakarajan
5 мая 2014 г. 13:12:39
2

Обновление: Начиная с 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, смотрите Understanding the Walker Class.

Удачи!

6 мар. 2013 г. 21:30:09
Комментарии

Фатальная ошибка: Передача по ссылке во время вызова была удалена в D:\www\wordpress\wp-content\themes\wpt_theme\functions.php на строке 44

Tahir Yasin Tahir Yasin
14 июл. 2014 г. 22:43:55

Строка #44: parent::start_el(&$output, $item, $depth, $args);

Tahir Yasin Tahir Yasin
14 июл. 2014 г. 22:44:23
1

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

/**
 * Классы для навигации с названием "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.

10 мая 2011 г. 22:36:49
Комментарии

Спасибо, пока мне нужен walker, но в следующий раз я обязательно рассмотрю этот вариант!

patnz patnz
11 мая 2011 г. 02:50:17
1

Если вам нужно создать выпадающее меню, это можно сделать только с помощью CSS.

Создайте пользовательское меню в WordPress с дочерними элементами, 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 для дополнительных эффектов, но приведённого кода достаточно для рабочего выпадающего меню.

10 мая 2011 г. 11:07:48
Комментарии

Спасибо, это для многоуровневого раскрывающегося древовидного меню, в которое я также вставляю управляющие элементы, но определенно лучше делать как можно больше с помощью css!

patnz patnz
11 мая 2011 г. 02:49:02