WordPress как на ладони
Новые WordPress шаблоны Недорогой хостинг для сайтов на WordPress: wordpress.jino.ru

add_menu_page() WP 1.5

Добавляет пункт (страницу) верхнего уровня в меню админ-панели (в один ряд с постами, страницами, пользователями и т.д.).

add_menu_page() используется для создания главного пункта меню в админ-панели и прикрепления к этому пункту функции, которая будет отвечать за страницу в админ-панели связанную с этим пунктом меню.

Если нужно добавить дочерний пункт меню, используйте add_submenu_page().

Если вы видите ошибку "You do not have sufficient permissions to access this page." при попытке зайти на страницу, это значит, что вы подключаете функцию слишком рано.

Подключать функцию нужно на хуке admin_menu.

Хуков нет.

Возвращает

Строку. Название хука, название страницы меню или false, если пользователь не имеет прав доступа к меню.

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

add_menu_page( $page_title, $menu_title, $capability, $menu_slug, $function, $icon_url, $position );
$page_title(строка) (обязательный)
Текст, который будет использован в теге <title> на странице, относящейся к пункту меню.
$menu_title(строка) (обязательный)
Название пункта меню в сайдбаре админ-панели.
$capability(строка) (обязательный)
Права пользователя (возможности), необходимые чтобы пункт меню появился в списке. Таблицу возможностей смотрите здесь.
$menu_slug(строка) (обязательный)

Уникальное название (slug), по которому затем можно обращаться к этому меню.

Если параметр $function не указан, этот параметр должен равняться названию PHP файла относительно каталога плагинов, который отвечает за вывод кода страницы этого пункта меню.

$function(строка)

Название функции, которая выводит контент страницы пункта меню.Этот параметр необязательный и если он не указан, WordPress ожидает что текущий подключаемый PHP файл генерирует страницу код страницы админ-меню, без вызова функции. Большинство авторов плагинов предпочитают указывать этот параметр.

Два варианта установки параметра:

  1. Если функция является методом класса, она вызывается по ссылке:
    array( $this, 'function_name' )
    или статически:
    array( __CLASS__, 'function_name' ).

  2. Во всех остальных случаях указываем название функции в виде строки.
    По умолчанию: нет
$icon_url(строка)

Иконка для пункта меню.

  • Если вам нужно подключить произвольную картинку, можно использовать функцию plugin_dir_url( __FILE__ ), чтобы получить УРЛ до папки файла плагина и затем дописать к нему название картинки: plugin_dir_url( __FILE__ ) .'plugin-icon.png'. Размеры иконки должны быть 20х20 пикселей или меньше.

  • С версии 3.8, WP использует специальные иконки dashicons, чтобы указать одну из этих иконок, выберите нужную в коллекции иконок и укажите в этом параметре название иконки. Например, иконка консоли называется dashicons-dashboard указываем это название.

  • С версии 3.8. можно указывать закодированную в base64 строку, которая будет содержать картинку: data:image/svg+xml;base64.... В этом случае, иконка будет указана как фон слоя.

  • Если указать 'none', то будет создан слой div картинку для которого можно затем указать в CSS стилях.

  • По умолчанию, когда указана пустая строка '', используется иконка консоли из списка dashicons и будет добавлен CSS класс menu-icon-generic в слою иконки.
    По умолчанию: ''
$position(число)

Число определяющее позицию меню. Чем больше цифра, тем ниже будет расположен пункт меню.

Внимание! Если два пункта используют одинаковую цифру-позицию, один из пунктов меню может быть перезаписан и будет показан только один пункт из двух. Чтобы избежать конфликта, можно использовать десятичные значения, вместо целых чисел: 63.3 вместо 63. Используйте кавычки для кода: "63.3".

По умолчанию, пункт меню будет добавлен в конец списка.

Список позиций для базовых пунктов меню:

2 Консоль
4 Разделитель
5 Посты
10 Медиа
15 Ссылки
20 Страницы
25 Комментарии
59 Разделитель
60 Внешний вид
65 Плагины
70 Пользователи
75 Инструменты
80 Настройки
99 Разделитель

По умолчанию: в конце списка иконок

Примеры

#1 Пункт настройки темы

Этот пример показывает как добавить страницу настроек темы, в главное меню админ-панели WordPress.

<?php
add_action('admin_menu', function(){
	add_menu_page( 'Дополнительные настройки сайта', 'Пульт', 'manage_options', 'site-options', 'add_my_setting', '', 4 ); 
} );

// функция отвечает за вывод страницы настроек
// подробнее смотрите API Настроек: http://wp-kama.ru/id_3773/api-optsiy-nastroek.html
function add_my_setting(){
	?>
	<div class="wrap">
		<h2><?php echo get_admin_page_title() ?></h2>

		<?php
		// settings_errors() не срабатывает автоматом на страницах отличных от опций
		if( get_current_screen()->parent_base !== 'options-general' )
			settings_errors('название_опции');
		?>

		<form action="options.php" method="POST">
			<?php
				settings_fields("opt_group");     // скрытые защитные поля
				do_settings_sections("opt_page"); // секции с настройками (опциями).
				submit_button();
			?>
		</form>
	</div>
	<?php

}

#2 Добавление меню для администратора

Добавим пункт меню в админ-панель, который будет виден только администраторам:

Вариант 1 (только для плагинов):

add_action( 'admin_menu', 'register_my_custom_menu_page' );
function register_my_custom_menu_page(){
	add_menu_page( 
		'custom menu title', 'custom menu', 'manage_options', 'myplugin/myplugin-admin.php', '', plugins_url( 'myplugin/images/icon.png' ), 6 
	);
}

В этом случае код страницы должен быть расположен в файле wp-content/plugins/myplugin/myplugin-admin.php:

<?php
	echo "Код страницы.";
?>

Вариант 2:

add_action( 'admin_menu', 'register_my_custom_menu_page' );
function register_my_custom_menu_page(){
	add_menu_page( 
		'custom menu title', 'custom menu', 'manage_options', 'custompage', 'my_custom_menu_page', plugins_url( 'myplugin/images/icon.png' ), 6 
	); 
}

function my_custom_menu_page(){
	echo "Код страницы.";   
}

#3 Добавление пункта меню, с проверкой что его еще нет

Допустим, что перед добавление пункта меню нужно убедится что этот пункт еще не добавлен из другого места. Для того чтобы такую проверку сделать очень быстрой, можно использовать глобальную переменную $admin_page_hooks

global $admin_page_hooks;

if( isset($admin_page_hooks['идентификатор_пункта_меню']) ){
	add_submenu_page( ... );
}
else {
	add_menu_page( ..., ..., ..., 'идентификатор_пункта_меню' );
	add_submenu_page( ... );
}

#4 Проверка наличия пункта меню или пункта подменю

Эта функция проверяет наличие пункта меню или пункта подменю по указанному идентификатору этого пункта.

/**
 * Находит указанный элемент меню или подменю админки.
 *
 * Нужно использовать после события 'admin_menu'.
 * 
 * Пример использования: if( is_admin_menu_item_exists('options-general.php') ){  }
 *
 * @param  string  $handle        Идентификатор пункта меню. Указывается в 4 параметре add_menu_page() или add_submenu_page()
 * @param  boolean [$sub = false] Указан ID меню или подменю?
 * @return boolean Есть пункт меню или нет
 */
function is_admin_menu_item_exists( $handle, $sub = false ){
	if( !is_admin() || (defined('DOING_AJAX') && DOING_AJAX) )
		return false;

	global $menu, $submenu;

	$check_menu = $sub ? $submenu : $menu;

	if( empty($check_menu) )
		return false;

	foreach( $check_menu as $k => $item ){
		if( $sub ){
			foreach( $item as $sm ){
			  if( $handle == $sm[2] )
				return true;
			}
		}
		elseif( $handle == $item[2] )
			return true;
	}

	return false;
}

Заметки

  1. Функция проверяет права пользователя, чтобы отобразить пункт меню. Функция, которая выводит код страницы должна проверять эти права отдельно.

  2. Если вы используете API настроек для сохранения данных и вам нужно чтобы сохранение работало для пользователей с правами ниже администратора, вам нужно изменить разрешение через хук option_page_capability_{$option_page}, где $option_page должно быть равно параметру $menu_slug.

    Пример, как разрешить Редакторам (Editor) сохранять данные:

    // Добавим видимость пункта меню для Редакторов
    add_action( 'admin_menu', 'register_my_page' );
    function register_my_page(){
    	add_menu_page( 'My Page Title', 'My Page', 'edit_others_posts', 'my_page_slug', 'my_page_function', plugins_url( 'myplugin/images/icon.png' ), 6 ); 
    }
    
    // Изменим права
    function my_page_capability( $capability ) {
    	return 'edit_others_posts';
    }
    add_filter( 'option_page_capability_my_page_slug', 'my_page_capability' );

Код add_menu_page: wp-admin/includes/plugin.php VER 4.9.8

<?php
function add_menu_page( $page_title, $menu_title, $capability, $menu_slug, $function = '', $icon_url = '', $position = null ) {
	global $menu, $admin_page_hooks, $_registered_pages, $_parent_pages;

	$menu_slug = plugin_basename( $menu_slug );

	$admin_page_hooks[$menu_slug] = sanitize_title( $menu_title );

	$hookname = get_plugin_page_hookname( $menu_slug, '' );

	if ( !empty( $function ) && !empty( $hookname ) && current_user_can( $capability ) )
		add_action( $hookname, $function );

	if ( empty($icon_url) ) {
		$icon_url = 'dashicons-admin-generic';
		$icon_class = 'menu-icon-generic ';
	} else {
		$icon_url = set_url_scheme( $icon_url );
		$icon_class = '';
	}

	$new_menu = array( $menu_title, $capability, $menu_slug, $page_title, 'menu-top ' . $icon_class . $hookname, $hookname, $icon_url );

	if ( null === $position ) {
		$menu[] = $new_menu;
	} elseif ( isset( $menu[ "$position" ] ) ) {
	 	$position = $position + substr( base_convert( md5( $menu_slug . $menu_title ), 16, 10 ) , -5 ) * 0.00001;
		$menu[ "$position" ] = $new_menu;
	} else {
		$menu[ $position ] = $new_menu;
	}

	$_registered_pages[$hookname] = true;

	// No parent as top level
	$_parent_pages[$menu_slug] = false;

	return $hookname;
}

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

Из метки: Меню администрирования (admin menu)

Еще из раздела: Админ-панель

23 коммента
Полезные 2 Вопросы 1 Все
  • campusboy3053 cайт: www.youtube.com/c/wpplus

    А как вытащить тайтл или название страницы, которую указываешь в этой функции? Ну что-то типа the_title, только для этих страниц? А то надоело менять в функции add_menu_page, а потом в шаблоне самой страницы.

    Ответить2.3 года назад #
  • campusboy3053 cайт: www.youtube.com/c/wpplus

    Из примера:

    add_menu_page( 
     'custom menu title', 'custom menu', 'manage_options', 'myplugin/myplugin-admin.php', '', plugins_url( 'myplugin/images/icon.png' ), 6 
    );

    Что-то при передачи такого аргумента:

    'myplugin/myplugin-admin.php'

    Ссылка получается от корня, то есть:

    http://site.ru/wp-admin/myplugin/myplugin-admin.php

    Я правда пробовал подключить файл темы так. Может для плагинов он как-то понимает, что надо путь переделать.

    Если делаю так:

    get_stylesheet_directory_uri().'/inc/add_my_setting_page.php'

    то получаю это:

    http://site.ru/site.ru/wp-content/themes/fs/inc/add_my_setting_page.php

    В итоге сделал по старинке smile

    function register_add_my_setting(){
     add_menu_page( 'Дополнительные настройки сайта', 'Пульт', 'manage_options', 'site-options', 'add_my_setting', '', 4 ); 
    }
    add_action( 'admin_menu', 'register_add_my_setting' );
    
    function add_my_setting(){
     include 'inc/add_my_setting_page.php';
    }
    1
    Ответить2.2 года назад #
    • Kama6918

      Я правда пробовал подключить файл темы так. Может для плагинов он как-то понимает, что надо путь переделать.

      Да так и есть, подправил в описании этот момент.

      Вообще лучше указать все параметры, вот как ты в конце сделал, так лучше всего! Надо пример добавить в описание smile

      П.С. Добавил еще пример, сделал его первым, там немного твоего кода smile

      1
      Ответить2.2 года назад #
      • campusboy3053 cайт: www.youtube.com/c/wpplus

        Почаще бы меня посещали умные мысли, я б чаще делился хорошим кодом laugh
        Вопрос: правильно ли на кастомной странице с настройками отправлять для сохранения данные на адрес options.php? Это по 1 примеру.

        Ответить2.2 года назад #
  • Дмитрий

    Спасибо за интересную публикацию!

    Kama не подскажите, есть ли возможность в add_menu_page() изменить получаемую страницу admin.php, например, на product.php. Заранее большое спасибо!

    Ответить2.1 года назад #
    • Kama6918

      Сморите фильтры функции... Все делается через фильтры. Я не понял что конкретно вам надо.

      Ответить2 года назад #
      • Дмитрий

        Спасибо большое за ответ! Попробую изложить детальней. Я взял функцию add_menu_page() и создал страницу с циклом для получения одного поста авторизованного автора из произвольной записи.

        Мне нужно, чтобы кастомная роль могла из определенной произвольной записи получать лишь один свой пост в административном меню... Кроме этого, созданная роль для редактирования своей опубликованной записи произвольного типа должна заходить через кнопку редактировать...

        Вообщем смысл в том, что используя add_menu_page() я получаю в админке такой URL: wp-admin/admin.php?page=edit-package

        А мне нужно чтобы URL не содержал admin.php, а что-то другое. Например, product.php. В итоге URL был бы таким:

        wp-admin/product.php?page=edit-package

        То есть можно как-то повлиять на функцию (с помощью фильтров или может нужно использовать какую-то другую функцию), чтобы получить желаемый URL. Спасибо!

        Ответить2 года назад #
        • Kama6918

          Так admin.php это же не просто текст в URL - это файл с кучей кода, который описывает страницу админки, со всякими проверками по ролям, функциями и хуками.

          Если вам нужно что-то уникальное для отдельной роли. Например, редактирование какого-то поста. То может проще сделать это во фронте? Или если у роли есть доступ в админку, стандартно через add_menu_page(), а там уже при обработке вывода, проверять права и раздавать кому что нужно. А URL путь будет стандартный. Поменять его конечно можно, но это больше проблем получите, проще придумать другое решение проблемы в рамках текущего URL и текущей среды. Как-то так мне кажется...

          Ответить2 года назад #
          • Дмитрий

            Очень благодарен за ваше мнение. Во фронте не пойдет. У кастомных ролей в дминке есть профиль и возможность редактировать еще два произвольных типа записи. Там все стандартно как и с post.

            А вот именно в этом типе, нужно исключить выборку всех записей, но при этом вывести всего одну и дать возможность ее редактировать. Вот такая вот задача.

            Буду думать. Просто до вашего поста где-то читал, что add_menu_page() имеет параметр, который позволяет задавать уникальное имя для страницы... Видимо имелся ввиду фильтр $menu_slug.

            Цитирую: Или если у роли есть доступ в админку, стандартно через add_menu_page(), а там уже при обработке вывода, проверять права и раздавать кому что нужно.

            Отвечаю: Именно так и сделал. Одна заминка с этим admin.php.

            Не подскажите, может можно создать свою страницу, а потом каким-то образом привязать ее к административному меню? Или может еще какие-то подобные функции (add_menu_page()) есть. Большое спасибо!!!

            Ответить2 года назад #
            • Kama6918

              Я так и не понял зачем нужно заменить admin.php. Сделать это будет вроде не просто...

              А вот именно в этом типе, нужно исключить выборку всех записей, но при этом вывести всего одну и дать возможность ее редактировать. Вот такая вот задача.

              Если нужно убрать все записи из таблицы записей и оставить одну. То это можно сделать через хук pre_get_posts

              Ответить2 года назад #
              • Дмитрий

                Спасибо! Изменить нужно, чтобы admin.php не попадал под условия запрета доступа. То есть, я жестко закрыл все страницы имеющие admin.php от непрошеных гостей. Вижу, что проще переписать условие... Спасибо Kama!!! Удачи!

                Ответить2 года назад #
                • Kama6918

                  Зацепись на хук current_screen и используй функцию get_current_screen() через нее открой все что хочешь открыть, остальное закрой. admin.php при этом не обязательно закрывать... Там смотри в сторону элементов массива base, parent_base, parent_file. Через них можно типами страницы закрыть/открыть... Да там кучу разных условий можно придумать под нужды и не трогать admin.php, так будет в разы проще...

                  Ответить2 года назад #
  • Подскажите, пожалуйста, возможно ли каким-либо цивилизованным способом решить следующую проблему. У меня установлен плагин Media Library Plus. Он добавляет в боковое меню админки отдельный пункт "Медиафайлы +" сразу вслед за стандартным "Медиафайлы".

    Я хочу засунуть его в подменю стандартного пункта. На текущий момент я тупо закомментировала в исходном файле плагина ненужные пункты подменю и строку add_menu_page(), заменив её строкой add_submenu_page() с нужными параметрами. Это, естественно, влечёт за собой необходимость каждый раз при обновлении плагина править исходный файл. Может быть можно оформить всё это через какой-нибудь фильтр или ещё что-нибудь в этом роде?

    Ответить2 года назад #
    • campusboy3053 cайт: www.youtube.com/c/wpplus

      Есть специальные плагины, которые позволяют довольно гибко управлять правым меню админки. Но можно и без плагина, конечно, к примеру, воспользоваться функцией remove_menu_page. А после удаления вставить ту строчку с submenu, которая у Вас уже готова.

      2
      Ответить2 года назад #
  • Доброго времени суток.
    Столкнулся с необходимость проверки на существование в админке пункта меню для добавления в него подменю.

    Сделал так:

    global $menu;
    $position = '5';
    
    if ( array_key_exists( $position, $menu ) ) {
    	add_submenu_page( ... );
    } else {
    	add_menu_page( ... );
    	add_submenu_page( ... );
    }
    

    ...но, зная WordPress, гложат смутные сомнения что есть более кашерный путь решения задачи...

    Ответить1.8 год назад #
    • Kama6918

      Так не правильно!

      В Админке есть глоб. переменные $admin_page_hooks - хранит все пункты меню. Правильнее будет проверить существование меню через эту переменную. Нужно проверить существование нужного элемента массива.

      Вариант 1:

      global $admin_page_hooks;
      
      if( isset($admin_page_hooks['идентификатор_пункта_меню']) ){
      	add_submenu_page( ... );
      }
       else {
      	add_menu_page( 1, 2, 3 'идентификатор_пункта_меню' );
      	add_submenu_page( ... );
      }

      Вариант 2:

      Вот еще другой вариант для проверки наличия подменю, на основе глоб. переменных $menu и $submenu....

      /**
       * Находит указанный элемент меню или подменю админки.
       *
       * Нужно исползовать после события 'admin_menu'.
       * 
       * Пример использования: if( is_admin_menu_item_exists('options-general.php') ){  }
       *
       * @param  string  $handle        Идентификатор пункта меню. Указывается в 4 параметре add_menu_page() или add_submenu_page()
       * @param  boolean [$sub = false] Указан ID меню или подменю?
       * @return boolean Есть пункт меню или нет
       */
      function is_admin_menu_item_exists( $handle, $sub = false ){
      	if( !is_admin() || (defined('DOING_AJAX') && DOING_AJAX) )
      		return false;
      
      	global $menu, $submenu;
      
      	$check_menu = $sub ? $submenu : $menu;
      
      	if( empty($check_menu) )
      		return false;
      
      	foreach( $check_menu as $k => $item ){
      		if( $sub ){
      			foreach( $item as $sm ){
      			  if( $handle == $sm[2] )
      				return true;
      			}
      		}
      		elseif( $handle == $item[2] )
      			return true;
      	}
      
      	return false;
      }

      от сюда: http://wordpress.stackexchange.com/questions/6311/how-to-check-if-an-admin-submenu-already-exists

      Ответить1.8 год назад #
  • system

    Добрый день, можно ли добавить второй пункт меню по типу записям, например новости со своими подменю как у записей?

    1
Здравствуйте, !     Войти . Зарегистрироваться