Умение правильно создавать меню и подменю необходимо каждому разработчику, осваивающему WordPress API. Административное меню занимает центральное место в построении функциональности тем и плагинов. Благодаря описанным ниже рекомендациям вы разберётесь во всех тонкостях создания меню, откроете доступ к опциям темы напрямую из боковой панели, а не только через раздел «Внешний вид», и научитесь строить профессиональные административные интерфейсы, которые выглядят как родные для WordPress.
Архитектура административного меню WordPress
WordPress предоставляет две основные функции для построения административных меню: add_menu_page() для элементов верхнего уровня и add_submenu_page() для дочерних пунктов. Обе функции подключаются через хук admin_menu, который срабатывает после инициализации базовой структуры панели управления, но до отрисовки меню в боковой панели. Этот момент выбран не случайно: он даёт окно для регистрации ваших меню до того, как WordPress отрисует навигацию.
Система меню WordPress имеет чёткую иерархию. Элементы верхнего уровня отображаются в левой боковой панели. Каждый такой элемент может содержать несколько подменю. Стандартные меню ядра — Консоль, Записи, Медиафайлы, Страницы, Комментарии, Внешний вид, Плагины, Пользователи, Инструменты, Настройки — занимают позиции со 2 по 10 по умолчанию, при этом позиция 1 зарезервирована за разделителем консоли. Когда вы создаёте своё меню, вы вставляете его в этот упорядоченный список рядом с элементами ядра.
За кулисами WordPress хранит данные меню в глобальных массивах $menu и $submenu. Каждая запись представляет собой ассоциативный массив с ключом по ярлыку меню. Массив $menu содержит элементы верхнего уровня как числовые массивы, где каждый элемент — это [menu_title, capability, menu_slug, page_title, css_classes, hookname, icon_url]. Понимание этой структуры помогает при отладке конфликтов меню или написании кода, модифицирующего меню других плагинов.
add_menu_page(): создание меню верхнего уровня
Функция add_menu_page() принимает до 7 аргументов. Пять из них обязательны, два опциональны, но критически важны для правильного размещения и брендирования. Сигнатура функции хорошо документирована, но часто используется неправильно, потому что разработчики пропускают чтение описаний параметров:
add_menu_page(
string $page_title,
string $menu_title,
string $capability,
string $menu_slug,
callable $callback = '',
string $icon_url = '',
int $position = null
);
[/codeblock]
| Параметр | Тип | Обязательный | Описание |
|---|---|---|---|
| $page_title | string | Да | Текст, отображаемый в заголовке браузера при просмотре административной страницы. Используйте описательный заголовок, например «Настройки MyTheme». Этот текст также появляется как заголовок h1 на вашей странице, если используется стандартная разметка WordPress. |
| $menu_title | string | Да | Текст в боковом меню панели управления. Делайте его коротким. Длинные названия ломают вёрстку боковой панели и обрезаются CSS. Максимальная рекомендуемая длина — около 20 символов с пробелами. |
| $capability | string | Да | Необходимое право пользователя для доступа к странице. Используйте 'manage_options' для общих настроек, 'edit_theme_options' для настроек темы. WordPress проверяет это право у текущего пользователя перед отображением пункта меню. |
| $menu_slug | string | Да | Уникальный идентификатор страницы меню, используется в URL как ?page=ваш-ярлык. Добавьте префикс с названием плагина или темы для предотвращения коллизий. Никогда не используйте общие ярлыки вроде «settings» или «options». |
| $callback | callable | Да | Функция, отрисовывающая содержимое страницы. Должна выводить валидный HTML. Если опущена или равна falsy, WordPress предполагает, что рендеринг страницы будет обработан через другие хуки — продвинутый шаблон, редко используемый на практике. |
| $icon_url | string | Нет | Иконка меню. Принимает имя класса Dashicons (например, 'dashicons-admin-generic'), SVG data URI или URL изображения. Использование класса Dashicons — самый простой подход, который гарантирует соответствие иконки цветовой схеме админ-панели WordPress. |
| $position | int | Нет | Позиция в порядке меню боковой панели. Большие числа отображаются ниже. Стандартные меню занимают позиции 2-10, 15, 20, 25, 60, 65, 70, 75, 80. Дробные значения вроде 60.5 не поддерживаются — используйте только целые числа. |
Практический пример: страница настроек темы
Ниже — полный пример регистрации меню верхнего уровня для страницы настроек темы. Обратите внимание на использование Dashicons для иконки и позиции 61 для размещения сразу после меню «Внешний вид»:
function mytheme_add_admin_menu() {
add_menu_page(
'Настройки MyTheme',
'MyTheme',
'manage_options',
'mytheme-settings',
'mytheme_settings_page_callback',
'dashicons-admin-generic',
61
);
}
add_action('admin_menu', 'mytheme_add_admin_menu');
function mytheme_settings_page_callback() {
?>
Настройки MyTheme
Настройте параметры вашей темы здесь.
Разбираем параметр capability
Параметр capability определяет, кто может видеть и получать доступ к вашим страницам меню. Это не просто косметический выбор — это ваш основной механизм контроля доступа в административной панели. WordPress предоставляет иерархию встроенных прав, привязанных к ролям пользователей. Выбор неправильного права может открыть чувствительные настройки редакторам, которые не должны их видеть, или скрыть важные опции от администраторов, которым они нужны.
| Роль | Типичные права | Применение для доступа к меню |
|---|---|---|
| Супер-администратор | manage_network, все остальные | Настройки сети мультисайта, управление пользователями между сайтами |
| Администратор | manage_options, activate_plugins, edit_theme_options, install_plugins | Общие настройки плагинов, опции темы, конфигурация сайта, импорт/экспорт |
| Редактор | edit_pages, edit_others_posts, manage_categories | Меню управления контентом, настройка рубрик и меток, панели модерации записей |
| Автор | edit_published_posts, upload_files | Личные панели контента, загрузка медиафайлов, настройка профиля |
| Участник | edit_posts, delete_posts | Минимальный. Участники редко имеют отдельные меню кроме стандартного экрана записей |
| Подписчик | read | Только страницы редактирования профиля. Подписчики обычно видят только экран своего профиля |
Распространённая ошибка — использование 'manage_options' для меню, которые должны быть доступны редакторам. Если ваше меню управляет настройками, связанными с контентом, такими как рубрика по умолчанию или модерация комментариев, используйте 'edit_pages' или 'moderate_comments'. Это даёт доступ нужным людям, сохраняя параметры конфигурации сайта под защитой 'manage_options'.
add_submenu_page(): построение иерархии меню
Функция add_submenu_page() создаёт пункт, который появляется под существующим меню верхнего уровня. Сигнатура почти идентична add_menu_page(), но с одним дополнительным параметром — ярлыком родительского меню — и она не принимает аргументы иконки или позиции, поскольку они наследуются от родителя:
add_submenu_page(
string $parent_slug,
string $page_title,
string $menu_title,
string $capability,
string $menu_slug,
callable $callback = ''
);
[/codeblock]
Параметр $parent_slug определяет, где появится ваше подменю. Передайте ярлык собственного меню верхнего уровня, чтобы вложить подменю под ваше кастомное меню. Передайте ярлык ядра WordPress, чтобы добавить страницу под существующее меню, такое как «Настройки» или «Инструменты». Оба подхода валидны и широко используются в зависимости от того, что делает ваша страница.
Добавление подменю под своё меню верхнего уровня
При использовании собственного меню верхнего уровня укажите ваш ярлык в качестве родительского. Это стандартный шаблон для плагинов и тем, которым нужно несколько страниц настройки, организованных под одним родителем:
function mytheme_add_admin_submenus() {
add_submenu_page(
'mytheme-settings',
'Настройки социальных сетей',
'Социальные сети',
'manage_options',
'mytheme-social',
'mytheme_social_page_callback'
);
add_submenu_page(
'mytheme-settings',
'Настройки отображения',
'Отображение',
'manage_options',
'mytheme-display',
'mytheme_display_page_callback'
);
}
add_action('admin_menu', 'mytheme_add_admin_submenus');
[/codeblock]
Добавление подменю под стандартные меню WordPress
Вы также можете добавлять страницы подменю в существующие меню ядра WordPress. Это распространённый подход для плагинов, которые хотят разместить свои настройки в разделе «Настройки», а не создавать собственный пункт верхнего уровня. Используйте стандартные ярлыки:
function myplugin_add_under_settings() {
add_submenu_page(
'options-general.php',
'Конфигурация API',
'Настройки API',
'manage_options',
'myplugin-api-config',
'myplugin_api_config_callback'
);
}
add_action('admin_menu', 'myplugin_add_under_settings');
[/codeblock]
| Меню ядра | Ярлык родителя | Типичное использование подменю |
|---|---|---|
| Консоль | index.php | Кастомные виджеты аналитики, ленты активности |
| Записи | edit.php | Экраны статусов записей, редакционные календари |
| Медиафайлы | upload.php | Расширения медиабиблиотеки, управление CDN |
| Страницы | edit.php?post_type=page | Шаблоны страниц, массовое редактирование |
| Внешний вид | themes.php | Редакторы кастомного CSS, управление шрифтами |
| Плагины | plugins.php | Проверка зависимостей плагинов, массовое управление |
| Пользователи | users.php | Расширения профилей, импорт/экспорт |
| Инструменты | tools.php | Диагностика, утилиты импорта/экспорта данных |
| Настройки | options-general.php | Страницы конфигурации плагинов |
Стратегии размещения меню
То, где вы размещаете меню, влияет на его заметность и воспринимаемую важность. WordPress использует числовую систему позиций, где меньшие числа отображаются выше в боковой панели. Выбор правильной позиции — это одновременно UX-решение и следование конвенциям. Позиции ядра:
2 — Консоль
4 — Разделитель
5 — Записи
10 — Медиафайлы
15 — Ссылки
20 — Страницы
25 — Комментарии
59 — Разделитель
60 — Внешний вид
65 — Плагины
70 — Пользователи
75 — Инструменты
80 — Настройки
99 — Разделитель
[/codeblock]
Для настроек темы позиция 61 размещает ваше меню между «Внешний вид» и «Плагины» — именно там пользователи интуитивно ищут опции, связанные с темой. Для меню плагинов позиция 66 размещает вас сразу после «Плагины». Для утилит и инструментов позиции 76-79 располагаются между «Инструменты» и «Настройки». Промежутки между позициями ядра сделаны намеренно, давая вам место для вставки кастомных меню без перезаписи встроенных пунктов.
Полная реализация: опции темы с подменю
Ниже — готовая к использованию реализация, создающая меню верхнего уровня с тремя подменю для темы. Этот шаблон использует Settings API для корректной обработки опций, демонстрирует технику общего ярлыка для предотвращения дублирующихся пунктов подменю и включает проверки прав в каждом колбэке для эшелонированной защиты:
function mytheme_admin_menu_setup() {
add_menu_page(
'Настройки MyTheme',
'MyTheme',
'manage_options',
'mytheme-main',
'mytheme_main_page_html',
'dashicons-admin-customizer',
61
);
add_submenu_page(
'mytheme-main',
'Общие настройки',
'Общие',
'manage_options',
'mytheme-main',
'mytheme_main_page_html'
);
add_submenu_page(
'mytheme-main',
'Настройки социальных сетей',
'Социальные сети',
'manage_options',
'mytheme-social',
'mytheme_social_page_html'
);
add_submenu_page(
'mytheme-main',
'Настройки отображения',
'Отображение',
'manage_options',
'mytheme-display',
'mytheme_display_page_html'
);
add_submenu_page(
'mytheme-main',
'Настройки типографики',
'Типографика',
'manage_options',
'mytheme-typography',
'mytheme_typography_page_html'
);
}
add_action('admin_menu', 'mytheme_admin_menu_setup');
function mytheme_main_page_html() {
if (!current_user_can('manage_options')) {
return;
}
?>
Общие настройки MyTheme
Удаление и переупорядочивание существующих меню
Иногда требуется удалить стандартные меню для определённых ролей пользователей или реорганизовать боковую панель. WordPress предоставляет remove_menu_page() для меню верхнего уровня и remove_submenu_page() для дочерних пунктов. Обе функции должны подключаться к admin_menu с высоким приоритетом, чтобы гарантировать выполнение после регистрации целевых меню:
function mytheme_clean_admin_menu() {
if (!current_user_can('manage_options')) {
remove_menu_page('tools.php');
remove_menu_page('edit-comments.php');
}
remove_submenu_page('themes.php', 'theme-editor.php');
remove_submenu_page('plugins.php', 'plugin-editor.php');
}
add_action('admin_menu', 'mytheme_clean_admin_menu', 999);
[/codeblock]
Динамическая видимость меню в зависимости от контекста
Вы можете условно регистрировать меню на основе прав пользователя, конфигурации сайта или даже текущего экрана. Это позволяет показывать меню только тогда, когда они актуальны, снижая визуальный шум для пользователей, которым не нужны определённые опции:
function mytheme_conditional_menus() {
if (current_user_can('manage_options')) {
add_menu_page(
'Расширенные настройки',
'Расширенные',
'manage_options',
'mytheme-advanced',
'mytheme_advanced_page'
);
}
if (get_option('mytheme_enable_analytics')) {
add_submenu_page(
'mytheme-main',
'Панель аналитики',
'Аналитика',
'manage_options',
'mytheme-analytics',
'mytheme_analytics_page'
);
}
$active_plugins = get_option('active_plugins');
if (in_array('woocommerce/woocommerce.php', $active_plugins)) {
add_submenu_page(
'mytheme-main',
'Интеграция с WooCommerce',
'WooCommerce',
'manage_options',
'mytheme-woocommerce',
'mytheme_woocommerce_page'
);
}
}
add_action('admin_menu', 'mytheme_conditional_menus');
[/codeblock]
Третий пример особенно полезен: он показывает подменю интеграции с WooCommerce только если WooCommerce действительно установлен и активен. Это предотвращает ситуацию, когда пользователи видят опции для плагинов, которых у них нет.
Использование SVG-иконок для меню
Хотя Dashicons хорошо работают для стандартных случаев, пользовательские SVG-иконки придают более отличительный вид и идеально масштабируются на дисплеях с высоким DPI. SVG должен быть закодирован как base64 data URI и использовать fill="%23999" для соответствия стандартному серому цвету админ-панели WordPress, который CSS ядра перекрашивает в синий при наведении и активном состоянии:
function mytheme_custom_icon() {
$svg = '';
$icon = 'data:image/svg+xml;base64,' . base64_encode($svg);
add_menu_page(
'MyTheme',
'MyTheme',
'manage_options',
'mytheme-main',
'mytheme_main_page_html',
$icon,
61
);
}
add_action('admin_menu', 'mytheme_custom_icon');
[/codeblock]
Цвет заливки по умолчанию использует серый цвет админ-панели WordPress (#999). CSS ядра автоматически перекрашивает иконки при наведении: когда пункт меню активен или под курсором, WordPress применяет синий оттенок через CSS-фильтры. %23 в SVG fill — это URL-закодированный символ решётки, необходимый потому, что значение цвета встроено внутрь data URI.
Интернационализация меток меню
Все заголовки меню и страниц должны проходить через функции перевода для мультиязычной поддержки. WordPress использует функции __() и _x() с текстовым доменом, соответствующим ярлыку вашего плагина или темы. Загружайте переводы до срабатывания хука admin_menu:
function mytheme_i18n_menu() {
add_menu_page(
__('Настройки MyTheme', 'mytheme'),
__('MyTheme', 'mytheme'),
'manage_options',
'mytheme-main',
'mytheme_main_page_html'
);
add_submenu_page(
'mytheme-main',
__('Настройки социальных сетей', 'mytheme'),
__('Социальные сети', 'mytheme'),
'manage_options',
'mytheme-social',
'mytheme_social_page_html'
);
}
add_action('admin_menu', 'mytheme_i18n_menu');
[/codeblock]
Проблема дублирующихся пунктов подменю
Одна из самых частых проблем при построении административных меню — обнаружение того, что WordPress создал дублирующийся пункт подменю с тем же названием, что и ваше меню верхнего уровня. Это происходит потому, что WordPress автоматически генерирует пункт подменю для каждого меню верхнего уровня, у которого зарегистрировано хотя бы одно подменю. Автоматически сгенерированный пункт использует заголовок и ярлык меню верхнего уровня.
Решение простое: сделайте так, чтобы ваш первый вызов add_submenu_page() использовал точно такой же $menu_slug, как и родительский add_menu_page(). Это заменяет автоматически сгенерированный пункт вашим собственным. Вот сравнение «до и после»:
Без исправления (появляется дубликат):
add_menu_page('Настройки темы', 'MyTheme', 'manage_options', 'mytheme', 'callback');
// Это создаст дублирующееся подменю «MyTheme»!
add_submenu_page('mytheme', 'Общие', 'Общие', 'manage_options', 'mytheme-general', 'callback');
[/codeblock]
С исправлением (чистое меню):
add_menu_page('Настройки темы', 'MyTheme', 'manage_options', 'mytheme', 'callback');
// Первое подменю использует тот же ярлык — заменяет авто-сгенерированный пункт
add_submenu_page('mytheme', 'Общие', 'Общие', 'manage_options', 'mytheme', 'callback');
add_submenu_page('mytheme', 'Соцсети', 'Соцсети', 'manage_options', 'mytheme-social', 'callback');
[/codeblock]
Отладка проблем регистрации меню
Когда меню не появляются как ожидалось, систематическая отладка экономит часы. Вот самые частые точки отказа и способы их диагностики:
Проверьте, срабатывает ли хук
Добавьте временный вызов error_log() внутрь вашего колбэка admin_menu, чтобы убедиться, что он выполняется. Если в логе отладки ничего не появляется, ваш вызов add_action(), вероятно, размещён после срабатывания хука или содержит опечатку в имени функции.
Проверьте соответствие прав
Право, которое вы передаёте в add_menu_page(), должно совпадать с тем, что действительно есть у текущего пользователя. Если вы залогинены как администратор и используете 'edit_published_posts', меню появится. Если позже вы тестируете как редактор и используете 'manage_options', оно не появится. Используйте плагин User Switching для быстрого переключения ролей при тестировании.
Проверьте конфликты ярлыков
Два меню не могут иметь одинаковый ярлык. Если другой плагин зарегистрировал 'mytheme-settings' до выполнения вашего кода, ваш add_menu_page() завершится молча. Всегда добавляйте префикс с пространством имён плагина или темы и используйте уникальные идентификаторы.
Проверьте существование колбэка
Если функция обратного вызова не существует на момент вызова add_menu_page(), меню регистрируется, но клик по нему вызывает фатальную ошибку. Проверьте, что имя функции написано без ошибок и что функция определена в файле, который был подключён до срабатывания admin_menu.
Работа с меню произвольных типов записей
Произвольные типы записей, зарегистрированные с 'show_in_menu' => true, автоматически получают меню верхнего уровня и подменю для списка записей, добавления и управления терминами таксономии. Вы можете добавить свои подменю к меню CPT, используя ярлык меню типа записи:
function myplugin_add_cpt_submenu() {
add_submenu_page(
'edit.php?post_type=product',
'Импорт товаров',
'Импорт товаров',
'manage_options',
'product-import',
'myplugin_product_import_page'
);
}
add_action('admin_menu', 'myplugin_add_cpt_submenu');
[/codeblock]
Формат ярлыка для меню произвольных типов записей: edit.php?post_type={ключ_типа_записи}. Этот шаблон работает для любого типа записей с незарезервированным ключом, включая типы от WooCommerce (product, shop_order), Events Calendar (tribe_events) или ваши собственные.
Соображения производительности
Хотя регистрация меню легковесна, колбэки отрисовки страниц — нет. Вот рекомендации для поддержания быстродействия административных страниц:
- Не загружайте весь WordPress на каждой административной странице. Используйте get_current_screen() внутри колбэка admin_menu для проверки, находитесь ли вы на нужной странице, перед загрузкой тяжёлых зависимостей — медиа-загрузчика WordPress, редакторов кода или сторонних SDK.
- Подключайте административные скрипты и стили только на ваших конкретных страницах, используя хук admin_enqueue_scripts с параметром $hook_suffix, а не глобально при каждой загрузке админ-страницы.
- Кэшируйте дорогостоящие запросы к базе данных в транзиентах для административных страниц, которые загружают большие наборы данных — логи, аналитику или историю импорта.
- Используйте admin-ajax.php или REST API для динамически обновляемых данных вместо перезагрузки всей страницы при каждом взаимодействии.
Часто задаваемые вопросы
В чём разница между add_menu_page() и add_submenu_page()?
add_menu_page() создаёт элемент верхнего уровня в боковой панели администратора с собственной иконкой и позицией. add_submenu_page() создаёт дочерний элемент, который появляется под родительским меню — будь то стандартное меню WordPress или созданное вами. Главное отличие: add_submenu_page() требует параметр $parent_slug для указания родительского меню и не принимает аргументы иконки или позиции, так как они наследуются от родителя. Используйте add_menu_page(), когда нужен новый раздел верхнего уровня; add_submenu_page() — для организации связанных настроек под общим родителем.
Какой хук использовать для регистрации административных меню?
Используйте хук действия admin_menu. Он срабатывает после настройки базовой структуры панели администратора, но до отрисовки меню в боковой панели. Это единственный хук для регистрации меню. Если нужно изменить меню, зарегистрированные другими плагинами или темами, используйте низкий приоритет, например 999, чтобы ваш колбэк выполнялся после всех остальных. Для удаления меню на основе роли пользователя рассмотрите также подключение к admin_init для проверки контекста текущего пользователя.
Какое право использовать для меню настроек темы?
Для настроек темы, управляющих внешним видом и макетом, используйте edit_theme_options. Это право предоставлено администраторам по умолчанию и является стандартным для страниц настройки тем. Для настроек плагинов, затрагивающих конфигурацию всего сайта — ключи API, кэширование, безопасность, — используйте manage_options. Для меню, связанных с контентом, — редакционные календари или управление таксономиями — используйте edit_posts или edit_pages в зависимости от требуемого уровня доступа.
Как разместить меню между двумя существующими меню WordPress?
Используйте аргумент $position функции add_menu_page() со значением между двумя позициями ядра. Стандартные меню занимают позиции 2 (Консоль), 5 (Записи), 10 (Медиафайлы), 20 (Страницы), 25 (Комментарии), 60 (Внешний вид), 65 (Плагины), 70 (Пользователи), 75 (Инструменты) и 80 (Настройки). Для размещения между «Внешний вид» и «Плагины» используйте позиции 61-64. Между «Плагины» и «Пользователи» — 66-69. WordPress автоматически обрабатывает коллизии, увеличивая дублирующиеся позиции, так что можно безопасно использовать любое целое число в промежутке.
Почему моё меню показывает дублирующийся пункт подменю?
WordPress автоматически создаёт пункт подменю с названием меню верхнего уровня, когда ни одно подменю не использует ярлык родительского меню. Чтобы предотвратить это, сделайте так, чтобы ваш первый вызов add_submenu_page() использовал тот же $menu_slug, что и родительский add_menu_page(). Это заменяет автоматически сгенерированный пункт вашим собственным. Если дубликаты сохраняются, проверьте, не регистрируете ли вы одно и то же меню дважды в разных колбэках хука.
Можно ли добавлять подменю в стандартные меню WordPress?
Да. Передайте ярлык стандартного меню в качестве параметра $parent_slug. Часто используемые ярлыки: index.php (Консоль), edit.php (Записи), themes.php (Внешний вид), plugins.php (Плагины), options-general.php (Настройки) и tools.php (Инструменты). Это распространённый шаблон для добавления страниц настройки плагинов в раздел «Настройки». Для меню произвольных типов записей используйте формат edit.php?post_type={ключ_типа_записи}.
Как удалить существующее административное меню?
Используйте remove_menu_page('ярлык') для меню верхнего уровня и remove_submenu_page('родительский-ярлык', 'ярлык-подменю') для подменю. Подключайтесь к admin_menu с высоким номером приоритета, обычно 999, чтобы удаление выполнялось после регистрации целевого меню. Для удалений, привязанных к роли, вызывайте эти функции условно внутри колбэка admin_menu на основе проверок current_user_can().
Какие варианты иконок доступны для административных меню?
Три варианта: классы CSS Dashicons (например, 'dashicons-admin-generic'), включённые в ядро WordPress и поддерживающие все встроенные глифы; URL пользовательских изображений размером 20x20px в PNG или другом формате; и base64-закодированные SVG data URI для иконок, не зависящих от разрешения, которые масштабируются на дисплеях с высоким DPI. SVG предпочтительнее для современной разработки: они идеально масштабируются, могут быть окрашены в соответствии с темой администратора через атрибут fill и не создают HTTP-запросов в отличие от URL изображений. Используйте fill="%23999" в SVG для соответствия стандартной цветовой схеме админ-панели WordPress.
Нажмите для реакции



