Создание меню в админке WordPress — полное руководство
Одним из ключевых этапов в освоении WordPress API является знакомство с системой меню административной панели. Меню — это точка входа пользователя в функционал вашей темы или плагина. Без правильно настроенного меню страница опций, которую вы создали через Settings API, будет недоступна. Пользователь просто не сможет найти её в админке.
WordPress предоставляет четыре разных способа добавления пунктов меню, и каждый решает свою задачу. Выбор неправильного типа меню приводит к путанице в интерфейсе и жалобам пользователей. В этой статье мы разберём все четыре способа, их параметры, ограничения и лучшие практики применения.
Четыре типа меню в WordPress
Прежде чем погружаться в код, важно понять, какие типы меню существуют и когда какой использовать. Неправильный выбор типа меню — одна из самых частых ошибок начинающих разработчиков тем и плагинов.
1. Меню верхнего уровня (Top-Level Menu). Создаёт новый пункт в левой боковой панели админки — такой же, как стандартные «Записи», «Страницы», «Настройки». Используется, когда ваш плагин или тема заслуживают собственного раздела. Функция: add_menu_page(). Пример: плагин WooCommerce добавляет свой пункт «Товары» в левое меню.
2. Подменю (Submenu). Добавляет дочерний пункт под существующим меню. Может быть как под стандартным пунктом WordPress (Настройки, Инструменты), так и под вашим собственным меню верхнего уровня. Функция: add_submenu_page(). Пример: подпункт «Настройки темы» внутри меню «Внешний вид».
3. Страница плагинов (Plugins Page). Добавляет пункт в меню «Плагины». Используется редко, в основном для страниц конфигурации конкретного плагина. Функция: add_plugins_page(). Отличается от add_submenu_page только тем, что жёстко привязана к меню «Плагины» и не требует указания родительского slug.
4. Страница тем (Themes Page). Добавляет пункт в меню «Внешний вид» (Appearance). Классический выбор для тем, которым нужна страница настроек. Функция: add_theme_page(). Идентична add_submenu_page для родителя 'themes.php', но семантически точнее.
| Функция | Куда добавляет | Типичное применение | Обязательные параметры |
|---|---|---|---|
| add_menu_page() | Новый пункт верхнего уровня | Крупный плагин со своим разделом | 5 из 7 |
| add_submenu_page() | Под существующим пунктом | Подраздел настроек плагина | 6 |
| add_plugins_page() | Меню «Плагины» | Конфигурация плагина | 5 |
| add_theme_page() | Меню «Внешний вид» | Настройки темы | 5 |
add_menu_page() — меню верхнего уровня
Функция add_menu_page() создаёт новый пункт в левой боковой панели. Она принимает семь параметров, из которых первые пять обязательны:
| Параметр | Тип | Обязательный | Описание |
|---|---|---|---|
| $page_title | string | Да | Заголовок страницы (в теге <title>) |
| $menu_title | string | Да | Название пункта в боковом меню |
| $capability | string | Да | Право, необходимое для доступа (обычно manage_options) |
| $menu_slug | string | Да | Уникальный slug пункта меню (используется в URL) |
| $callback | callable | Да | Функция, выводящая содержимое страницы |
| $icon_url | string | Нет | URL иконки или dashicon-класс |
| $position | int | Нет | Позиция в меню (чем меньше число, тем выше) |
Базовый пример добавления меню верхнего уровня:
function sandbox_add_admin_menu() {
add_menu_page(
'Sandbox Theme Options',
'Sandbox',
'manage_options',
'sandbox-options',
'sandbox_options_page_html',
'dashicons-admin-generic',
61
);
}
add_action( 'admin_menu', 'sandbox_add_admin_menu' );
function sandbox_options_page_html() {
if ( ! current_user_can( 'manage_options' ) ) {
return;
}
?>
Иконки меню: dashicons и кастомные SVG
Параметр $icon_url в add_menu_page() определяет иконку пункта меню. WordPress поддерживает три способа задания иконок:
Dashicons — встроенный набор иконок WordPress. Просто укажите CSS-класс, например 'dashicons-admin-generic', 'dashicons-chart-area', 'dashicons-shield'. Всего доступно более 200 иконок.
Кастомное изображение — укажите URL PNG или SVG-файла. Размер должен быть 20x20 пикселей для оптимального отображения: get_template_directory_uri() . '/assets/icon.png'
Base64 SVG — встроенный SVG, закодированный в base64. Позволяет обойтись без отдельного файла:
$icon_svg = 'data:image/svg+xml;base64,' . base64_encode(
''
);
add_menu_page( 'My Plugin', 'My Plugin', 'manage_options', 'my-plugin', 'my_page_callback', $icon_svg, 30 );[/codeblock]Позиционирование меню
Параметр $position определяет, в каком месте боковой панели появится ваш пункт меню. WordPress резервирует определённые позиции для стандартных пунктов:
| Позиция | Стандартный пункт | Примечание |
|---|---|---|
| 2 | Консоль (Dashboard) | Не используйте |
| 5 | Записи (Posts) | Не используйте |
| 10 | Медиафайлы (Media) | Не используйте |
| 15 | Ссылки (Links) | Можно переопределить |
| 20 | Страницы (Pages) | Не используйте |
| 25 | Комментарии (Comments) | Не используйте |
| 60 | Внешний вид (Appearance) | Не используйте |
| 65 | Плагины (Plugins) | Не используйте |
| 70 | Пользователи (Users) | Не используйте |
| 75 | Инструменты (Tools) | Не используйте |
| 80 | Настройки (Settings) | Не используйте |
Для своего меню выбирайте позиции между стандартными. Популярные варианты: 26 (между Комментариями и Внешним видом), 61 (между Внешним видом и Плагинами), 81 (после Настроек). Если два плагина используют одну позицию, WordPress добавляет суффикс к slug последнего зарегистрированного пункта.
add_submenu_page() — подменю
Функция add_submenu_page() добавляет дочерний пункт под существующим меню. Сигнатура аналогична add_menu_page(), но с дополнительным первым параметром — slug родительского меню:
add_submenu_page(
'sandbox-options',
'Social Network Settings',
'Social Networks',
'manage_options',
'sandbox-social',
'sandbox_social_page_html'
);[/codeblock]Здесь 'sandbox-options' — это slug родительского меню, созданного через add_menu_page(). Подменю появляется при наведении на родительский пункт и может содержать любое количество дочерних страниц.
Для добавления подменю к стандартным пунктам WordPress используйте их slug:
| Стандартное меню | Slug родителя | Требуемое право |
|---|---|---|
| Консоль | index.php | read |
| Записи | edit.php | edit_posts |
| Медиафайлы | upload.php | upload_files |
| Страницы | edit.php?post_type=page | edit_pages |
| Внешний вид | themes.php | switch_themes |
| Плагины | plugins.php | activate_plugins |
| Пользователи | users.php | list_users |
| Инструменты | tools.php | edit_posts |
| Настройки | options-general.php | manage_options |
add_plugins_page() и add_theme_page() — специализированные подменю
Эти две функции являются обёртками над add_submenu_page() с фиксированным родителем. Они существуют для семантической ясности и уменьшения вероятности ошибки в slug родительского меню.
add_plugins_page() — добавляет пункт в меню «Плагины»:
add_plugins_page(
'My Plugin Configuration',
'My Plugin',
'manage_options',
'my-plugin-config',
'my_plugin_config_page_html'
);[/codeblock]add_theme_page() — добавляет пункт в меню «Внешний вид», идеально подходит для страниц опций темы:
add_theme_page(
'Theme Options',
'Theme Options',
'manage_options',
'theme-options',
'theme_options_page_html'
);[/codeblock]Обе функции подключаются к хуку admin_menu, как и все остальные функции меню. Порядок вызова внутри хука не влияет на порядок отображения пунктов — WordPress сортирует их по позиции и алфавиту.
Хук admin_menu и приоритеты
Все функции создания меню должны вызываться внутри хука admin_menu. Этот хук срабатывает после загрузки ядра, но до рендеринга боковой панели. Базовое подключение:
function sandbox_register_menus() {
add_menu_page( /* ... */ );
add_submenu_page( /* ... */ );
}
add_action( 'admin_menu', 'sandbox_register_menus' );[/codeblock]Приоритет хука (третий параметр add_action) определяет, когда именно ваши меню будут зарегистрированы относительно других плагинов. По умолчанию приоритет равен 10. Если вы хотите, чтобы ваше меню появилось после всех стандартных пунктов, используйте более высокий приоритет:
add_action( 'admin_menu', 'sandbox_register_menus', 99 );[/codeblock]Приоритет 99 гарантирует, что ваш код выполнится после большинства плагинов, и вы сможете переопределить или дополнить уже существующие меню. Если вы разрабатываете плагин, который должен быть загружен до всего остального, используйте приоритет 1.
Условное отображение меню
Иногда меню должно быть видно только определённым пользователям или при выполнении условий. WordPress не предоставляет встроенного механизма условного скрытия меню, кроме проверки capabilities. Однако есть два обходных пути.
Метод 1: Проверка роли пользователя внутри хука. Оберните вызов add_menu_page() в проверку:
function sandbox_conditional_menu() {
$user = wp_get_current_user();
if ( in_array( 'administrator', $user->roles, true ) ) {
add_menu_page( 'Advanced Settings', 'Advanced', 'manage_options', 'advanced-settings', 'advanced_page_html' );
}
}
add_action( 'admin_menu', 'sandbox_conditional_menu' );[/codeblock]Метод 2: Фильтр submenu. WordPress позволяет фильтровать массив подменю перед рендерингом. Это более чистый подход для динамического управления видимостью:
function sandbox_hide_menu_for_editors( $submenu ) {
if ( current_user_can( 'editor' ) && ! current_user_can( 'manage_options' ) ) {
unset( $submenu['themes.php'][10] );
}
return $submenu;
}
add_filter( 'submenu', 'sandbox_hide_menu_for_editors', 99 );[/codeblock]Локализация названий меню
Названия меню должны быть переводимыми. Используйте функции __() или _e() с текстовым доменом вашей темы или плагина:
add_menu_page(
__( 'Sandbox Theme Options', 'sandbox' ),
__( 'Sandbox', 'sandbox' ),
'manage_options',
'sandbox-options',
'sandbox_options_page_html',
'dashicons-admin-generic',
61
);[/codeblock]Текстовый домен должен совпадать с тем, что указан в заголовке темы (Text Domain) или в заголовке главного файла плагина. Без правильно заданного текстового домена ваш плагин не будет распознан системой переводов WordPress.
Проверка прав: какой capability выбрать
Выбор capabilities — это не просто «поставлю manage_options и всё заработает». Неправильный выбор открывает доступ к настройкам пользователям, которые не должны их видеть, или блокирует доступ тем, кому настройки нужны.
| Capability | Кто имеет по умолчанию | Когда использовать |
|---|---|---|
| manage_options | Только Administrator | Критические настройки сайта, темы, плагинов. По умолчанию для большинства страниц опций |
| edit_theme_options | Administrator | Настройки внешнего вида: кастомайзер, виджеты, меню |
| activate_plugins | Administrator | Управление плагинами (активация, деактивация) |
| edit_posts | Administrator, Editor, Author, Contributor | Страницы, связанные с контентом, не с настройками |
| read | Все зарегистрированные пользователи | Информационные страницы, дашборды, отчёты |
| custom_capability | Назначается вручную | Специфичный функционал плагина (управление подписками, модерация) |
function sandbox_advanced_menu_check() {
if ( current_user_can( 'manage_options' ) || current_user_can( 'edit_theme_options' ) ) {
add_menu_page( 'Theme Settings', 'Theme Settings', 'edit_theme_options', 'theme-settings', 'theme_settings_page' );
}
}
add_action( 'admin_menu', 'sandbox_advanced_menu_check' );[/codeblock]Этот паттерн полезен в многоуровневых системах, где часть настроек доступна администратору, а часть — редактору, управляющему контентом. WordPress проверит capabilities при загрузке меню и покажет пункт только тем, кто соответствует хотя бы одному условию.
Кастомные возможности (Custom Capabilities)
Если стандартных capabilities WordPress недостаточно, вы можете создать собственные. Это особенно актуально для плагинов со специфичным функционалом. Регистрация кастомной capability происходит при активации плагина:
function sandbox_add_custom_capability() {
$role = get_role( 'administrator' );
$role->add_cap( 'manage_sandbox_settings' );
}
register_activation_hook( __FILE__, 'sandbox_add_custom_capability' );
function sandbox_remove_custom_capability() {
$role = get_role( 'administrator' );
$role->remove_cap( 'manage_sandbox_settings' );
}
register_deactivation_hook( __FILE__, 'sandbox_remove_custom_capability' );[/codeblock]Динамическое построение меню из нескольких страниц
Когда плагин разрастается, одна страница настроек перестаёт вмещать весь функционал. Типичный паттерн для крупных плагинов — одно меню верхнего уровня с несколькими подменю, каждое из которых ведёт на свою страницу опций:
function sandbox_multi_page_menu() {
add_menu_page(
'Sandbox Pro',
'Sandbox Pro',
'manage_options',
'sandbox-pro',
'sandbox_dashboard_page',
'dashicons-layout',
26
);
add_submenu_page(
'sandbox-pro',
'Dashboard',
'Dashboard',
'manage_options',
'sandbox-pro',
'sandbox_dashboard_page'
);
add_submenu_page(
'sandbox-pro',
'Display Options',
'Display',
'manage_options',
'sandbox-display',
'sandbox_display_page'
);
add_submenu_page(
'sandbox-pro',
'Social Networks',
'Social',
'manage_options',
'sandbox-social',
'sandbox_social_page'
);
add_submenu_page(
'sandbox-pro',
'Import/Export',
'Import/Export',
'manage_options',
'sandbox-import-export',
'sandbox_import_export_page'
);
}
add_action( 'admin_menu', 'sandbox_multi_page_menu' );[/codeblock]Обратите внимание на важную деталь: первый подпункт использует тот же slug ('sandbox-pro'), что и родительское меню. Если slug подменю совпадает с родительским, WordPress не создаёт дублирующий пункт — подменю просто не добавляется. Это стандартный приём для того, чтобы клик по родительскому пункту вёл на страницу Dashboard, а остальные пункты — на соответствующие подстраницы.
Переопределение стандартных страниц через меню
Иногда нужно заменить стандартную страницу WordPress своей реализацией. Например, создать собственный список записей или дашборд с аналитикой. Для этого используется приём с тем же slug, что и у стандартного меню, но с кастомным колбэком:
function sandbox_replace_dashboard() {
add_submenu_page(
'index.php',
'Custom Dashboard',
'Dashboard',
'read',
'index.php',
'sandbox_custom_dashboard'
);
}
add_action( 'admin_menu', 'sandbox_replace_dashboard' );[/codeblock]Этот код заменяет стандартный Dashboard на ваш кастомный, сохраняя при этом оригинальное название пункта меню и его положение. Пользователь не заметит разницы в интерфейсе, но увидит вашу страницу вместо стандартной. Важно: если вы переопределяете критическую страницу вроде Dashboard, убедитесь, что ваша версия не теряет функциональность оригинала — например, виджеты «На виду» или блоки уведомлений об обновлениях.
Особенности меню в мультисайтовых установках WordPress
При работе с WordPress Multisite поведение меню меняется. Некоторые стандартные пункты (Tools, Settings) доступны только суперадмину, а не администратору отдельного сайта. Если ваш плагин должен работать в мультисайтовой среде, учитывайте следующее:
Используйте is_multisite() для проверки окружения и адаптируйте capability в зависимости от контекста. В мультисайте администратор сайта имеет право manage_options, но не manage_network (зарезервировано для суперадмина). Плагин, жёстко требующий manage_network, не будет виден администраторам отдельных сайтов, даже если функционал плагина им нужен:
function sandbox_multisite_menu() {
$capability = is_multisite() ? 'manage_network' : 'manage_options';
add_menu_page(
'Sandbox Network Settings',
'Sandbox',
$capability,
'sandbox-network',
'sandbox_network_page'
);
}
add_action( 'admin_menu', 'sandbox_multisite_menu' );[/codeblock]Пункты меню, зарегистрированные с родителем 'settings.php' (сетевые настройки), отображаются только в сетевой админке и только для суперадмина. Это полезно для создания сетевых страниц конфигурации, которые не должны быть видны администраторам отдельных сайтов.
Проверка корректности регистрации меню
Когда меню не появляется в боковой панели, первое, что нужно проверить — действительно ли WordPress зарегистрировал ваш пункт. Самый быстрый способ: дамп глобального массива $menu в подвале админки:
function sandbox_debug_admin_menu() {
if ( current_user_can( 'manage_options' ) ) {
echo '';
echo '';
}
}
add_action( 'admin_footer', 'sandbox_debug_admin_menu' );[/codeblock]Откройте любую страницу админки как администратор и загляните в исходный HTML-код. Найдите свой slug в дампе массива — если его нет, проблема в хуке admin_menu (проверьте, что add_action действительно вызывает вашу функцию). Если slug есть, но пункт не отображается — проблема в capability: текущий пользователь не соответствует требованиям. Для более продвинутой отладки можно использовать плагин Admin Menu Editor или Query Monitor — оба визуализируют структуру меню и подсказывают, какой capability не хватает для отображения конкретного пункта.
\u{201c}Золотое правило WordPress-разработчика: никогда не жёстко не задавайте manage_options, если страница не управляет критическими настройками сайта. Используйте наименее привилегированную capability, достаточную для выполнения задачи. Это принцип наименьших привилегий в действии.
Типичные ошибки при создании меню
Дублирование slug. Если два плагина используют одинаковый $menu_slug, WordPress добавит суффикс -2, -3 и так далее к тому, что зарегистрирован позже. Это ломает ссылки и проверки на текущую страницу. Всегда используйте префикс вашего плагина или темы в slug: не 'settings', а 'myplugin-settings'.
Отсутствие колбэка. Параметр $callback обязателен. Если вы забыли определить функцию колбэка, WordPress выведет пустую страницу без ошибок. Проверяйте, что имя функции в $callback точно совпадает с определением.
Вызов вне хука admin_menu. Функции меню не сработают, если вызвать их напрямую в functions.php без обёртки add_action('admin_menu', ...). Результат — Call to undefined function или молчаливое игнорирование.
Неверный capability для подменю. Если capability подменю выше, чем у родительского меню, подменю просто не отобразится. WordPress не показывает пункты, к которым у пользователя нет доступа.
Часто задаваемые вопросы по меню WordPress
Чем отличаются add_menu_page и add_submenu_page?
add_menu_page() создаёт новый пункт верхнего уровня в боковой панели админки, такой же как «Записи» или «Настройки». add_submenu_page() добавляет дочерний пункт под существующим меню — стандартным или вашим собственным. Ключевое отличие: add_menu_page требует иконку и позицию, add_submenu_page требует slug родителя.
Обязательно ли указывать иконку для add_menu_page?
Нет, параметр $icon_url опциональный. Если не указать, WordPress использует иконку по умолчанию — пустой кружок. Но я настоятельно рекомендую всегда задавать иконку: она помогает пользователям визуально идентифицировать ваш пункт меню среди десятка других.
Как добавить подменю в стандартное меню WordPress?
Используйте add_submenu_page() с slug родителя, соответствующим стандартному меню: 'index.php' для Консоли, 'themes.php' для Внешнего вида, 'options-general.php' для Настроек и так далее. Slug остальных меню смотрите в таблице выше в этой же статье.
Можно ли изменить порядок уже существующих пунктов меню?
Да, через глобальный массив $menu. Но это считается плохой практикой, так как конфликтует с другими плагинами. Лучше создайте своё меню верхнего уровня и управляйте его позицией через параметр $position — это безопасно и предсказуемо.
Как скрыть стандартный пункт меню от определённых пользователей?
Используйте функцию remove_menu_page() с хуком admin_menu и приоритетом 99. Например: remove_menu_page('tools.php') скроет меню «Инструменты». Оборачивайте вызов в проверку прав: if (!current_user_can('manage_options')) { remove_menu_page('tools.php'); }
Что делать, если два плагина используют одинаковый slug меню?
WordPress автоматически добавляет числовой суффикс (-2, -3...) второму зарегистрированному пункту. Это предотвращает фатальную ошибку, но ломает URL. Лучшая профилактика: всегда используйте префикс плагина или темы в slug — 'myplugin-settings' вместо 'settings'.
Как проверить, на какой странице админки находится пользователь?
Используйте функцию get_current_screen(), которая возвращает объект WP_Screen с полями id и base. Например, для проверки, что пользователь на вашей странице: $screen = get_current_screen(); if ($screen->id === 'toplevel_page_sandbox-options') { ... }
Можно ли добавить меню с SVG-иконкой?
Да, передайте data:image/svg+xml;base64,... строку в параметр $icon_url. SVG должен иметь размеры 20x20px. Убедитесь, что цвет иконки — #9ea3a8 (стандартный серый WordPress), иначе при наведении иконка не изменит цвет на белый.
Как правильно локализовать названия меню?
Оборачивайте $page_title и $menu_title в функцию __() с текстовым доменом: __( 'My Settings', 'my-textdomain' ). Текстовый домен должен быть загружен через load_theme_textdomain() или load_plugin_textdomain() до вызова admin_menu.
В каком хуке вызывать функции создания меню?
Все функции создания меню (add_menu_page, add_submenu_page, add_plugins_page, add_theme_page) должны вызываться внутри хука admin_menu. Без этого хука WordPress не распознает ваши меню, и они просто не появятся в боковой панели.
Как обновить меню без перезагрузки страницы?
Меню админки рендерится при каждом запросе к серверу, поэтому любые изменения в функциях регистрации меню применяются мгновенно после обновления страницы. AJAX-обновление боковой панели не поддерживается стандартным WordPress — для этого потребуется кастомное решение с REST API и JavaScript.



