Альтернативная вёрстка подменю при использовании функции wp_nav_manu

Как известно, функция WordPress wp_nav_menu() для вложенных меню использует просто вложенный в <li> тег <ul>. Чаще всего это более cheap jerseys чем достаточно, но иногда сложный дизайн меню требует больше элементов для вёрстки. Что и было в моём случае. Я уже Cryptocurrency думал, что придётся выводить меню вручную, без использования wp_nav_menu(), однако, внимательнее перечитав документацию по ссылке выше, увидел очень красивое решение этой проблемы, специально заготовленное WordPress.

Итак, в своей предварительной html-вёрстке дизайна я сделал подменю, которое выглядело так:

<ul>
    <li class='has_sub'>
        <a href='#'>Item</a>
        <div class='sub'>
            <div class='sh'>
            </div>
            <div class='sb'>
                <ul>
                <li><a>Sum-menu_item</a>
                  </ul>
              </div>
        </div>
    </li>
</ul>

Каким образом заставить wp_nav_menu генерировать такую вёрстку? Оказывается, разработчики WordPress предусмотрели такую возможность. Существует класс Walker_Nav_Menu, который как раз предназначен для генерации тегов, обрамляющих различные пункты меню и подменю. В классе есть следующие функции:

start_lvl() Вызывается перед тем, как начать вывод пунктов подменю
end_lvl() Вызывается после того, как все пункты меню выведены
start_el() Вызывается перед выводом очередного элемента меню
end_el() Вызываетяс после вывода очередного элемента меню

Описание этого класса можно посмотреть в wp-includes/nav-menu-template.php. А у функции wp_nav_menu() есть такой параметр как walker, в который мы можем передать экземпляр своего класса, содержащий те же методы, который будет в этом случае использоваться вместо стандартного. Таким образом, для решения моей задачи мне потребовалось добавить простенький класс в файл functions.php своей темы:

class My_theme_menu_walker extends Walker_Nav_Menu {
    function start_lvl(&$output, $depth = 0, $args = array()) {
        $output .= "<div class='sub'><div class='sh'></div><div class='sb'><ul>";
    }

    function end_lvl( &$output, $depth = 0, $args = array()) {
        $output .= "</ul></div></div>";
    }
}

А сам вызов wp_nav_menu выглядит у меня в теме так:

wp_nav_menu(array("theme_location"=>"main_menu",
                  "container"=>false, // Контейнер мне не нужен
                  "menu_class"=>'', // класс для тега ul тоже без надомности
                  "walker"=>new My_theme_menu_walker() // Объект класса, который будет выводить обрамляющие теги
                                                           // Обязательно передать созданный объект, а не имя класса
                  ));

7 комментариев

    • Александр, а в чём проблема? Такое меню выводится стандартными средствами wordpress. Ну плюс если в теме у вас прописана поддержка многоуровнего меню, то оно выведется, если нет — увы. Как прописать в теме — wp_nav_menu. В стандартном варианте она даёт вёрстку только через <ul>, <li> и <a>, поэтому в моём случае пришлось дополнить.

  1. Уважаемый Михаил!
    Благодаря Вашему посту сумел построить необходимое мне меню, но столкнулся с другой проблемой, связанной с обработкой категорий.
    Мне необходимо вывести меню, список второго уровня которого отображается по событию hover, в котором кроме пунктов второго уовня должна быть ещё и информация о постах, которая берётся из это й же родительской категории (по названию идентична пункту меню первого уровня). Фактически моя задача сводится к выводу в walker’e названия родительского пункта меню. Опыта php-программирования у меня нет, потому обращаюсь за консультацией к Вам.
    Изрядно порывшись в поисковиках, нашёл решение, основанное на хуке для функции wp_nav_menu — sorted_menu_items.
    add_filter( ‘wp_nav_menu_objects’, ‘wpse16243_wp_nav_menu_objects’ );
    function wpse16243_wp_nav_menu_objects( $sorted_menu_items )
    {
    foreach ( $sorted_menu_items as $menu_item ) {
    if ( $menu_item->current ) {
    $GLOBALS[‘wpse16243_title’] = $menu_item->title;
    break;
    }
    }
    return $sorted_menu_items;
    }

    Соответственно
    function start_lvl(&$output, $item, $title, $depth = 0, $args = array()) {
    $output .= »
    В разделе «.$GLOBALS[‘wpse16243_title’].»»;
    }
    я вижу название активного пункта первого уровня меню, но это происходит только по клику.
    Не можли бы Вы подсказать, как вывести название пункта меню при наведении курсора на соответствующий пункт 1-го уровня меню.
    Буду очень признателен за Ваш ответ.

    • Alex, на первый взгляд (глубоко копать у меня сейчас немного не хватает времени) в вашем случае wp_nav_menu() вообще не подходит, поскольку она используется для вывода предварительно сделанного в админке меню. Код, который вы привели, не добавляет посты из родительской категории в меню, а сохраняет заголовок активного пункта меню в массиве $_GLOBALS, видимо для использования затем в другой части программы. Я бы поискал хуки, позволяющие формировать меню на лету в навигационное меню, или бы делал код вывода меню сам.

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

Ваш e-mail не будет опубликован.