Произвольные поля в меню

В этом уроке хочу познакомить вас с двумя новыми хуками, появившимися в WordPress 5.4, которые позволят вам добавить какой-нибудь текст или HTML в интерфейс редактирования элемента меню в админке и кастомайзере. А если можно добавить HTML, то можно добавить какие-то поля 🤔

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

Экшен-хук wp_nav_menu_item_custom_fields срабатывает сразу после того, как выводятся все поля при редактировании конкретного элемента меню и имеет следующие параметры:

  • $item_id – ID элемента меню,
  • $item – объект элемента меню,
  • $depth – уровень вложенности элемента меню,
  • $args – объект дополнительных аргументов,
  • $id – ID самого меню, а не элемента.

То есть у нас есть возможность передать все эти параметры в прикреплённую к хуку функцию, например так:

add_action( 'wp_nav_menu_item_custom_fields', 'true_hello', 10, 5 );
 
function true_hello( $item_id, $item, $depth, $args, $id ) {
 
	echo 'Приветик';
 
}

И в итоге в админке мы получаем:

Добавление текста в редактирования элемента меню WordPress

Сам я не очень часто пользуюсь кастомайзером, как-то добавлял поля для своего плагина туда и в то время написал гайд по кастомайзеру, с тех пор мне практически не приходилось его использовать. Однако есть плагины, которые его используют и не имеют альтернативных настроек в админке WordPress, например один такой плагин многие знают – WooCommerce.

На этом пункте особо подробно не буду останавливаться, скажу лишь, что у хука wp_nav_menu_item_custom_fields_customize_template нет никаких параметров, однако внутри HTML, который вы выведете этим хуком, вы можете использовать такие конструкции как {{ data.menu_item_id }} или <# if ( 'custom' === data.item_type ) { #>.

Я бы написал об этом отдельный урок, и напишу, когда (если) буду чаще пользоваться кастомайзером.

Пример

Так как я сам недавно запилил на сайте два видеокурса (раз и два) и настраивал отображение сайта для зарегистрированных и незарегистрированных пользователей, то актуальнее всего будет добавить в элемент меню, который мы с вами будем выводить на примере условия отображения для авторизованных пользователей, например так:

Произвольные поля и настройки в меню WordPress

Добавление полей в меню

add_action( 'wp_nav_menu_item_custom_fields', 'true_menu_field', 10, 5 );
 
function true_menu_field( $item_id, $item, $depth, $args, $id ) {
 
	// можете сюда также вкинуть wp_nonce_field и его проверку в следующем шаге 
 
	$is_logged_in = get_post_meta( $item_id, '_menu_loggedin', true );
 
	echo '<p class="description">
		<label>
			<input type="checkbox" ' . checked( 'yes', $is_logged_in, false ) . ' name="menu-item-loggedin[' . $item_id . ']">
			Только для зарегистрированных пользователей
		</label>
	</p>';
 
}
  • Как видно на строчке 7, работа с метаданными меню по сути как и работа с мета обычных типов записей, мы даже используем наверняка знакомую вам get_post_meta().
  • На строке 11 функция checked() позволяет сравнить два значения и, в случае их совпадения, сразу вывести checked='checked' для поля чекбокса.

Сохранение полей

Тут тоже всё делается обычным хуком, очень похожим на принцип действия save_post.

add_action( 'wp_update_nav_menu_item', 'true_update_menu', 10, 2 );
 
function true_update_menu( $menu_id, $menu_item_db_id ) {
 
	// если добавляли nonce-поле, то тут его валидация
 
	$meta_value = isset( $_POST[ 'menu-item-loggedin' ][ $menu_item_db_id ] ) && 'on' == $_POST[ 'menu-item-loggedin' ][ $menu_item_db_id ] ? 'yes' : 'no';
	update_post_meta( $menu_item_db_id, '_menu_loggedin', $meta_value );
 
}

Супер, чекбокс добавили, сохраняться тоже должен норм, теперь нужно как-то задействовать всё это на сайте.

Вывод при помощи wp_get_nav_menu_items()

Про функцию wp_get_nav_menu_items() у меня есть отдельный пост на сайте, а сейчас вкратце покажу, как интегрировать в неё нашу проверку на авторизованного пользователя при помощи is_user_logged_in().

if( $menu_items = wp_get_nav_menu_items( $menu ) ) {
 
	foreach ( $menu_items as $key => $menu_item ) {
 
 
		if( ! is_user_logged_in() && 'yes' == get_post_meta( $menu_item->ID, '_menu_loggedin', true ) ) {
			continue;
		}
 
		// ... тут идёт вывод элемента меню
 
	}
 
}

В самой функции wp_nav_menu() мы не можем так легко залезть в тело цикла и прописать туда своё условие.

Что же делать? Использовать класс волкера, про который вы у меня можете почитать здесь и посмотреть видеоурок здесь.

Наше условие нужно прописать в самом начале метода волкера start_el()

function start_el( &$output, $item, $depth = 0, $args = NULL, $id = 0 ) {
 
 
	if( ! is_user_logged_in() && 'yes' == get_post_meta( $item->ID, '_menu_loggedin', true ) ) {
		return;
	}
 
 
	// ... 
 
 
}

Миша

В последние годы я долго не знал, что мне делать с сайтом misha.blog, ведь он практически не приносит никакого профита, но недавно я осознал, что моя миссия – способствовать распространению WordPress. Ведь WordPress – это лучший движок для разработки сайтов – как для тех, кто готов использовать заложенную структуру этой CMS, так и для тех, кто предпочитает headless решения.

Сам же я впервые познакомился с WordPress в 2009 году. Организатор WordCamp. Преподаватель в школах Epic Skills и LoftSchool.

Если вам нужна помощь с вашим сайтом или может даже разработка с нуля на WordPress / WooCommerce — пишите. Я и моя команда сделаем вам всё на лучшем уровне.

Комментарии — 2

Комментирование этого поста более не доступно.
  • Nikolay 8 апреля 2020 #

    Огромное спасибо, за такие статьи!!!

    • Миша 8 апреля 2020 #

      Вэлкам 🙃