WordPress. Меню навигации. Часть 2 из 2

25.03.2019

Теги: CMSWeb-разработкаWordPressМенюНавигация

Использование параметра walker

Для построения меню WordPress использует класс Walker_Nav_Menu, объект этого класса является значением по умолчанию для параметра walker функции wp_nav_menu(). Мы можем создать свой класс и переопределить в нем методы, чтобы формировать html-код меню, как нам нужно. Например, чтобы задать CSS-класс nav-item для элементов <li> и CSS-класс nav-link для элементов <a>:

<?php
class My_Walker_Nav_Menu extends Walker_Nav_Menu {
    /**
     * Starts the element output.
     *
     * @since 3.0.0
     * @since 4.4.0 The {@see 'nav_menu_item_args'} filter was added.
     *
     * @see Walker::start_el()
     *
     * @param string   $output Used to append additional content (passed by reference).
     * @param WP_Post  $item   Menu item data object.
     * @param int      $depth  Depth of menu item. Used for padding.
     * @param stdClass $args   An object of wp_nav_menu() arguments.
     * @param int      $id     Current item ID.
     */
    public function start_el( &$output, $item, $depth = 0, $args = array(), $id = 0 ) {
        if ( isset( $args->item_spacing ) && 'discard' === $args->item_spacing ) {
            $t = '';
            $n = '';
        } else {
            $t = "\t";
            $n = "\n";
        }
        $indent = ( $depth ) ? str_repeat( $t, $depth ) : '';

        $classes = empty( $item->classes ) ? array() : (array) $item->classes;
        $classes[] = 'menu-item-' . $item->ID;
        // добавляем CSS-класс nav-item для элементов <li>
        $classes[] = 'nav-item';
        // добавляем CSS-класс active для текущей страницы
        if ($item->current) {
            $classes[] = 'active';
        }

        /**
         * Filters the arguments for a single nav menu item.
         *
         * @since 4.4.0
         *
         * @param stdClass $args  An object of wp_nav_menu() arguments.
         * @param WP_Post  $item  Menu item data object.
         * @param int      $depth Depth of menu item. Used for padding.
         */
        $args = apply_filters( 'nav_menu_item_args', $args, $item, $depth );

        /**
         * Filters the CSS class(es) applied to a menu item's list item element.
         *
         * @since 3.0.0
         * @since 4.1.0 The `$depth` parameter was added.
         *
         * @param array    $classes The CSS classes that are applied to the menu item's `<li>` element.
         * @param WP_Post  $item    The current menu item.
         * @param stdClass $args    An object of wp_nav_menu() arguments.
         * @param int      $depth   Depth of menu item. Used for padding.
         */
        $class_names = join( ' ', apply_filters( 'nav_menu_css_class', array_filter( $classes ), $item, $args, $depth ) );
        $class_names = $class_names ? ' class="' . esc_attr( $class_names ) . '"' : '';

        /**
         * Filters the ID applied to a menu item's list item element.
         *
         * @since 3.0.1
         * @since 4.1.0 The `$depth` parameter was added.
         *
         * @param string   $menu_id The ID that is applied to the menu item's `<li>` element.
         * @param WP_Post  $item    The current menu item.
         * @param stdClass $args    An object of wp_nav_menu() arguments.
         * @param int      $depth   Depth of menu item. Used for padding.
         */
        $id = apply_filters( 'nav_menu_item_id', 'menu-item-'. $item->ID, $item, $args, $depth );
        $id = $id ? ' id="' . esc_attr( $id ) . '"' : '';

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

        $atts = array();
        $atts['title']  = ! empty( $item->attr_title ) ? $item->attr_title : '';
        $atts['target'] = ! empty( $item->target )     ? $item->target     : '';
        $atts['rel']    = ! empty( $item->xfn )        ? $item->xfn        : '';
        $atts['href']   = ! empty( $item->url )        ? $item->url        : '';

        /**
         * Filters the HTML attributes applied to a menu item's anchor element.
         *
         * @since 3.6.0
         * @since 4.1.0 The `$depth` parameter was added.
         *
         * @param array $atts {
         *     The HTML attributes applied to the menu item's `<a>` element, empty strings are ignored.
         *
         *     @type string $title  Title attribute.
         *     @type string $target Target attribute.
         *     @type string $rel    The rel attribute.
         *     @type string $href   The href attribute.
         * }
         * @param WP_Post  $item  The current menu item.
         * @param stdClass $args  An object of wp_nav_menu() arguments.
         * @param int      $depth Depth of menu item. Used for padding.
         */
        $atts = apply_filters( 'nav_menu_link_attributes', $atts, $item, $args, $depth );
        // добавляем CSS-класс nav-link для ссылок
        $atts['class'] = 'nav-link';

        $attributes = '';
        foreach ( $atts as $attr => $value ) {
            if ( ! empty( $value ) ) {
                $value = ( 'href' === $attr ) ? esc_url( $value ) : esc_attr( $value );
                $attributes .= ' ' . $attr . '="' . $value . '"';
            }
        }

        /** This filter is documented in wp-includes/post-template.php */
        $title = apply_filters( 'the_title', $item->title, $item->ID );

        /**
         * Filters a menu item's title.
         *
         * @since 4.4.0
         *
         * @param string   $title The menu item's title.
         * @param WP_Post  $item  The current menu item.
         * @param stdClass $args  An object of wp_nav_menu() arguments.
         * @param int      $depth Depth of menu item. Used for padding.
         */
        $title = apply_filters( 'nav_menu_item_title', $title, $item, $args, $depth );

        $item_output = $args->before;
        $item_output .= '<a'. $attributes .'>';
        $item_output .= $args->link_before . $title . $args->link_after;
        $item_output .= '</a>';
        $item_output .= $args->after;

        /**
         * Filters a menu item's starting output.
         *
         * The menu item's starting output only includes `$args->before`, the opening `<a>`,
         * the menu item's title, the closing `</a>`, and `$args->after`. Currently, there is
         * no filter for modifying the opening and closing `<li>` for a menu item.
         *
         * @since 3.0.0
         *
         * @param string   $item_output The menu item's starting HTML output.
         * @param WP_Post  $item        Menu item data object.
         * @param int      $depth       Depth of menu item. Used for padding.
         * @param stdClass $args        An object of wp_nav_menu() arguments.
         */
        $output .= apply_filters( 'walker_nav_menu_start_el', $item_output, $item, $depth, $args );
    }
}

Мы переопределили метод start_el() класса Walker_Nav_Menu. Потребовалось лишь несколько строк кода, чтобы добавить CSS-классы nav-item и nav-link:

// добавляем CSS-класс nav-item для элементов <li>
$classes[] = 'nav-item';
// добавляем CSS-класс active для текущей страницы
if ($item->current) {
    $classes[] = 'active';
}
// добавляем CSS-класс nav-link для ссылок
$atts['class'] = 'nav-link';

Если прочие css-классы для элементов <li> не нужны, чуть-чуть изменяем код:

// $classes = empty( $item->classes ) ? array() : (array) $item->classes;
// $classes[] = 'menu-item-' . $item->ID;
// добавляем CSS-класс nav-item для элементов <li>
$classes = ['nav-item'];
// добавляем CSS-класс active для текущей страницы
if ($item->current) {
    $classes[] = 'active';
}

Подключаем файл с классом My_Walker_Nav_Menu в файле functions.php

require_once __DIR__ . '/My_Walker_Nav_Menu.php';

И выводим меню, передавая объект этого класса параметру walker:

<nav class="navbar navbar-expand-lg navbar-dark bg-primary">
    <div  class="container">
        <a class="navbar-brand" href="<?= home_url(); ?>">Главная</a>
        <button class="navbar-toggler"
                type="button"
                data-toggle="collapse"
                data-target="#main-menu"
                aria-controls="main-menu"
                aria-expanded="false"
                aria-label="Toggle navigation">
            <span class="navbar-toggler-icon"></span>
        </button>
        <?php
        wp_nav_menu([
            'theme_location'  => 'header_menu',
            'container'       => 'div',
            'container_class' => 'collapse navbar-collapse',
            'container_id'    => 'main-menu',
            'menu_class'      => 'navbar-nav mr-auto',
            'menu_id'         => 'main-menu-ul',
            'walker'          => new My_Walker_Nav_Menu(),
        ]);
        ?>
    </div>
</nav>

Использование функции wp_get_nav_menu_items()

Функция возвращает массив объектов элементов меню. Если меню не содержит элементов, возвращает пустой массив, либо false, если указанного меню не существует.

wp_get_nav_menu_items($menu, $args = []);
  • $menu (строка). Можно указать ID, slug или название меню, элементы которого нужно будет получить. Не указывайте здесь области темы.
  • $args (массив). Дополнительные параметры вывода.

По умолчанию параметр $args принимает следующие значения:

$args = [
    'nopaging'               => true,
    'post_type'              => 'nav_menu_item',
    'post_status'            => 'publish',
    'order'                  => 'ASC',
    'orderby'                => 'menu_order',
    'output'                 => ARRAY_A,
    'output_key'             => 'menu_order',
    'update_post_term_cache' => false
];

Давайте по традиции добавим CSS-класс nav-item для элементов <li> и CSS-класс nav-link для элементов <a>:

<nav class="navbar navbar-expand-lg navbar-dark bg-primary">
    <div  class="container">
        <a class="navbar-brand" href="<?= home_url(); ?>">Главная</a>
        <button class="navbar-toggler"
                type="button"
                data-toggle="collapse"
                data-target="#main-menu"
                aria-controls="main-menu"
                aria-expanded="false"
                aria-label="Toggle navigation">
            <span class="navbar-toggler-icon"></span>
        </button>
        <?php if ($items = wp_get_nav_menu_items('Главное меню')): ?>
            <div class="collapse navbar-collapse" id="main-menu">
                <ul class="navbar-nav mr-auto">
                    <?php foreach ($items as $item): ?>
                        <?php $current = get_queried_object_id() == $item->object_id; ?>
                        <li class="nav-item<?= $current ? ' active' : ''; ?>">
                            <a class="nav-link" href="<?= $item->url; ?>"><?= $item->title; ?></a>
                        </li>
                    <?php endforeach; ?>
                </ul>
            </div>
        <?php endif; ?>
    </div>
</nav>

Объект элемента меню:

WP_Post Object
(
    [ID] => 1911
    [post_author] => 1
    [post_date] => 2019-03-24 13:47:14
    [post_date_gmt] => 2019-03-24 10:47:14
    [post_content] =>  
    [post_title] => 
    [post_excerpt] => 
    [post_status] => publish
    [comment_status] => closed
    [ping_status] => closed
    [post_password] => 
    [post_name] => 1911
    [to_ping] => 
    [pinged] => 
    [post_modified] => 2019-03-25 11:58:47
    [post_modified_gmt] => 2019-03-25 08:58:47
    [post_content_filtered] => 
    [post_parent] => 0
    [guid] => http://www.server.com/?p=1911
    [menu_order] => 1
    [post_type] => nav_menu_item
    [post_mime_type] => 
    [comment_count] => 0
    [filter] => raw
    [db_id] => 1911
    [menu_item_parent] => 0
    [object_id] => 2
    [object] => page
    [type] => post_type
    [type_label] => Страница
    [url] => http://www.server.com/about-author/
    [title] => Об авторе блога
    [target] => 
    [attr_title] => 
    [description] => 
    [classes] => Array
        (
            [0] => 
        )
    [xfn] => 
)

Дополнительно

Поиск: CMS • Web-разработка • WordPress • Меню • Навигация • Walker_Nav_Menu • wp_get_nav_menu_items • wp_nav_menu • get_queried_object_id

Каталог оборудования
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Производители
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Функциональные группы
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.