Закладочная навигация в WordPress — организация страниц опций
По мере роста темы или плагина количество настроек неизбежно увеличивается. Три секции на одной странице — терпимо. Десять секций — уже нечитаемо. Пользователь вынужден бесконечно скроллить в поисках нужного поля, теряя контекст и время. Решение, знакомое каждому пользователю десктопных приложений — закладочная навигация (tabs).
WordPress предоставляет готовую CSS-инфраструктуру для создания вкладок в админ-панели. Классы nav-tab-wrapper и nav-tab стилизуют навигацию точно так же, как на страницах «Темы» или «Плагины». Вам остаётся только добавить логику переключения вкладок и привязку к группам опций Settings API. В этой статье мы реализуем полноценную многостраничную панель настроек с двумя вкладками, сохранением состояния активной вкладки и выводом сообщений об успехе через settings_errors().
План реализации
Наша цель — создать страницу опций с двумя вкладками: «Display Options» (настройки отображения) и «Social Networks» (социальные сети). При загрузке страницы активна первая вкладка. После сохранения настроек активная вкладка не сбрасывается — пользователь остаётся там же, где был до нажатия кнопки «Сохранить». При успешном сохранении выводится стандартное уведомление WordPress.
Технический план:
- Создать HTML-структуру вкладок с классами
nav-tab-wrapperиnav-tab - Добавить query-параметр
tabдля идентификации активной вкладки - Проверять параметр
tabв колбэке страницы опций и применять классnav-tab-activeк активной вкладке - Выводить содержимое соответствующей группы опций в зависимости от активной вкладки
- Добавить скрытое поле в форму, чтобы WordPress запомнил активную вкладку при сохранении
- Вызвать
settings_errors()для отображения сообщений об успехе/ошибках
HTML-структура вкладок
WordPress использует два CSS-класса для стилизации вкладок: nav-tab-wrapper — контейнер, объединяющий вкладки в строку, и nav-tab — стиль отдельной вкладки. Активная вкладка дополнительно получает класс nav-tab-active. HTML-структура выглядит так:
Sandbox Theme Options
Display Options Social Networks
Обратите внимание: вкладки — это ссылки <a>, а не кнопки или элементы списка. WordPress стилизует именно такую структуру, и отходить от неё не рекомендуется — вкладки потеряют нативный вид админ-панели.
Определение активной вкладки через query-параметр
Каждая вкладка ведёт на ту же страницу опций, но с разным значением параметра tab в URL: admin.php?page=sandbox-theme-options&tab=display. Колбэк страницы проверяет этот параметр и определяет, какую вкладку подсветить и содержимое какой группы опций показать:
function sandbox_theme_options_page_html() {
if ( ! current_user_can( 'manage_options' ) ) {
return;
}
$active_tab = isset( $_GET['tab'] ) ? sanitize_key( $_GET['tab'] ) : 'display';
?>
sanitize_key() критически важна для безопасности. Параметр $_GET['tab'] приходит от пользователя и может содержать XSS-вектор. sanitize_key() оставляет только буквы, цифры, дефисы и подчёркивания — безопасное подмножество символов.Регистрация секций для разных страниц
Внимательный читатель заметит, что do_settings_sections() вызывается с разными page slug в зависимости от активной вкладки: 'sandbox_display_options_page' и 'sandbox_social_options_page'. Это значит, что секции должны быть зарегистрированы для разных страниц. Вот как выглядит обновлённая функция регистрации:
function sandbox_register_settings() {
register_setting(
'sandbox_options_group',
'sandbox_theme_options',
array(
'type' => 'array',
'sanitize_callback' => 'sandbox_sanitize_options',
'default' => array(
'show_header' => 1,
'show_sidebar' => 1,
'show_footer' => 1,
'facebook_url' => '',
'twitter_url' => '',
),
)
);
add_settings_section(
'sandbox_display_section',
'Display Options',
'sandbox_display_section_callback',
'sandbox_display_options_page'
);
add_settings_field(
'sandbox_show_header', 'Show Header',
'sandbox_checkbox_field_callback',
'sandbox_display_options_page', 'sandbox_display_section',
array( 'label_for' => 'sandbox_show_header', 'option' => 'sandbox_theme_options', 'key' => 'show_header' )
);
add_settings_section(
'sandbox_social_section',
'Social Network Links',
'sandbox_social_section_callback',
'sandbox_social_options_page'
);
add_settings_field(
'sandbox_facebook_url', 'Facebook URL',
'sandbox_url_field_callback',
'sandbox_social_options_page', 'sandbox_social_section',
array( 'label_for' => 'sandbox_facebook_url', 'option' => 'sandbox_theme_options', 'key' => 'facebook_url' )
);
}
add_action( 'admin_init', 'sandbox_register_settings' );[/codeblock]Ключевой момент: все поля по-прежнему принадлежат одной группе опций (sandbox_options_group) и хранятся в одном массиве (sandbox_theme_options). Разделение происходит только на уровне интерфейса — разные секции зарегистрированы для разных page slug. При сохранении формы WordPress обновляет весь массив опций целиком, независимо от того, на какой вкладке была нажата кнопка «Сохранить».
Сохранение состояния вкладки после отправки формы
При нажатии кнопки «Сохранить» WordPress перенаправляет пользователя на URL без query-параметра tab. В результате активная вкладка сбрасывается на значение по умолчанию — пользователь всегда возвращается на первую вкладку после сохранения. Это неудобно: изменил URL соцсетей, сохранил — и оказался на вкладке «Display». Чтобы исправить это, добавим скрытое поле в форму и обработаем его при перенаправлении:
function sandbox_theme_options_page_html() {
if ( ! current_user_can( 'manage_options' ) ) {
return;
}
$active_tab = isset( $_GET['tab'] ) ? sanitize_key( $_GET['tab'] ) : 'display';
?>
Теперь добавим код для перенаправления с сохранением вкладки. WordPress вызывает хук wp_redirect при редиректе после сохранения настроек. Мы перехватим этот редирект и добавим параметр tab:function sandbox_preserve_active_tab( $location ) {
if ( isset( $_POST['sandbox_active_tab'] ) ) {
$location = add_query_arg( 'tab', sanitize_key( $_POST['sandbox_active_tab'] ), $location );
}
return $location;
}
add_filter( 'wp_redirect', 'sandbox_preserve_active_tab' );[/codeblock]Этот фильтр проверяет, было ли отправлено скрытое поле sandbox_active_tab, и если да — добавляет соответствующий query-параметр к URL редиректа. После сохранения пользователь остаётся на той же вкладке, где нажал кнопку «Сохранить».
settings_errors() — сообщения об успехе и ошибках
Функция settings_errors() выводит стандартные уведомления WordPress об успешном сохранении, ошибках валидации или предупреждениях. Вызов должен располагаться до навигации с вкладками, чтобы сообщение было видно всегда. Без неё пользователь не узнает, сохранились ли настройки:
settings_errors( 'sandbox_theme_options' );[/codeblock]WordPress автоматически добавляет сообщение «Settings saved.» при успешном сохранении через Settings API. Кастомные сообщения добавляются через add_settings_error() в функции санитизации:
function sandbox_sanitize_options( $input ) {
$sanitized = array();
if ( isset( $input['facebook_url'] ) && ! empty( $input['facebook_url'] ) ) {
$sanitized['facebook_url'] = esc_url_raw( $input['facebook_url'] );
$parsed = wp_parse_url( $sanitized['facebook_url'] );
if ( ! isset( $parsed['host'] ) || strpos( $parsed['host'], 'facebook.com' ) === false ) {
add_settings_error(
'sandbox_theme_options',
'invalid_facebook_url',
'Facebook URL must point to facebook.com. Your input was not saved.',
'error'
);
$sanitized['facebook_url'] = '';
}
}
return $sanitized;
}[/codeblock]Динамическая подстановка slug страницы в форму
WordPress по умолчанию отправляет форму настроек на options.php. Query-параметр tab теряется при отправке, и WordPress не знает, на какую вкладку вернуть пользователя. Одно из решений — динамически менять action формы, чтобы он включал текущий tab:
$form_action = 'options.php';
if ( $active_tab !== 'display' ) {
$form_action = add_query_arg( 'tab', $active_tab, 'options.php' );
}
echo '


