WordPress как на ладони
Готовые темы (шаблоны) для WordPress wordpress jino

wp_nav_menu() WP 3.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(), тогда поддержка меню темой включиться автоматически.

Еще про включение и добавление меню можете почитать в отдельной статье.

Оглавление:

Фильтры изменения элемента меню

  • 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>
Хуки из функции:
Возвращает

Функция выводит на экран html код меню.

к началу

Использование

<?php wp_nav_menu( $args ); ?>
wp_nav_menu( array(
	'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'          => '',
) );

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

theme_location(строка)
Идентификатор расположение меню в шаблоне. Идентификатор, указывается при регистрации меню функцией register_nav_menu().
По умолчанию: ''
menu(строка)
Меню которое нужно вывести. Соответствие: id, слаг или название меню.
По умолчанию: ""
container(строка)

Чем оборачивать ul тег. Допустимо: div или nav.

Если не нужно оборачивать ничем, то пишем false: container => false.
По умолчанию: div

container_class(строка)
Значение атрибута class у контейнера меню.
По умолчанию: menu-{menu slug}-container
container_id(строка)
Значение атрибута id у контейнера меню.
По умолчанию: ''
menu_class(строка)
Значение атрибута class у тега ul.
По умолчанию: menu
menu_id(строка)
Значение атрибута id у тега ul.
По умолчанию: слаг меню
echo(логическое)
Выводить на экран (true) или возвратить для обработки (false).
По умолчанию: true
fallback_cb(строка)
Функция для обработки вывода, если никакое меню не найдено.
Передает все аргументы $args указанной тут функции.
Установите '__return_empty_string' чтобы ничего не выводилось, если меню нет.
По умолчанию: wp_page_menu
before(строка)
Текст перед тегом <a> в меню.
По умолчанию: ''
after(строка)
Текст после каждого тега </a> в меню.
По умолчанию: ''
link_before(строка)
Текст перед анкором каждой ссылки в меню.
По умолчанию: ''
link_after(строка)
Текст после анкора каждой ссылки в меню.
По умолчанию: ''
items_wrap(строка)
Нужно ли оборачивать элементы в тег ul. Если нужно, указывается шаблон обертки.
По умолчанию: '<ul id="%1$s" class="%2$s">%3$s</ul>'
depth(число)
Сколько уровень вложенных друг в друга ссылок показывать. 0 - все уровни.
walker(объект)
Класса, который будет использоваться для построения меню. Нужно указывать объект, а не строку, например new My_Menu_Walker(). По умолчанию: Walker_Nav_Menu(). Как использовать смотрите ниже...
По умолчанию: Walker_Nav_Menu
item_spacing(строка)
Оставлять или нет переносы строк в HTML коде меню. Может быть: preserve или discard
По умолчанию: 'preserve'
к началу

Примеры

#1. Первое не пустое меню, с настройками вывода по умолчанию:

<?php wp_nav_menu(); ?>

#2. Выведем меню с названием "Навигация по сайту":

<?php wp_nav_menu( array('menu' => 'Навигация по сайту' )); ?>

#3 Меню из страниц. Пример из темы: Twenty Ten.

Если параметры вывода не указаны и меню не найдено, то будет построено меню из страниц, функцией wp_page_menu().

В этом примере, будет выведено меню со слагом 'primary':

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

#4 Использование фильтра 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;
}

#4.1. Удалим контейнер, только у одного, выводимого меню

<?php wp_nav_menu( array( 'container' => '' ) ); ?>

#5 Удалим ul обертку

Этот пример удалит обертку тега ul у меню:

<?php wp_nav_menu( array( 'items_wrap' => '%3$s' ) ); ?>

#6 Добавим слово в начало меню

Этот пример показывает, как добавить слово в начало списка меню, в виде такого же элемента меню, только не ссылки. Добавим в начало меню, слово "Список", также укажем атрибут id созданному тегу li:

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

#7 Добавим CSS классы ко всем меню

Используя хук, мы можем добавить свои CSS классы, если соблюдается нужное нам условие.

Добавим CSS класс, если это пост и название элемента меню равно "blog":

<?php
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;
}
?>

#8 Использование своей функции для построения меню

Чтобы это сделать, во-первых нужно указать аргумент 'walker' => new Your_Walker_Function.

Your_Walker_Function - это наш новый класс, который строит меню. Чтобы не изобретать велосипед, её можно скопировать из оригинала (класс Walker_Nav_Menu из файла \wp-includes\nav-menu-template.php) и просто подправить там где нужно.

Вот пример, добавляющий глубину меню и четные/нечетные CSS классы к элементам меню (обоим ul и li):

// свой класс построения меню:
class magomra_walker_nav_menu extends Walker_Nav_Menu {

	// add classes to ul sub-menus
	function start_lvl( &$output, $depth ) {
		// 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, $item, $depth, $args ) {
		global $wp_query;
		$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 );
	}
}

// И там, где нужно выводим меню так:
function magomra_nav_menu( $menu_id ) {
	// main navigation menu
	$args = array(
		'theme_location'    => 'navigation_menu_primary',
		'container'     => 'div',
		'container_id'      => 'top-navigation-primary',
		'conatiner_class'   => 'top-navigation',
		'menu_class'        => 'menu main-menu menu-depth-0 menu-even', 
		'echo'          => true,
		'items_wrap'        => '<ul id="%1$s" class="%2$s">%3$s</ul>',
		'depth'         => 10, 
		'walker'        => new magomra_walker_nav_menu
	);

	// print menu
	wp_nav_menu( $args );
}
к началу

#9 Отдельные меню для авторизованных пользователей

Если нужно показывать разные меню, авторизованным и неавторизованным пользователям, то используем условный тег 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 разных меню и прикрепить их к соответствующим локациям (областям).

#10 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 ) )
			$item->classes[] = 'menu-parent-item'; // все элементы поля "classes" меню, будут совмещены и выведены в атрибут class HTML тега <li>
	}

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

#11 Добавление класса к отдельным элементам меню

С версии 4.1.

Появился специальных хук для этого: 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;
}

До версии 4.1.

Классы элементам меню добавляются функцией _wp_menu_item_classes_by_context( &$menu_items );. Но к сожалению в ней не предусмотрены никакие фильтры, чтобы добавить свой класс. Поэтому пойдем обходным путем и используем костыль str_replace():

// получаем а не выводим меню
$menu = wp_nav_menu( array( 'echo' => 0, ) );
// добавляем ко всем пунктам класс my__class
$menu = str_replace('class="menu-item', 'class="menu-item my__class', $menu );
// выводим на экран
echo $menu;
к началу

#12 Выводить меню, только если оно существует

По умолчанию, если меню нет, то вместо него будут выведены страницы сайта. Но если нужно выводить меню, только в том случае когда оно создано в админ-панели, укажите параметр fallback_cb как '__return_empty_string':

<?php
wp_nav_menu( array(
	'theme_location' => 'primary-menu',
	'fallback_cb' => '__return_empty_string'
) );
?>

13 Вывод только подпункта меню

Допустим, есть первый уровень и у каждого из элементов первого уровня, есть свое подменю. Нам нужно вывести такое подменю у пункта с классом 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>";

Не очень оптимальный, но рабочий пример. Иногда может пригодится, для малопосещаемых сайтов где нужно быстро получить результат.

к началу

CSS классы элементов меню

Следующие 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 (категория, метка или произвольная таксономия)
к началу

Для элементов текущей страницы

  • .current-menu-item — если ссылка в меню совпадает с адресом просматриваемой страницы. Текущая страница.

Для элементов родительских для просматриваемой страницы

  • .current-menu-parent
  • .current-{object}-ancestor
  • .current-{type}-ancestor

Для элементов как-то связанных с просматриваемой страницей

  • .current-menu-ancestor
  • .current-{object}-ancestor
  • .current-{type}-ancestor

Для элементов связанных с главной страницей сайта

  • .menu-item-home

Совместимость с функцией wp_page_menu()

  • .page_item
  • .page-item-$ID
  • .current_page_item
  • .current_page_parent
  • .current_page_ancestor

Параметры $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 - ярлык записи
к началу

Пример использования параметра 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 схеме.

Код wp nav menu: wp-includes/nav-menu-template.php WP 4.7.5

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

	$defaults = array( '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>', '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 to 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 the wp_nav_menu() output.
	 *
	 * Returning a non-null value to 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 based on the requested menu
	$menu = wp_get_nav_menu_object( $args->menu );

	// Get the nav menu based on the theme_location
	if ( ! $menu && $args->theme_location && ( $locations = get_nav_menu_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 ) {
			if ( $menu_items = wp_get_nav_menu_items( $menu_maybe->term_id, array( 'update_post_term_cache' => false ) ) ) {
				$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 (if one was specified), or bail.
	 *
	 * If no menu items were found:
	 *  - Fall back, but only if no theme location was specified.
	 *  - 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 the list of HTML tags that are valid for use as menu containers.
		 *
		 * @since 3.0.0
		 *
		 * @param array $tags The acceptable HTML tags for use as menu containers.
		 *                    Default is array containing 'div' and 'nav'.
		 */
		$allowed_tags = apply_filters( 'wp_nav_menu_container_allowedtags', array( 'div', 'nav' ) );
		if ( is_string( $args->container ) && in_array( $args->container, $allowed_tags ) ) {
			$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 ) . '"' : '';
			$nav_menu .= '<'. $args->container . $id . $class . '>';
		}
	}

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

	$sorted_menu_items = $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 before generating the menu's HTML.
	 *
	 * @since 3.1.0
	 *
	 * @param array    $sorted_menu_items The menu items, sorted by each menu item's 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 ) ) {
			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 the HTML list content for navigation menus.
	 *
	 * @since 3.0.0
	 *
	 * @see wp_nav_menu()
	 *
	 * @param string   $items The HTML list content for the menu items.
	 * @param stdClass $args  An object containing wp_nav_menu() arguments.
	 */
	$items = apply_filters( 'wp_nav_menu_items', $items, $args );
	/**
	 * Filters the HTML list content for a specific navigation menu.
	 *
	 * @since 3.0.0
	 *
	 * @see wp_nav_menu()
	 *
	 * @param string   $items The HTML list content for the menu items.
	 * @param stdClass $args  An object containing wp_nav_menu() arguments.
	 */
	$items = apply_filters( "wp_nav_menu_{$menu->slug}_items", $items, $args );

	// Don't print any markup if there are no items at this point.
	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 the HTML content for navigation menus.
	 *
	 * @since 3.0.0
	 *
	 * @see wp_nav_menu()
	 *
	 * @param string   $nav_menu The HTML content for the 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;
}

Cвязанные функции

Из метки: nav_menu (меню навигации)

Еще из раздела: Другие функции темы

wp_nav_menu 101 комментарий
Полезные 10 Вопросы 9 Все
  • Руслан

    Здравствуйте!
    Скажите пожалуйста, есть ли возможность получить id элемента меню в своей функции для построения меню?
    Т.е. если в меню содержатся в разнобой рубрики, страницы и посты, мне нужно получить непосредственно их ID.
    Просто хочу настроить меню таким образом, чтобы можно было выводить перед ссылкой ещё и иконку из произвольного поля страницы/рубрики.
    Спасибо!

    Ответить4 месяца назад #
    2
    • Руслан

      Разобрался!
      Нашел дополнительные параметры объекта $item:

      /*
      * Некоторые из параметров объекта $item
      * ID - ID самого элемента меню, а не объекта на который он ссылается
      * menu_item_parent - ID родительского элемента меню
      * classes - массив классов элемента меню
      * post_date - дата добавления
      * post_modified - дата последнего изменения
      * post_author - ID пользователя, добавившего этот элемент меню
      * title - заголовок элемента меню
      * url - ссылка
      * attr_title - HTML-атрибут 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 - ярлык, который был у поста при его добавлении в меню
      */
      Ответить4 месяца назад #
      1
  • campusboy1455 cайт: wp-plus.ru
    @

    При вызове этой функции сразу делается 4 запроса к БД. Многовато для 1 функции smile

    Ответить4 месяца назад #
  • lincaseidhe22 cайт: ardeya.ru

    Кама, помогай, срочно нужно smile Хочу найти функцию, которая позволит добавлять класс к ссылке внутри тега li, но так и не вижу выхода...

    Использую для вывода класс, который тут описан - My_Walker_Nav_Menu, чтобы собственный вывод сделать. В общем практически все что нужно получилось, только не получается к родителю добавить класс.

    Если добавляю в тело класса:

    if( $item->menu_item_parent ) {
       $parent_class = 'dropdown-toggle';
    }

    и в выводе добавляю эту переменную - то он присваивает не к родительскому, а к дочернему. В общем я в расстеряности. Пробовал менять на ancestor - ноль реакции, класс вообще не присваивается....

    Ответить4 месяца назад #
    • lincaseidhe22 cайт: ardeya.ru

      Кстати при использовании данного расширителя - невозможно добавить произвольный класс из меню wordpress...

      Или пульните ссылкой на готовое решение... Времени верстку переделывать - просто нет.... Верстал какой-то пьяный сантаклаус smile

      Ответить4 месяца назад #
  • Андрей

    Кама, покажите пожалуйста, как запускать фильтр для вставки css классов всм элементам меню ? Я не представляю, как вставить в меню функцию apply filter

    Ответить2 месяца назад #
  • Владислав

    Здравствуйте! Есть задача сделать трехуровневое меню.
    Огромное спасибо за статью с Walker, все получилось сделать кроме одного.

    Задумка состоит в том, чтобы при наведении на первый уровень элементов, открывался второй уровень (это сделано), а при клике по родительскому li добавлялся класс active к этому же li (это сделано), а к дочернему ul добавлялся класс static, который не будет давать ul сворачиваться (вот в этом-то и проблема)

    Разметка для понимания:

    <li class="active">
    	<a>Ссылка</a>
    	<ul class="static"> // Как добавить класс static к дочернему ul, когда родитель - li получит класс active?
    	</ul>
    </li>
    </li>

    Третий уровень должен открываться при клике по родительскому li второго уровня и вложенный ul получает класс static.

    <li>
    	<a>Ссылка</a>
    	<ul>
    		<li class="active">
    			<a>Ссылка</a>
    			<ul class="static">
    			</ul>
    		</li>
    	</ul>
    </li>

    Получается, нужно добавлять к дочернему ul класс static тогда, когда к родителю - li присваивается класс active.

    Вот код для walker

    // Добавляем свой класс для пунктов меню:
    class my_walker_nav_menu extends Walker_Nav_Menu {
    
    // Добавляем классы к вложенным ul
    function start_lvl( &$output, $depth ) {
    	// Глубина вложенных ul
    	$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  ? 'dropdown' : '' ),
    		( $display_depth >=2 ? 'dropdown' : '' ),
    		'menu-depth-' . $display_depth
    		);
    	$class_names = implode( ' ', $classes );
    
    	// build html
    	$output .= "\n" . $indent . '<ul class="' . $class_names . '">' . "\n";
    }
    
    // Добавляем классы к вложенным li
     function start_el( &$output, $item, $depth, $args ) {
    	global $wp_query;
    	$indent = ( $depth > 0 ? str_repeat( "\t", $depth ) : '' ); // code indent
    
    	// depth dependent classes
    	$depth_classes = array(
    		( $depth == 0 ? 'has-sub' : '' ),
    		( $depth >=2 ? '' : '' ),
    		( $depth % 2 ? '' : '' ),
    		'menu-item-depth-' . $depth
    	);
    	$depth_class_names = esc_attr( implode( ' ', $depth_classes ) );
    
    	// passed classes
    	$classes = empty( $item->classes ) ? array() : (array) $item->classes;
    
    	$mycurrent = ( $item->current == 1 ) ? ' active' : '';
    
    	$class_names = esc_attr( implode( ' ', apply_filters( 'nav_menu_css_class', array_filter( $classes ), $item ) ) );
    
    	$output .= $indent . '<li id="nav-menu-item-'. $item->ID . '" class="' . $depth_class_names . ' ' . $class_names . $mycurrent . '">';
    
    	// Добавляем атрибуты и классы к элементу a (ссылки)
    	$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 ? 'parent' : '' ) . ( $depth == 1 ? 'child' : '' ) . ( $depth >= 2 ? 'sub-child' : '' ) . '"';
    
    	$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 );
    }
    
    }
    Ответить24 дня назад #
  • Владислав

    Привет всем еще раз. Искал везде, но не нашел как сделать через walker. Сделал на js, но при переходе на страницу на долю секунды меню отображается свернутым, а потом срабатывает js, добавляет заветный класс static к дочернему ul и только потом меню становится развернутым. Поэтому пишу еще раз в надежде решить вопрос через walker или php в целом... Возможно кто подскажет хоть в какую сторону копать?

    Пытался еще сделать через current_item_parent, прописывая в start_lvl строку:
    $currentul = ( $item->current_item_parent == 1 ? ' static': '' );
    и потом добавляя переменную в output
    $output .= "\n" . $indent . '<ul class="' . $class_names . $currentul . '">' . "\n";
    но это не срабатывает, возможно потому что элемент $item работает только в start_el

    Возможно можно добавить какой-то фильтр... нашел как это сделать, но опять же таки работает только для элементов li меню...

    Ответить20 дней назад #
    • campusboy1455 cайт: wp-plus.ru
      @

      Привет. А почему ты привязался именно к слову "static"? По умолчанию WP всем дочерним UL даёт класс submenu, может к нему и привязать свой JS/CSS?

      Ответить20 дней назад #
      • Владислав

        О, спасибо за ответ, есть с кем переговорить хоть, может на какую мысль набредем...
        Это не то чтобы привязка, просто в меню изначально используется класс static. Я его скачал и пытаюсь выводить динамически теперь.
        Я могу задать всем элементам с классом submenu класс static, но проблема в том, что тогда все дочерние списки откроются, а нужно чтобы открылся только список дочерний к li с классом active, а остальные так и оставались скрытыми.

        Ответить20 дней назад #
        • campusboy1455 cайт: wp-plus.ru
          @

          Я не пойму зачем такая привязка, а пока не пойму, как помочь. Я к тому, что если отображается с помощью css, то:

          ul.sub-menu{
          	display: none;
          }
          
          li.current-menu-item ul.sub-menu{
          	display: block;
          }

          У тебя вместо ".current-menu-item" идёт "active"

          Ответить20 дней назад #
          • Владислав

            Да, но при наведении курсора на активный элемент li и убирая курсор в сторону js скрывает дочерний ul и потом снова открывает (благодаря css). Открытие и скрытие дочерних ul работает также по hover. Поэтому, чтобы не прописывать дополнительный js для активных пунктов, подумал может есть способ добавить класс через php.

            Ответить20 дней назад #
            • campusboy1455 cайт: wp-plus.ru
              @

              Как по мне, намного проще сделать "защиту" в JS от такого, чем возиться с Волкерами. Если делаешь на jQuery, то просто проверяй через hasClass(). Разве это сложнее, чем Волкер ваять целый? smile

              Ответить20 дней назад #
              • Владислав

                Понял...просто мысль о том, что нужно добавить всего один класс, чтобы все заработало не дает мне покоя) Окей, тогда пошел перепиливать код менюшки, спасибо за помощь!

                Ответить20 дней назад #
                • campusboy1455 cайт: wp-plus.ru
                  @

                  Не за что. Волкер стоит создавать, когда надо кардинально изменить вёрстку меню, а такую мелочь легко на JS сделать. Можно и не проверять, а при выборе элементов hover указать .not(). Там несколько способов у jquery победить такое. Удачи!

                  Ответить20 дней назад #
                • campusboy1455 cайт: wp-plus.ru
                  @

                  Не знаю, правильно ли уловил мысль, но вот набросал меню и js.

                  Ответить20 дней назад #
  • Денис
    @

    Как сделать шаблон меню, в котором бы выводился не только главный заголовок, а ещё два?
    У меня каждая страница имеет три пункта, три отдельных поля: основной заголовок на русском, на китайском и картинка. Картинка это тоже обычное поле, в котором прописан тег . Все три пункта нужно выводить. То бишь так

    На русском中文

    На русском中文

    Как сделать? Непонятно как выводить китайское и картинку.

    Ответить15 дней назад #
  • Денис
    @

    Как сделать шаблон меню, в котором бы выводился не только главный заголовок, а ещё два?
    У меня каждая страница имеет три пункта, три отдельных поля: основной заголовок на русском, на китайском и картинка. Картинка это тоже обычное поле, в котором прописан тег . Все три пункта нужно выводить. То бишь так

    <ul>
    <li><h1 class="entry-title"><a href="">На русском<br /><span>中文</span><br />
    <img src="" width="1100" height="618" border="0"/></a></h1></li>
    
    <li><h1 class="entry-title"><a href="">На русском<br /><span>中文</span><br />
    <img src="" width="1100" height="618" border="0"/></a></h1></li>
    </ul>

    Как сделать? Непонятно как выводить китайское и картинк

    Ответить15 дней назад #
  • Андрей

    Здравствуйте, Тимур!
    Скажите, пожалуйста, есть ли возможность при помощи встроенных функций ограничить число уровней в меню в админке. Например, я создаю дизайн, где больше двух уровней в теме технически невозможно (задумка такая), но при редактировании меню пользователь может создать и третий и четвертый уровень. Как можно это запретить? Спасибо!

    Ответить10 дней назад #
    • campusboy1455 cайт: wp-plus.ru
      @

      Привет. Отвечу за него. Обратите внимание на параметр depth.

      Ответить10 дней назад #
      1

Здравствуйте, !

Ваш комментарий