Как сохранять элементы меню по отдельности? (вместо того, чтобы каждый раз сохранять всё меню целиком)

Прежде всего давайте я покажу вам, что имею ввиду:

Как сохранять элементы меню по отдельности в WordPress

В каких случаях может понадобиться данный функционал?

  • Когда у нас большое количество элементов меню, а изменить требуется лишь один или два.
  • Если у вас медленное интернет-соединение или большое время ответа сервера.

Шаг 1. Создаем файл JavaScript и подключаем его в админку сайта

Допустим у себя я создал файл themes/twentyten-child/truemenu.js и подключил его при помощи wp_enqueue_script().

function true_enqueue_menu_script() {
 	wp_enqueue_script( 'truemenu', get_stylesheet_directory_uri() . '/truemenu.js', array('jquery'), null, false );
}
 
add_action( 'admin_enqueue_scripts', 'true_enqueue_menu_script' );

Шаг 2. jQuery-плагин Live Query

Нам он понадобится для автоматического добавления кнопки «Изменить» каждому элементу меню.

Почему не использовать функцию each()? Да потому что она будет работать только для существующих элементов меню. А для нас важно не только изменять существующие, но и добавлять новые пункты меню.

Сам плагин доступен по этой ссылке. А дальше уже смотрите сами — вы можете просто вставить содержимое плагина в начало файла truemenu.js или же тоже подключить его функцией wp_enqueue_script().

Шаг 3. Добавляем кнопки сохранения элементов меню и настраиваем события для них.

Вот собственно и содержимое файла truemenu.js. Этот код добавляем кнопку «Изменить» для каждого элемента меню на странице wp-admin/nav-menus.php и позволяет нам по нажатию на кнопку отправлять AJAX-запросы.

/* сюда вы можете вставить код плагина Live Query */
 
jQuery(function($){
 
	$(".menu-item-settings").livequery(function() {
		$(this).append('<a class="button button-primary true-edit-menu">Изменить</a>');
	});
 
	// если не хотите использовать Live Query plugin, тогда закомментируйте строчки сверху и раскомментируйте эти
	//$('.menu-item-settings').each(function(i){ 
	//	$(this).append('<a class="button button-primary true-edit-menu">Изменить</a>');
	//});
 
	$('.true-edit-menu').live('click',function(){
		btn = $(this); // записываем элемент кнопки в переменную
		item = btn.parent();
		var item_url = item.find('.edit-menu-item-url').val(); // ссылка меню
		var item_attrtitle = item.find('.edit-menu-item-attr-title').val(); // текст при наведении
		var item_title = item.find('.edit-menu-item-title').val(); // анкор ссылки
		var item_classes = item.find('.edit-menu-item-classes').val(); // классы CSS 
		var item_xfn = item.find('.edit-menu-item-xfn').val(); // XFN
		var item_desc = item.find('.edit-menu-item-description').val(); // описание
		var item_target = item.find('.field-link-target').find('input').attr('checked'); // открытие в новой вкладке
		var item_menuid =  item.find('.menu-item-data-db-id').val(); // ID элемента меню
		var item_parentid = item.find('.menu-item-data-parent-id').val(); // ID родительского элемента меню
		var item_menu = $('#menu').val(); // ID самого меню
		var item_pos = item.find('.menu-item-data-position').val(); // порядковый номер элемента
		$.ajax({
			type: 'POST',
			url: ajaxurl,
			data: 'action=savemenuitem&item_url=' + item_url + '&item_attrtitle=' + item_attrtitle + '&item_title=' + item_title + '&item_classes=' + item_classes + '&item_xfn=' + item_xfn + '&item_desc=' + item_desc + '&item_target=' + item_target + '&item_menuid=' + item_menuid + '&item_parentid=' + item_parentid + '&item_menu=' + item_menu + '&item_pos=' + item_pos + '&item_max=' + $('.menu-item-settings').length,
			beforeSend: function(xhr){
				btn.text('Сохраняю...');
			},
			success: function(data){
				btn.text('Изменить');
			}
		});
		return false;
	});
 
});

Шаг 4. Код обработчика PHP, который и будет сохранять элементы меню

Я использовал функцию wp_insert_post() для изменения/добавления элемента меню и wp_set_object_terms() для присвоения элемента к определенному меню. Код можете вставить в functions.php вашей темы:

function true_saveitem_callback(){
 
	// параметры для wp_insert_post() (да, элементы меню это оказывается типы постов)
	$item_args = array(
		'ID'		=> $_POST['item_menuid'],
		'post_title'    => $_POST['item_title'],
		'post_type'	=> 'nav_menu_item',
		'post_status'	=> 'publish',
		//'menu_order'	=> $_POST['item_pos'], // Я закомментировал эту строку, потому что изменение порядка элементов не работает так, как хотелось бы
		'post_content'  => $_POST['item_desc'], // описание
		'post_excerpt'   => $_POST['item_attrtitle'] // атрибут title
	);
 
	// для новых элементов важно правильно установить порядок
 	if ( 'draft' == get_post_status( intval($_POST['item_menuid']) ) ) {
 		$item_args['menu_order'] = $_POST['item_max'];
 	}
 
	// insert or update the menu element
	$item_id = wp_insert_post( $item_args );
 
	// присваиваем элемент меню (да, сами меню это таксономии)
	wp_set_object_terms( $item_id, intval($_POST['item_menu']), 'nav_menu', $append = false );
 
	// post meta parameters
	$target = ($_POST['item_target'] == 'checked') ? '_blank' : ''; 
	update_post_meta( $item_id, '_menu_item_target', $target);
	update_post_meta( $item_id, '_menu_item_menu_item_parent', $_POST['item_parentid']);
	update_post_meta( $item_id, '_menu_item_classes', $_POST['item_classes']);
	update_post_meta( $item_id, '_menu_item_xfn', esc_attr($_POST['item_xfn']));
	update_post_meta( $item_id, '_menu_item_url', esc_attr($_POST['item_url']));
 
	die();
}
 
if( is_admin() ) {
	add_action('wp_ajax_savemenuitem', 'true_saveitem_callback');
}

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

Подпишитесь, чтобы раз в неделю получать свежие статьи с блога по email.

По теме

Комментарии 9

  • VRS7 мая 2015 в 16:05 #

    Благодарю! Это просто супер-класс))!
    Буду пробовать вечером.

  • Джама10 мая 2015 в 02:05 #

    Интересная мысль, только я даже не представляю как вы должны были намучатся с этими меню что бы придумывать такие "колёса" =)

  • VRS17 июля 2015 в 00:07 #

    Доброй ночи.
    Поставила - все отлично).
    Загвоздка в обратном действии). Если удалить элемент, то требуется сохранять все меню целиком. А как удалять пункты индивидуально?

    • Миша17 июля 2015 в 07:07 #

      Доброе утро! Удаление не делал :)

      • VRS17 июля 2015 в 23:07 #

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

        <a class="button button-primary true-edit-menu">Изменить</a><a class="button button-primary true-delete-menu">Удалить</a>

        Но вторая кнопка не появилась.

        Еще вопросик про порядок элементов. Целый день рою буржунет, но так и не нашла, как в волкере отсортировать пункты меню по алфавиту. Как это было в wp_page_menu.

        • Миша19 июля 2015 в 10:07 #

          Да, wp_delete_post().

          Почему не появилась вторая кнопка — не представляю, возможно кэш?

          На вопрос про порядок сортировки ответил в другом комментарии)

          • VRS19 июля 2015 в 14:07 #

            Да, наверно, кэш. Пробовала вообще удалить скрипт с сервера, а кнопка не исчезла)).
            Миш, а есть идеи как все-таки фиксировать порядок элементов? Для wp_get_nav_menu_items() нужно указывать локацию или id меню, а они у меня выводятся виджетами =(.

Оставить комментарий / вопрос

phpjsHTMLCSSSQLПросто код
  Для того, чтобы оставить комментарий, пожалуйста, зарегистрируйтесь или авторизуйтесь на сайте.
Получайте новости блога по email или следите за мной в социальных сетях.
  • Миша: Да, точно)

  • Владимир: и на третьей строке не хватает скобки ) закрывающей if :)

  • Миша: Добрый вечер! Рекомендую получить ID пользователя через функцию get_current_user_id().

  • Дмитрий: Миша, подскажите пожалуйста, я использую такой редирект, но он не срабатывает: add_action( 'template_redirect', funct...

  • Миша: Ну как не определена - это аргумент функции. Или я просто вас не до конца понимаю.