wp_nav_menu() WP 3.0.0

Виводить довільне меню, створене в адмін-панелі: “Зовнішній вигляд > меню” (Appearance > Menus).

Яке саме меню навігації виводити (їх може бути кілька), вказується у параметрі theme_location.

Якщо не вказано параметр theme_location, то меню для виводу буде підбиратися в наступному порядку:

  1. Меню, що підходить за ID, назвою або описом переданим у параметрі ‘menu’ і якщо в цьому меню є хоч одне посилання (один елемент);

  2. інакше, перше не пусте меню;

  3. або, виведе значення, що повертається функцією вказаною в параметрі “fallback_cb” (за замовчуванням там вказано функція wp_page_menu);

  4. якщо нічого не підійшло, функція нічого не виведе.

Щоб тема підтримувала меню, потрібно увімкнути цю можливість за допомогою:
add_theme_support(‘menus’);

Або можна зареєструвати місце для меню за допомогою register_nav_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><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
(масив)
Масив параметрів меню.


За замовчуванням: array() (предустановки)


Аргументи параметра $args


theme_location
(рядок)
Ідентифікатор розташування меню у шаблоні. Ідентифікатор, вказується під час реєстрації меню функцією
register_nav_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>у меню.


За замовчуванням: ”
Текст перед анкором кожного посилання меню.


За замовчуванням: ”
Текст після анкору кожного посилання меню.


За замовчуванням: ”

depth
(число)
До якого рівня вкладеності потрібно відображати посилання (елементи меню). 0 – всі рівні.


За замовчуванням: 0

item_spacing
(рядок) (WP 4.7)
Залишати чи ні перенесення рядків у HTML коді меню. Можливо:
preserveабо
discard


За замовчуванням: ‘preserve’

echo
(true/false)
Виводити на екран або повернути для обробки.


Типово: true

walker
(об’єкт)

Клас, який буде використовуватися для побудови меню. Потрібно вказувати екземпляр об’єкта, а не рядок, наприклад new My_Menu_Walker().

Як використовувати Walker_Nav_Menu()


Приклади

4

#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;
}
1

#2 Перше не порожнє меню з налаштуваннями виводу за замовчуванням:

<?php wp_nav_menu(); ?>
1

#3 Виведення лише підпункту меню

Допустимо, є перший рівень і у кожного з елементів першого рівня є своє підменю. Нам потрібно вивести таке підменю у пункту з класом 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');

// Виведемо підменю пункту "готові-рішення"
preg_match('~'. $regex_part .'.*sub-menu[^>]+>(.*?)</ul>~s', $menu, $mm );

if( ! empty( $mm[1] ) )
	echo "<ul>$mm[1]</ul>";

Не дуже оптимальний, але робочий приклад. Іноді може стати в нагоді, для маловідвідуваних сайтів де потрібно швидко отримати результат.

0

#4 Виведемо меню з назвою “Навігація сайтом”:

<?php wp_nav_menu( [ 'menu' => 'Навігація по сайту' ] ); ?>
0

#5 Меню зі сторінок. Приклад із теми: Twenty Ten.

Якщо параметри виводу не вказані та меню не знайдено, то буде збудовано меню зі сторінок, функцією wp_page_menu() .

У цьому прикладі буде виведено меню, прикріплене до області меню ‘primary’:

<div id="access" role="navigation">
	<?php wp_nav_menu([
		'container_class' => 'menu-header',
		'theme_location' => 'primary'
	]); ?>
</div>
0

#6 Використання фільтра 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;
}
0

#7 Видалимо контейнер, тільки в одного меню, що виводиться

<?php wp_nav_menu( [ 'container' => '' ] ); ?>
0

#8 Видалимо ul обгортку

Цей приклад видаляє обгортку тега ul у меню:

<?php wp_nav_menu( [ 'items_wrap' => '%3$s' ] ); ?>
0

#9 Додамо слово на початок меню

Цей приклад показує, як додати слово на початок списку меню, у вигляді того ж елемента меню, тільки не посилання.

Додамо на початок меню, слово “Список”, а також вкажемо атрибут id створеному тегу li:

<?php wp_nav_menu([
	'theme_location' => 'primary',
	'items_wrap' => '<ul><li id="item-id">Список: </li>%3$s</ul>'
]); ?>
0

#10 Додамо 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;
}
0

#11 Використання своєї функції для побудови меню

Приклад розширення класу Walker_Nav_Menu для створення свого довільного HTML коду який виводиться функцією wp_nav_menu() . Наш HTML-код буде написаний спеціально для нашої теми.

Нижче є код свого довільного класу, який будує меню. Він додає глибину меню та парні/непарні CSS класи до елементів меню (обом ul і li):

Щоб не винаходити велосипед, копіюємо код класу Walker_Nav_Menu {} і просто змінюємо його, як нам потрібно.

// свій клас побудови меню:
class My_Walker_Nav_Menu extends Walker_Nav_Menu {

	// add classes to ul sub-menus
	function start_lvl( &$output, $depth = 0, $args = NULL ) {
		// depth dependent classes
		$indent = ( $depth > 0 ? str_repeat( "t", $depth ) : ''); //code indent
		$display_depth = ($ depth + 1); // because it counts the first submenu as 0
		$classes = array(
			'sub-menu',
			( $display_depth % 2 ? 'menu-odd' : 'menu-even' ),
			( $display_depth >=2 ? 'sub-sub-menu' : '' ),
			'menu-depth-'. $display_depth
		);
		$class_names = implode('', $classes);

		// build html
		$output .= "n" . $indent. '<ul class="' . $class_names . '">' . "n";
	}

	// add main/sub classes to li's and links
	function start_el( &$output, $data_object, $depth = 0, $args = null, $current_object_id = 0 ) {
		global $wp_query;

		// Зберігає більше script, specific name for use withthis method.
		$item = $data_object;

		$indent = ( $depth > 0 ? str_repeat( "t", $depth ) : ''); //code indent

		// depth dependent classes
		$depth_classes = array(
			( $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 ) );

		// passed classes
		$classes = empty( $item->classes )? array() : (array) $item->classes;
		$class_names = esc_attr( implode( ' ', apply_filters( 'nav_menu_css_class', array_filter( $classes ), $item ) ) );

		// build html
		$output.=$indent. '<li id="nav-menu-item-'. $item->ID . '" class="' . $depth_class_names . ' ' . $class_names . '">';

		// link attributes
		$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 = sprintf( '%1$s<a%2$s>%3$s%4$s%5$s</a>%6$s',
			$args->before,
			$attributes,
			$args->link_before,
			apply_filters( 'the_title', $item->title, $item->ID ),
			$args->link_after,
			$args->after
		);

		// build html
		$output .= apply_filters( 'walker_nav_menu_start_el', $item_output, $item, $depth, $args);
	}

}

Тепер, коли клас готовий, використовуємо його функції wp_nav_menu() . Для цього потрібно вказати екземпляр нашого класу у параметрі 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' ] );

0

#12 Окремі меню для авторизованих користувачів

Якщо потрібно показувати різні меню, авторизованим та неавторизованим користувачам, то використовуємо умовний тег 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 різних меню та прикріпити їх до відповідних локацій (областей).

0

#13 Додавання класу до окремих елементів меню

З’явився спеціальний хук для цього: 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;
}
0

#14 Виводити меню, тільки якщо воно існує

За замовчуванням, якщо меню немає, замість нього будуть виведені сторінки сайту. Але якщо потрібно виводити меню, тільки в тому випадку, коли воно створене в адмін-панелі, вкажіть параметр fallback_cbяк '__return_empty_string':

wp_nav_menu( array(
	'theme_location' => 'primary-menu',
	'fallback_cb' => '__return_empty_string'
)));
0

#15 Кешування меню (wp_nav_menu) у кеш об’єктів

Код нижче показує, як можна кешувати весь код меню в об’єктний кеш. Кеш скидатиметься під час оновлення меню. Кешування працюватиме для всіх меню.

<?php
/**
 * 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() );
	}
}

Pj_Cached_Nav_Menus::load();

Оригінальний код: https://github.com/pressjitsu/cached-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. Нижче показано майже всі параметри цього елемента:

ПолеОпис
IDID елементу меню
menu_item_parentID батьківського елемента меню
classesмасив класів елементу меню
post_dateдата додавання
post_modifiedдата останньої зміни
post_authorID користувача, який додав цей елемент меню
titleзаголовок елемента меню
urlпосилання елемента меню
attr_titletitle атрибут посилання
xfnrel атрибут посилання
targettarget атрибут посилання
currentдорівнює 1, якщо це поточний елемент
current_item_ancestor1, якщо поточний елемент – це вкладений елемент
current_item_parent1 якщо поточний елемент – це батьківський елемент
menu_orderпорядковий номер у меню
object_idID об’єкта меню. Записи, терміни та ін.
typeтип об’єкта меню (такса, запис)
objectназва такси, типу запису: page, category, post_tag…
type_labelлокалізована назва типу: Рубрика, Сторінка
post_parentID батьківського запису
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. Використовується для отримання додаткового вмісту.
	 * @param WP_Post $item Menu item data object.
	 * @param int $depth Відомості про меню. Використовується для 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.0Added the item_spacing argument.
З версії 5.5.0Added the container_aria_label argument.

Код wp_nav_menu() WP 6.0.2

function wp_nav_menu( $args = array() ) {
	static $menu_id_slugs = array();

	$defaults = array(
		'menu' => '',
		'container' => 'div',
		'container_class' => '',
		'container_id' => '',
		'container_aria_label' => '',
		'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>',
		'item_spacing' => 'preserve',
		'depth' => 0,
		'walker' => '',
		'theme_location' => '',
	);

	$ args = wp_parse_args ($ args, $ defaults);

	if ( ! in_array( $args['item_spacing'], array( 'preserve', 'discard' ), true ) ) {
		// Invalid value, fall back to default.
		$args['item_spacing'] = $defaults['item_spacing'];
	}

	/**
	 * Filters the arguments used до display a navigation menu.
	 *
	 * @ Since 3.0.0
	 *
	 * @see wp_nav_menu()
	 *
	 * @param array $args Array of wp_nav_menu() arguments.
	 */
	$args = apply_filters( 'wp_nav_menu_args', $args );
	$args = (object) $args;

	/**
	 * Filters whether to short-circuit wp_nav_menu() output.
	 *
	 * Returning a non-null value from the filter will short-circuit wp_nav_menu(),
	 * echoing that value if $args->echo is true, returning that value otherwise.
	 *
	 * @ Since 3.9.0
	 *
	 * @see wp_nav_menu()
	 *
	 * @param string|null $output Nav menu output to short-circuit with. Default null.
	 * @param stdClass $args An object containing wp_nav_menu() arguments.
	 */
	$nav_menu = apply_filters( 'pre_wp_nav_menu', null, $args );

	if ( null !== $nav_menu ) {
		if ($args->echo) {
			echo $nav_menu;
			return;
		}

		return $nav_menu;
	}

	// Get the nav menu базується на the requested menu.
	$menu = wp_get_nav_menu_object( $args->menu );

	// Get the nav menu заснований на theme_location.
	$locations = get_nav_menu_locations();
	if ( ! $menu && $args->theme_location && $locations && isset( $locations[ $args->theme_location ] ) ) {
		$menu = wp_get_nav_menu_object( $locations[ $args->theme_location ] );
	}

	// Get the first menu that has items if we still can't find a menu.
	if ( ! $menu && ! $args->theme_location ) {
		$menus = wp_get_nav_menus();
		foreach ( $menus as $menu_maybe ) {
			$menu_items = wp_get_nav_menu_items( $menu_maybe->term_id, array( 'update_post_term_cache' => false ) );
			if ( $menu_items ) {
				$menu = $menu_maybe;
				break;
			}
		}
	}

	if ( empty( $args->menu ) ) {
		$args->menu = $menu;
	}

	// If the menu exists, get its items.
	if ( $menu && ! is_wp_error( $menu ) && ! isset( $menu_items ) ) {
		$menu_items = wp_get_nav_menu_items( $menu->term_id, array( 'update_post_term_cache' => false ) );
	}

	/*
	 * If no menu was found:
	 * - Fall back (якщо один був specified), або bail.
	 *
	 * If no menu items were found:
	 * - Fall back, але тільки якщо немає місця розміщення було визначено.
	 * - Otherwise, bail.
	 */
	if ( ( ! $menu || is_wp_error( $menu ) || ( isset( $menu_items ) && empty( $menu_items ) && ! $args->theme_location ) )
		&& isset( $args->fallback_cb ) && $args->fallback_cb && is_callable( $args->fallback_cb ) ) {
			return call_user_func( $args->fallback_cb, (array) $args );
	}

	if ( ! $menu || is_wp_error( $menu ) ) {
		return false;
	}

	$nav_menu = '';
	$items = '';

	$ show_container = false;
	if ( $args->container ) {
		/**
		 * Filters List HTML tags, які є вірними для використання як menu containers.
		 *
		 * @ Since 3.0.0
		 *
		 * @param string[] $tags Примітні HTML tags для використання як menu containers.
		 * Default is array containing 'div' і 'nav'.
		 */
		$allowed_tags = apply_filters( 'wp_nav_menu_container_allowedtags', array( 'div', 'nav' ) );

		if ( is_string( $args->container ) && in_array( $args->container, $allowed_tags, true ) ) {
			$ show_container = true;
			$class = $args->container_class ? ' class="' . esc_attr( $args->container_class ) . '"' : ' class="menu-' . $menu->slug . '-container"';
			$id = $args->container_id ? ' id="' . esc_attr( $args->container_id ) . '"' : '';
			$aria_label = ( 'nav' === $args->container && $args->container_aria_label ) ? ' aria-label="' . esc_attr( $args->container_aria_label ) . '"' : '';
			$nav_menu .= '<' . $args->container . $id. $class. $aria_label . '>';
		}
	}

	// Set up the $menu_item variables.
	_wp_menu_item_classes_by_context( $menu_items );

	$sorted_menu_items = array();
	$menu_items_with_children = array();
	foreach ((array) $menu_items as $menu_item) {
		$sorted_menu_items[ $menu_item->menu_order ] = $menu_item;
		if ( $menu_item->menu_item_parent ) {
			$menu_items_with_children[ $menu_item->menu_item_parent ] = true;
		}
	}

	// Add the menu-item-has-children class where applicable.
	if ( $menu_items_with_children ) {
		foreach ( $sorted_menu_items as &$menu_item ) {
			if ( isset( $menu_items_with_children[ $menu_item->ID ] ) ) {
				$menu_item->classes[] = 'menu-item-has-children';
			}
		}
	}

	unset($menu_items, $menu_item);

	/**
	 * Filters the sorted list of menu item objects перед generating the menu's HTML.
	 *
	 * @ Since 3.1.0
	 *
	 * @param array $sorted_menu_items Докладно про те, що я маю menu order.
	 * @param stdClass $args An object containing wp_nav_menu() arguments.
	 */
	$sorted_menu_items = apply_filters( 'wp_nav_menu_objects', $sorted_menu_items, $args );

	$items .= walk_nav_menu_tree( $sorted_menu_items, $args->depth, $args );
	unset($sorted_menu_items);

	// Attributes.
	if ( ! empty( $args->menu_id ) ) {
		$wrap_id = $args->menu_id;
	} else {
		$wrap_id = 'menu-'. $menu->slug;

		while ( in_array( $wrap_id, $menu_id_slugs, true ) ) {
			if ( preg_match( '#-(d+)$#', $wrap_id, $matches ) ) {
				$wrap_id = preg_replace( '#-(d+)$#', '-' . ++$matches[1], $wrap_id );
			} else {
				$wrap_id = $wrap_id . '-1';
			}
		}
	}
	$menu_id_slugs[] = $wrap_id;

	$wrap_class = $args->menu_class ? $args->menu_class : '';

	/**
	 * Filters HTML content content for navigation menus.
	 *
	 * @ Since 3.0.0
	 *
	 * @see wp_nav_menu()
	 *
	 * @param string $items HTML content list для menu items.
	 * @param stdClass $args An object containing wp_nav_menu() arguments.
	 */
	$items = apply_filters( 'wp_nav_menu_items', $items, $args );
	/**
	 * Filters HTML content content for specific navigation menu.
	 *
	 * @ Since 3.0.0
	 *
	 * @see wp_nav_menu()
	 *
	 * @param string $items HTML content list для menu items.
	 * @param stdClass $args An object containing wp_nav_menu() arguments.
	 */
	$items = apply_filters( "wp_nav_menu_{$menu->slug}_items", $items, $args );

	// Не потрібно друкувати будь-яку мітку, якщо не є елементи в цьому пункті.
	if ( empty( $items ) ) {
		return false;
	}

	$nav_menu .= sprintf( $args->items_wrap, esc_attr( $wrap_id ), esc_attr( $wrap_class ), $items );
	unset ($ items);

	if ( $show_container ) {
		$nav_menu .= '</' . $args->container . '>';
	}

	/**
	 * Filters HTML content for navigation menus.
	 *
	 * @ Since 3.0.0
	 *
	 * @see wp_nav_menu()
	 *
	 * @param string $nav_menu HTML вміст для navigation menu.
	 * @param stdClass $args An object containing wp_nav_menu() arguments.
	 */
	$nav_menu = apply_filters( 'wp_nav_menu', $nav_menu, $args);

	if ($args->echo) {
		echo $nav_menu;
	} else {
		return $nav_menu;
	}
}

Залишити відповідь

Ваша e-mail адреса не оприлюднюватиметься. Обов’язкові поля позначені *