Создание меню в админке WordPress — полное руководство

Одним из ключевых этапов в освоении WordPress API является знакомство с системой меню административной панели. Меню — это точка входа пользователя в функционал вашей темы или плагина. Без правильно настроенного меню страница опций, которую вы создали через Settings API, будет недоступна. Пользователь просто не сможет найти её в админке.

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

Не путайте меню админки с навигационным меню сайта. Меню админки — это левая боковая панель в консоли WordPress. Навигационное меню настраивается через Appearance → Menus и отвечает за ссылки на фронтенде.

Четыре типа меню в 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_titlestringДаЗаголовок страницы (в теге <title>)
$menu_titlestringДаНазвание пункта в боковом меню
$capabilitystringДаПраво, необходимое для доступа (обычно manage_options)
$menu_slugstringДаУникальный slug пункта меню (используется в URL)
$callbackcallableДаФункция, выводящая содержимое страницы
$icon_urlstringНетURL иконки или dashicon-класс
$positionintНетПозиция в меню (чем меньше число, тем выше)

Базовый пример добавления меню верхнего уровня:

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; } ?>

Всегда проверяйте права пользователя в колбэке страницы через current_user_can(). Без этой проверки любой зарегистрированный пользователь, угадавший URL админ-страницы, сможет получить к ней доступ.

Иконки меню: 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]
С версии WordPress 4.0 параметр $icon_url принимает название dashicon-класса без префикса 'dashicons-' — просто 'admin-generic'. Но я рекомендую всегда указывать полный класс для совместимости со старыми версиями и большей явности кода.

Позиционирование меню

Параметр $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 последнего зарегистрированного пункта.

Не используйте позицию 2 (Консоль) и позицию ниже 1. Позиция 1 и ниже зарезервированы для разделителей меню. Ваш пункт может просто не отобразиться.

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.phpread
Записиedit.phpedit_posts
Медиафайлыupload.phpupload_files
Страницыedit.php?post_type=pageedit_pages
Внешний видthemes.phpswitch_themes
Плагиныplugins.phpactivate_plugins
Пользователиusers.phplist_users
Инструментыtools.phpedit_posts
Настройкиoptions-general.phpmanage_options
При добавлении подменю к стандартному пункту WordPress не обязательно указывать capability выше, чем у родителя. Укажите manage_options для страниц настроек, edit_posts для инструментов — и WordPress сам проверит, имеет ли пользователь доступ к родительскому меню.

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]
Проверка ролей через in_array срабатывает корректно, но помните: возможности (capabilities) надёжнее, чем роли. Роль можно переименовать, возможность — нет. По возможности используйте current_user_can(), а не проверку роли.

Метод 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_optionsAdministratorНастройки внешнего вида: кастомайзер, виджеты, меню
activate_pluginsAdministratorУправление плагинами (активация, деактивация)
edit_postsAdministrator, Editor, Author, ContributorСтраницы, связанные с контентом, не с настройками
readВсе зарегистрированные пользователиИнформационные страницы, дашборды, отчёты
custom_capabilityНазначается вручнуюСпецифичный функционал плагина (управление подписками, модерация)
Ещё более тонкая настройка достигается через проверку нескольких capabilities одновременно. Например, страница должна быть доступна только администраторам и редакторам с правом управления опциями:

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]
Кастомные capabilities не удаляются автоматически при деактивации плагина. Если не вызвать remove_cap() в хуке деактивации, capability останется в базе данных навсегда. Это не критично, но замусоривает таблицу wp_options.

Динамическое построение меню из нескольких страниц

Когда плагин разрастается, одна страница настроек перестаёт вмещать весь функционал. Типичный паттерн для крупных плагинов — одно меню верхнего уровня с несколькими подменю, каждое из которых ведёт на свою страницу опций:

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]
В мультисайте capability суперадмина проверяется через is_super_admin(), а не через current_user_can(). Это важное различие, которое часто упускают при портировании плагина из одиночной установки.

Пункты меню, зарегистрированные с родителем '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 не показывает пункты, к которым у пользователя нет доступа.

Для отладки меню используйте плагин Admin Menu Editor или временно выведите дамп глобальной переменной $menu: добавьте add_action('admin_footer', function() { echo ''; });

Часто задаваемые вопросы по меню 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.