wp_nav_menu()
Выводит меню, созданное в админ-панели: "внешний вид > меню" (Appearance > Menus).
Какое именно меню выводить (их может быть несколько), указывается в параметре theme_location или menu.
Чтобы тема поддерживала меню, нужно включить эту возможность с помощью:
add_theme_support( 'menus' )
Или можно зарегистрировать место (слот) для меню, с помощью register_nav_menu(), тогда поддержка меню темой включиться автоматически.
Важно: нюанс с отсутствующим меню
При использовании функции, если указанный theme_location не существует или в него не назначено ни одно меню, WordPress передаст управление функции wp_page_menu(), которая выводит список всех страниц, а не меню. При этом параметры container, container_class и прочие начинают применяться к <ul>, а не к контейнеру, это может нарушить ожидаемую HTML-разметку.
Пример:
$menu = wp_nav_menu( [ 'theme_location' => 'my_location', 'container' => 'nav', 'container_class' => 'nav header__nav', 'menu_class' => 'header__list', 'menu_id' => 'my-id', 'echo' => false, ] ); echo htmlspecialchars( $menu );
Результат, когда нет "my_location" или в нем нет ни одного меню:
<nav id="my-id" class="header__list"> <ul> <li class="page_item page-item-14813"><a href="УРЛ">Заголовок страницы</a></li> </ul> </nav>
Результат, когда в "my_location" есть меню:
<nav class="nav header__nav"> <ul id="my-id" class="header__list"> <li id="menu-item-6411" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-6411"> <a href="УРЛ">Заголовок элемента меню</a> </li> </ul> </nav>
🛑 Это поведение ломает разметку, если вы ожидаете, что menu_class будет применён к <ul>, а не к <nav>.
✅ Чтобы избежать таких ситуаций:
- Убедитесь, что нужный
theme_locationзарегистрирован через register_nav_menus(). - Назначьте хоть одно меню для указаного в пармпетре
theme_locationслота в админке. - Либо явно указывайте
menuпо названию, если хотите избежать fallback на wp_page_menu().
🛑 Всегда проверяйте, что меню существует, особенно при верстке и стилизации.
Подробнее читайте в комментариях.
Дополнительно про включение и добавление меню читайте в отдельной статье.
Фильтры для изменения элемента меню
-
wp_nav_menu_args - фильтрует список параметров wp_nav_menu().
-
nav_menu_item_args - фильтрует параметры отдельного элемента меню.
-
nav_menu_css_class - фильтрует css классы (class атрибут) отдельного <li> элемента меню.
-
nav_menu_item_id - фильтрует ID атрибут отдельного <li> элемента меню.
-
nav_menu_link_attributes - фильтрует атрибуты <a> элемента меню: title, target, rel, href.
-
nav_menu_item_title - фильтрует текст анкора ссылки элемента меню.
-
walker_nav_menu_start_el - фильтрует HTML код начала отдельного элемента меню. Начало означает незакрытый li тег: <li><a></a>
- nav_menu_submenu_css_class - позволяет изменить CSS классы, добавленные к вложенным ul элементам (спискам меню). По умолчанию добавляется класс sub-menu.
Возвращает
null|Строку|false. Функция выводит на экран html код меню.
Шаблон использования
wp_nav_menu( [ 'theme_location' => '', 'menu' => '', 'container' => 'div', 'container_class' => '', 'container_id' => '', 'menu_class' => 'menu', 'menu_id' => '', 'echo' => true, 'fallback_cb' => 'wp_page_menu', 'before' => '', 'after' => '', 'link_before' => '', 'link_after' => '', 'items_wrap' => '<ul id="%1$s" class="%2$s">%3$s</ul>', 'depth' => 0, 'walker' => '', ] );
Использование
<?php wp_nav_menu( $args ); ?>
Аргументы параметра $args
- theme_location(строка)
Идентификатор расположение меню в шаблоне. Идентификатор, указывается при регистрации меню функцией register_nav_menu().
Если не указан параметр
theme_location, то меню для вывода будет подбираться в следующем порядке:- Меню, подходящее по ID, слагу или описанию переданному в параметре menu и если в этом меню есть хоть одна ссылка (один элемент).
- Иначе, первое меню из не пустого слота для меню.
- Или, выведет значение возвращаемое функцией указанной в параметре fallback_cb. По умолчанию там указано функция wp_page_menu().
- Если ничего не подошло, функция ничего и не выведет.
По умолчанию: ''
- Меню которое нужно вывести. Можно указать:
id,slugилиназвание меню.
По умолчанию: '' - container(строка/false)
- Чем оборачивать ul тег. Может быть:
divилиnav.
Если не нужно оборачивать ничем, то пишем false:container => false.
По умолчанию: div - container_class(строка)
- Значение атрибута
class=""у контейнера меню.
По умолчанию: menu-{menu slug}-container - container_id(строка)
- Значение атрибута
id=""у контейнера меню.
По умолчанию: '' - container_aria_label(строка) (WP 5.5)
- Значение атрибута
aria-label=""у контейнера меню.
По умолчанию: '' - Значение атрибута class у тега ul.
По умолчанию: menu - Значение атрибута id у тега ul.
По умолчанию: menu-{menu slug} - items_wrap(строка)
- Шаблон обёртки для элементов меню. Шаблон обязательно должен иметь плейсхолдер %3$s, остальное опционально.
По умолчанию: '<ul id="%1$s" class="%2$s">%3$s</ul>' - fallback_cb(строка)
- Функция для обработки вывода, если никакое меню не найдено.
Передает все аргументы $args указанной тут функции.
Установите пустую строку''или'__return_empty_string', чтобы ничего не выводилось, если меню нет.
По умолчанию: wp_page_menu - before(строка)
- Текст перед тегом
<a>в меню.
По умолчанию: '' - after(строка)
- Текст после каждого тега
</a>в меню.
По умолчанию: '' - link_before(строка)
- Текст перед анкором каждой ссылки в меню.
По умолчанию: '' - link_after(строка)
- Текст после анкора каждой ссылки в меню.
По умолчанию: '' - depth(число)
- До какого уровня вложенности нужно показывать ссылки (элементы меню). 0 - все уровни.
По умолчанию: 0 - item_spacing(строка) (WP 4.7)
- Оставлять или нет переносы строк в HTML коде меню. Может быть:
preserveилиdiscard
По умолчанию: 'preserve' - echo(true/false)
- Выводить на экран или возвратить для обработки.
По умолчанию: true - walker(объект)
Класса, который будет использоваться для построения меню. Нужно указывать экземпляр объекта, а не строку, например
new My_Menu_Walker().Как использовать смотрите в этом примере.
По умолчанию: Walker_Nav_Menu()
Примеры
#1 CSS класс для родительских элементов меню
Если нужно добавить CSS класс для элементов меню, у которых есть дочерние (сложенные списки ссылок), то делаем так:
add_filter( 'wp_nav_menu_objects', 'css_for_nav_parrent' );
function css_for_nav_parrent( $items ){
foreach( $items as $item ){
if( __nav_hasSub( $item->ID, $items ) ){
// все элементы поля "classes" меню, будут совмещены и выведены в атрибут class HTML тега <li>
$item->classes[] = 'menu-parent-item';
}
}
return $items;
}
function __nav_hasSub( $item_id, $items ){
foreach( $items as $item ){
if( $item->menu_item_parent && $item->menu_item_parent == $item_id )
return true;
}
return false;
} #2 Первое не пустое меню, с настройками вывода по умолчанию:
<?php wp_nav_menu(); ?>
#3 Удалим ul обертку
Этот пример удалит обертку тега ul у меню:
<?php wp_nav_menu( [ 'items_wrap' => '%3$s' ] ); ?>
#4 Использование своей функции для построения меню
Пример расширения класса Walker_Nav_Menu, для создания своего произвольного HTML кода который выводится функцией wp_nav_menu(). Наш HTML код будет написан специально для нашей темы. Ниже код своего произвольного класса, который строит меню. Он добавляет глубину меню и четные/нечетные CSS классы к элементам меню (обоим ul и li): Чтобы не изобретать велосипед, копируем код класса Walker_Nav_Menu{} и просто изменяем его как нам нужно. Теперь, когда класс готов, используем его в функции wp_nav_menu(). Для этого нужно указать экземпляр нашего класса в параметре Теперь там, где нужно выводить меню используем нашу функцию:/**
* Пользовательский класс walker для навигационных меню.
*/
class My_Walker_Nav_Menu extends Walker_Nav_Menu {
/**
* Добавляет классы к подменю (ul).
*
* @return void
*/
function start_lvl( &$output, $depth = 0, $args = null ) {
// классы, зависящие от уровня вложенности
$indent = ( $depth > 0 ? str_repeat( "\t", $depth ) : '' ); // отступ в коде
$display_depth = ( $depth + 1); // потому что первый уровень подменю считается как 0
$classes = [
'sub-menu',
( $display_depth % 2 ? 'menu-odd' : 'menu-even' ),
( $display_depth >= 2 ? 'sub-sub-menu' : '' ),
'menu-depth-' . $display_depth,
];
$class_names = implode( ' ', $classes );
$output .= "\n" . $indent . '<ul class="' . $class_names . '">' . "\n";
}
//
/**
* Добавляет основные классы для li и ссылок.
*
* @return void
*/
function start_el( &$output, $data_object, $depth = 0, $args = null, $current_object_id = 0 ) {
$item = $data_object; // используем более описательное имя для использования внутри этого метода.
$indent = ( $depth > 0 ? str_repeat( "\t", $depth ) : '' ); // отступ в коде
// классы, зависящие от уровня вложенности
$depth_classes = [
( $depth == 0 ? 'main-menu-item' : 'sub-menu-item' ),
( $depth >= 2 ? 'sub-sub-menu-item' : '' ),
( $depth % 2 ? 'menu-item-odd' : 'menu-item-even' ),
'menu-item-depth-' . $depth,
];
$depth_class_names = esc_attr( implode( ' ', $depth_classes ) );
// переданные классы
$classes = empty( $item->classes ) ? [] : (array) $item->classes;
$class_names = esc_attr( implode( ' ', apply_filters( 'nav_menu_css_class', array_filter( $classes ), $item ) ) );
// создание HTML
$output .= $indent . '<li id="nav-menu-item-'. $item->ID . '" class="' . $depth_class_names . ' ' . $class_names . '">';
// атрибуты ссылки
$attributes = ! empty( $item->attr_title ) ? ' title="' . esc_attr( $item->attr_title ) .'"' : '';
$attributes .= ! empty( $item->target ) ? ' target="' . esc_attr( $item->target ) .'"' : '';
$attributes .= ! empty( $item->xfn ) ? ' rel="' . esc_attr( $item->xfn ) .'"' : '';
$attributes .= ! empty( $item->url ) ? ' href="' . esc_attr( $item->url ) .'"' : '';
$attributes .= ' class="menu-link ' . ( $depth > 0 ? 'sub-menu-link' : 'main-menu-link' ) . '"';
$item_output = strtr( '{BEFORE}<a{ATTRIBUTES}>{LINK_BEFORE}{TITLE}{LINK_AFTER}</a>{AFTER}', [
'{BEFORE}' => $args->before,
'{ATTRIBUTES}' => $attributes,
'{LINK_BEFORE}' => $args->link_before,
'{TITLE}' => apply_filters( 'the_title', $item->title, $item->ID ),
'{LINK_AFTER}' => $args->link_after,
'{AFTER}' => $args->after,
] );
$output .= apply_filters( 'walker_nav_menu_start_el', $item_output, $item, $depth, $args );
}
}
walker.function my_nav_menu( $args ) {
$args = array_merge( [
'container' => 'div',
'container_id' => 'top-navigation-primary',
'container_class' => 'top-navigation',
'menu_class' => 'menu main-menu menu-depth-0 menu-even',
'echo' => false,
'items_wrap' => '<ul id="%1$s" class="%2$s">%3$s</ul>',
'depth' => 10,
'walker' => new My_Walker_Nav_Menu()
], $args );
echo wp_nav_menu( $args );
}
my_nav_menu( [ 'theme_location' => 'navigation_menu_primary' ] );
#5 Добавим CSS классы ко всем меню
Используя хук, мы можем добавить свои CSS классы, если соблюдается нужное нам условие.
Добавим CSS класс, если это пост и название элемента меню равно "blog":
add_filter( 'nav_menu_css_class', 'special_nav_class', 10, 2 );
function special_nav_class($classes, $item){
if( is_single() && $item->title == "Blog" ){
$classes[] = "special-class";
}
return $classes;
} #6 Выведем меню с названием "Навигация по сайту":
<?php wp_nav_menu( [ 'menu' => 'Навигация по сайту' ] ); ?>
#7 Меню из страниц. Пример из темы: Twenty Ten.
Если параметры вывода не указаны и меню не найдено, то будет построено меню из страниц, функцией wp_page_menu().
В этом примере будет выведено меню, прикрепленное к области меню 'primary':
<div id="access" role="navigation"> <?php wp_nav_menu( [ 'container_class' => 'menu-header', 'theme_location' => 'primary' ] ); ?> </div>
#8 Использование фильтра wp_nav_menu_args для установки параметров по умолчанию для всех меню
Чтобы удалить контейнер у всех навигационных меню сразу, используем следующих код в файле темы functions.php. Используем хук wp_nav_menu_args:
add_filter( 'wp_nav_menu_args', 'my_wp_nav_menu_args' );
function my_wp_nav_menu_args( $args = '' ){
$args['container'] = false;
return $args;
} #9 Удалим контейнер, только у одного, выводимого меню
<?php wp_nav_menu( [ 'container' => '' ] ); ?>
#10 Добавим слово в начало меню
Этот пример показывает, как добавить слово в начало списка меню, в виде такого же элемента меню, только не ссылки.
Добавим в начало меню, слово "Список", также укажем атрибут id созданному тегу li:
<?php wp_nav_menu( [ 'theme_location' => 'primary', 'items_wrap' => '<ul><li id="item-id">Список: </li>%3$s</ul>' ] ); ?>
#11 Отдельные меню для авторизованных пользователей
Если нужно показывать разные меню, авторизованным и неавторизованным пользователям, то используем условный тег is_user_logged_in():
if ( is_user_logged_in() ) {
wp_nav_menu( array( 'theme_location' => 'logged-in-menu' ) );
}
else {
wp_nav_menu( array( 'theme_location' => 'logged-out-menu' ) );
}
В админке нужно создать 2 разных меню и прикрепить их к соответствующим локациям (областям).
#12 Добавление класса к отдельным элементам меню
Появился специальных хук для этого: nav_menu_css_class. Классы можно добавлять или удалять через него. Для примера давайте добавим класс my__class ко всем элементам меню:
add_filter( 'nav_menu_css_class', 'add_my_class_to_nav_menu', 10, 2 );
function add_my_class_to_nav_menu( $classes, $item ){
/* $classes содержит
Array(
[1] => menu-item
[2] => menu-item-type-post_type
[3] => menu-item-object-page
[4] => menu-item-284
)
*/
$classes[] = 'my__class';
return $classes;
} #13 Выводить меню, только если оно существует
По умолчанию, если меню нет, то вместо него будут выведены страницы сайта. Но если нужно выводить меню, только в том случае когда оно создано в админ-панели, укажите параметр fallback_cb как '__return_empty_string':
wp_nav_menu( array( 'theme_location' => 'primary-menu', 'fallback_cb' => '__return_empty_string' ) );
#14 Вывод только подпункта меню
Допустим, есть первый уровень и у каждого из элементов первого уровня, есть свое подменю. Нам нужно вывести такое подменю у пункта с классом menu-item-135:
## Вырезаем все LI нужного submenu и выводим их в своем UL блоке
$menu = wp_nav_menu( array(
'theme_location' => 'header_menu',
'container' => '',
'echo' => 0,
) );
$regex_part = preg_quote('menu-item-135');
// выведем подменю пункта "gotovye-resheniya"
preg_match('~'. $regex_part .'.*sub-menu[^>]+>(.*?)</ul>~s', $menu, $mm );
if( ! empty( $mm[1] ) )
echo "<ul>$mm[1]</ul>";
Не очень оптимальный, но рабочий пример. Иногда может пригодится, для малопосещаемых сайтов где нужно быстро получить результат.
#15 Кэширование меню (wp_nav_menu) в кэш объектов
Код ниже показывает как можно кэшировать весь код меню в объектный кэш. Кэш будет сбрасываться при обновлении меню. Кэширование будет работать для всех меню.<?php
Pj_Cached_Nav_Menus::load();
/**
* Caches calls to wp_nav_menu().
*/
class Pj_Cached_Nav_Menus {
public static $ttl = 3600; // use 0 to cache forever (until nav menu update)
public static $cache_menus = array();
public static function load() {
add_filter( 'pre_wp_nav_menu', array( __CLASS__, 'pre_wp_nav_menu' ), 10, 2 );
add_filter( 'wp_nav_menu', array( __CLASS__, 'maybe_cache_nav_menu' ), 10, 2 );
add_action( 'wp_update_nav_menu', array( __CLASS__, 'clear_caches' ) );
}
private static function _cache_key( $args ) {
$_args = (array) $args;
unset( $_args['menu'] );
return 'pj-cached-nav-menu:' . md5( json_encode( $_args ) );
}
private static function _timestamp() {
static $timestamp;
if ( ! isset( $timestamp ) )
$timestamp = get_option( 'pj-cached-nav-menus-timestamp', 0 );
return $timestamp;
}
public static function pre_wp_nav_menu( $output, $args ) {
if ( ! empty( $args->menu ) )
return $output;
$cache_key = self::_cache_key( $args );
self::$cache_menus[] = $cache_key;
$cache = get_transient( $cache_key );
if ( is_array( $cache ) && $cache['timestamp'] >= self::_timestamp() ) {
$output = $cache['html'] . '<!-- pj-cached-nav-menu -->';
}
return $output;
}
public static function maybe_cache_nav_menu( $html, $args ) {
$cache_key = self::_cache_key( $args );
if ( ! in_array( $cache_key, self::$cache_menus ) )
return $html;
$cache = array(
'html' => $html,
'timestamp' => time(),
);
set_transient( $cache_key, $cache, self::$ttl );
return $html;
}
public static function clear_caches() {
update_option( 'pj-cached-nav-menus-timestamp', time() );
}
}
Оригинальный код: https://github.com/pressjitsu/cached-nav-menus
Композер пакет: https://github.com/inpsyde/menu-cache Статья по нему: https://www.kobzarev.com/wordpress/cache-nav-menus/
Другой аналогичный пример: https://www.bjornjohansen.com/wordpress-menu-cache
CSS классы элементов меню
Добавляемые классы смотрите в функции _wp_menu_item_classes_by_context().
Следующие CSS классы добавляются к элементам меню (разделение по условиям на каких страницах находится пользователь):
Для всех элементов на всех страницах
-
.menu-item— ко всем элементам меню; -
.menu-item-object-{object}— ко всем элементам. {object} замениться на название типа записи или таксономии:.menu-item-object-category— для категорий..menu-item-object-tag— для меток..menu-item-object-page— для постоянных страниц..menu-item-object-custom‒ для произвольного элемента меню.
.menu-item-type-{type}— ко всем элементам меню. {type} замениться на тип ссылки (запись или таксономия):.menu-item-type-post_type— постоянная страница, произвольный тип записи..menu-item-type-taxonomy— категория, метка или произвольная таксономия..menu-item-type-custom‒ для произвольного элемента меню.
На текущей странице
.current-menu-item— если ссылка в меню совпадает с адресом просматриваемой страницы. Текущая страница.
Для родительских элементов у просматриваемой страницы
.current-menu-parent.current-{taxonomy}-ancestor.current-{post_type}-ancestor
Для элементов как-то связанных с просматриваемой страницей
.current-menu-ancestor.current-{object}-ancestor.current-{type}-ancestor
Для элементов связанных с главной страницей сайта
.menu-item-home
Совместимость с функцией wp_page_menu()
.page_item.page-item-{$menu_item->object_id}.current_page_item.current_page_parent.current_page_ancestor
Остальное
.menu-item-has-children‒ Если у элемента есть дочерние элементы.ul.sub-menu‒ У дочернего элемента ul..menu-item-privacy-policy‒ пункт меню "Страница политики конфиденциальности"..menu-item-home‒ пункт меню "Главная страница".
Объект $item
Параметры $item
В примерах часто используется элемент меню $item. Ниже показаны почти все параметры этого элемента:
| Поле | Описание |
|---|---|
| ID | ID элемента меню |
| menu_item_parent | ID родительского элемента меню |
| classes | массив классов элемента меню |
| post_date | дата добавления |
| post_modified | дата последнего изменения |
| post_author | ID пользователя, добавившего этот элемент меню |
| title | заголовок элемента меню |
| url | ссылка элемента меню |
| attr_title | title атрибут ссылки |
| xfn | rel атрибут ссылки |
| target | target атрибут ссылки |
| current | равен 1, если это текущий элемент |
| current_item_ancestor | 1, если текущий элемент - это вложенный элемент |
| current_item_parent | 1 если текущим элемент - это родительский элемент |
| menu_order | порядковый номер в меню |
| object_id | ID объекта меню. Записи, термина и т.д. |
| type | тип объекта меню (такса, запись) |
| object | название таксы, типа записи: page, category, post_tag ... |
| type_label | локализованное название типа: Рубрика, Страница |
| post_parent | ID родительской записи |
| post_title | заголовок записи |
| post_name | ярлык записи |
Пример объекта $item
WP_Post Object ( [ID] => 10 [post_author] => 5 [post_date] => 2019-02-11 13:33:39 [post_date_gmt] => 2019-02-11 13:33:39 [post_content] => [post_title] => New [post_excerpt] => [post_status] => publish [comment_status] => closed [ping_status] => closed [post_password] => [post_name] => new [to_ping] => [pinged] => [post_modified] => 2019-02-11 23:10:19 [post_modified_gmt] => 2019-02-11 23:10:19 [post_content_filtered] => [post_parent] => 0 [guid] => http://dh5.com/?p=10 [menu_order] => 1 [post_type] => nav_menu_item [post_mime_type] => [comment_count] => 0 [filter] => raw [db_id] => 10 [menu_item_parent] => 0 [object_id] => 10 [object] => custom [type] => custom [type_label] => Custom Link [title] => New [url] => # [target] => [attr_title] => [description] => [classes] => Array [0] => extra-sub-menu [1] => menu-item [2] => menu-item-type-custom [3] => menu-item-object-custom [xfn] => [current] => [current_item_ancestor] => [current_item_parent] => )
Пример использования параметра walker
В walker можно указать объект, который будет строить меню. В этом объекте можно описать HTML код получаемого меню.
Если нужно создать меню для нестандартной верстки, то иногда проще переделать этот объект, чем переделывать верстку.
В качестве примера walker объекта, возьмем класс Walker_Nav_Menu{}, который используется по умолчанию. В нём нас интересует только один метод start_el(). Именно он отвечает за HTML каждого элемента. Как правило, достаточно изменить только его. Для этого нужно создать свой класс, который будет расширять класс Walker_Nav_Menu и указать его в параметре walker при вызове меню.
Смотрим на примере. Взят код метода start_el() без изменений. Используем в качестве шаблона:
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 Passed by reference. Used to append additional content.
* @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;
$args = apply_filters( 'nav_menu_item_args', $args, $item, $depth );
$class_names = join( ' ', apply_filters( 'nav_menu_css_class', array_filter( $classes ), $item, $args, $depth ) );
$class_names = $class_names ? ' class="' . esc_attr( $class_names ) . '"' : '';
$id = apply_filters( 'nav_menu_item_id', 'menu-item-'. $item->ID, $item, $args, $depth );
$id = $id ? ' id="' . esc_attr( $id ) . '"' : '';
// создаем HTML код элемента меню
$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 : '';
$atts = apply_filters( 'nav_menu_link_attributes', $atts, $item, $args, $depth );
$attributes = '';
foreach ( $atts as $attr => $value ) {
if ( ! empty( $value ) ) {
$value = ( 'href' === $attr ) ? esc_url( $value ) : esc_attr( $value );
$attributes .= ' ' . $attr . '="' . $value . '"';
}
}
$title = apply_filters( 'the_title', $item->title, $item->ID );
$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;
$output .= apply_filters( 'walker_nav_menu_start_el', $item_output, $item, $depth, $args );
}
}
Теперь, при вызове меню указываем свой walker:
wp_nav_menu( array( 'theme_location' => 'head_menu', 'walker' => new My_Walker_Nav_Menu(), ) );
Готово, теперь каждый элемент меню будет строиться по нужной нам HTML схеме.
БЭМ меню с помощью фильтров
Будет формироваться вёрстка по методологии БЭМ:
<ul class="menu menu--main menu--horizontal"> <li class="menu-node menu-node--main_lvl_1 menu-node--active"> <a href="#" class="menu-link menu-link--active">Пункт 1</a> <ul class="menu menu--dropdown menu--vertical"> <li class="menu-node menu-node--main_lvl_2"> <a href="#" class="menu-link">Подпункт 1.1</a> </li> <li class="menu-node menu-node--main_lvl_2"> <a href="#" class="menu-link">Подпункт 1.2</a> </li> </ul> </li> <li class="menu-node menu-node--main_lvl_1"> <a href="#" class="menu-link">Пункт 2</a> </li> <li class="menu-node menu-node--main_lvl_1"> <a href="#" class="menu-link">Пункт 3</a> </li> </ul>
Файл index.php или другой для вывода меню
<?php wp_nav_menu( [ 'theme_location' => 'header-menu', ] );
Файл functions.php
<?php
add_action( 'after_setup_theme', function () {
register_nav_menus( [
'header-menu' => 'Верхняя область',
'footer-menu' => 'Нижняя область',
] );
} );
// Изменяет основные параметры меню
add_filter( 'wp_nav_menu_args', 'filter_wp_menu_args' );
// Изменяем атрибут id у тега li
add_filter( 'nav_menu_item_id', 'filter_menu_item_css_id', 10, 4 );
// Изменяем атрибут class у тега li
add_filter( 'nav_menu_css_class', 'filter_nav_menu_css_classes', 10, 4 );
// Изменяет класс у вложенного ul
add_filter( 'nav_menu_submenu_css_class', 'filter_nav_menu_submenu_css_class', 10, 3 );
// Добавляем классы ссылкам
add_filter( 'nav_menu_link_attributes', 'filter_nav_menu_link_attributes', 10, 4 );
function filter_wp_menu_args( $args ) {
if ( $args['theme_location'] === 'header-menu' ) {
$args['container'] = false;
$args['items_wrap'] = '<ul class="%2$s">%3$s</ul>';
$args['menu_class'] = 'menu menu--main menu-horizontal';
}
return $args;
}
function filter_menu_item_css_id( $menu_id, $item, $args, $depth ) {
return $args->theme_location === 'header-menu' ? '' : $menu_id;
}
function filter_nav_menu_css_classes( $classes, $item, $args, $depth ) {
if ( $args->theme_location === 'header-menu' ) {
$classes = [
'menu-node',
'menu-node--main_lvl_' . ( $depth + 1 )
];
if ( $item->current ) {
$classes[] = 'menu-node--active';
}
}
return $classes;
}
function filter_nav_menu_submenu_css_class( $classes, $args, $depth ) {
if ( $args->theme_location === 'header-menu' ) {
$classes = [
'menu',
'menu--dropdown',
'menu--vertical'
];
}
return $classes;
}
function filter_nav_menu_link_attributes( $atts, $item, $args, $depth ) {
if ( $args->theme_location === 'header-menu' ) {
$atts['class'] = 'menu-link';
if ( $item->current ) {
$atts['class'] .= ' menu-link--active';
}
}
return $atts;
}
—
Заказывайте очень дешевые лайки на публичную страницу в Facebook на данном сервисе и получайте возможность выбрать не только приятную цену, но и персональные условия для приобретения ресурса. Так, например, Вам будет доступен выбор скоростного режима поступления и качества подписываемых страниц. Кроме того, сервис предоставляет гарантии своим клиентам.
Список изменений
| С версии 3.0.0 | Введена. |
| С версии 4.7.0 | Added the item_spacing argument. |
| С версии 5.5.0 | Added the container_aria_label argument. |