Страница настроек WordPress: свой плагин без лишних форм
Разбираем, как добавить страницу настроек в админку WordPress 6.x через Settings API: зарегистрировать параметры, вывести поля, сохранить значения и не оставить форму без проверки прав и nonce.

Страница настроек в WordPress должна не просто показывать несколько полей, а корректно проверять права, создавать nonce, очищать ввод и сохранять значения в одной опции. Ниже — рабочий плагин для WordPress 6.x, который добавляет раздел в «Настройки», выводит текстовое поле, email и переключатель. На сборку и проверку такого каркаса понадобится около 20–30 минут.
Что подготовить до начала
Пример рассчитан на WordPress 6.x и PHP 7.4 или новее. Код можно проверить на локальной копии сайта, staging-сервере или отдельном тестовом домене.
- доступ к файлам WordPress или возможность загрузить ZIP-плагин;
- учётную запись с правом
manage_options— обычно это администратор; - текстовый редактор, который сохраняет PHP-файл в UTF-8 без BOM;
- резервную копию сайта перед установкой плагина.
Настройки не стоит записывать напрямую в таблицу базы данных. WordPress уже предоставляет для этого Settings API[1]: он связывает поля формы, проверку запроса, сохранение и отображение сообщений об ошибке.
Settings API или собственная форма
Для обычных параметров плагина используйте Settings API. Самостоятельная обработка POST-запроса нужна только тогда, когда стандартная схема не подходит: например, для сложного мастера настройки, массового импорта или формы, которая не является страницей параметров.
| Подход | Что получаете | Цена | Когда выбирать |
|---|---|---|---|
| Settings API | Регистрацию параметров, nonce, проверку прав, сообщения о сохранении | Нужно разобраться в нескольких хуках и именах идентификаторов | Для обычных текстовых полей, списков, переключателей и числовых параметров |
| Собственная обработка формы | Полный контроль над HTML и сценарием сохранения | Nonce, capability-проверку, очистку и ошибки нужно организовать самостоятельно | Для нестандартных сценариев, где Settings API ограничивает интерфейс |
Главная ошибка страницы настроек — не плохой дизайн, а сохранение данных без проверки того, кто именно отправил запрос и что находится в полях.
Минимальный плагин с рабочей страницей
Создайте файл my-settings-page.php в каталоге wp-content/plugins/my-settings-page/. Вставьте код целиком, активируйте плагин в разделе «Плагины», затем откройте «Настройки» → «Мои настройки».
<?php
/**
* Plugin Name: My Settings Page
* Description: Пример страницы настроек через Settings API.
* Version: 1.0.0
* Requires at least: 6.0
* Requires PHP: 7.4
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
function my_settings_page_add_menu() {
add_options_page(
'Мои настройки',
'Мои настройки',
'manage_options',
'my-settings-page',
'my_settings_page_render'
);
}
add_action( 'admin_menu', 'my_settings_page_add_menu' );
function my_settings_page_register() {
register_setting(
'my_settings_page_group',
'my_settings_page_options',
array(
'type' => 'array',
'sanitize_callback' => 'my_settings_page_sanitize',
'default' => array(
'company_name' => '',
'contact_email' => '',
'enabled' => 0,
),
)
);
add_settings_section(
'my_settings_page_main_section',
'Основные параметры',
'my_settings_page_section_text',
'my-settings-page'
);
add_settings_field(
'company_name',
'Название компании',
'my_settings_page_company_name_field',
'my-settings-page',
'my_settings_page_main_section'
);
add_settings_field(
'contact_email',
'Email для уведомлений',
'my_settings_page_email_field',
'my-settings-page',
'my_settings_page_main_section'
);
add_settings_field(
'enabled',
'Включить функцию',
'my_settings_page_enabled_field',
'my-settings-page',
'my_settings_page_main_section'
);
}
add_action( 'admin_init', 'my_settings_page_register' );
function my_settings_page_sanitize( $input ) {
$output = array();
$output['company_name'] = isset( $input['company_name'] )
? sanitize_text_field( $input['company_name'] )
: '';
$output['contact_email'] = isset( $input['contact_email'] )
? sanitize_email( $input['contact_email'] )
: '';
$output['enabled'] = ! empty( $input['enabled'] ) ? 1 : 0;
return $output;
}
function my_settings_page_section_text() {
echo '<p>Эти значения сохраняются в одной опции WordPress.</p>';
}
function my_settings_page_get_options() {
$defaults = array(
'company_name' => '',
'contact_email' => '',
'enabled' => 0,
);
return wp_parse_args(
get_option( 'my_settings_page_options', array() ),
$defaults
);
}
function my_settings_page_company_name_field() {
$options = my_settings_page_get_options();
?>
<input type="text"
name="my_settings_page_options[company_name]"
value="<?php echo esc_attr( $options['company_name'] ); ?>"
class="regular-text">
<?php
}
function my_settings_page_email_field() {
$options = my_settings_page_get_options();
?>
<input type="email"
name="my_settings_page_options[contact_email]"
value="<?php echo esc_attr( $options['contact_email'] ); ?>"
class="regular-text">
<?php
}
function my_settings_page_enabled_field() {
$options = my_settings_page_get_options();
?>
<label>
<input type="checkbox"
name="my_settings_page_options[enabled]"
value="1"
<?php checked( 1, $options['enabled'] ); ?>>
Активировать функцию
</label>
<?php
}
function my_settings_page_render() {
if ( ! current_user_can( 'manage_options' ) ) {
return;
}
?>
<div class="wrap">
<h1><?php echo esc_html( get_admin_page_title() ); ?></h1>
<form action="options.php" method="post">
<?php
settings_fields( 'my_settings_page_group' );
do_settings_sections( 'my-settings-page' );
submit_button( 'Сохранить настройки' );
?>
</form>
</div>
<?php
}
Что в этом коде связано между собой
add_options_page() добавляет страницу в раздел «Настройки». Его параметр manage_options одновременно ограничивает доступ к меню, но проверка в функции вывода всё равно нужна: страницу нельзя считать защищённой только потому, что ссылка скрыта от части пользователей.
Вызов register_setting() связывает группу my_settings_page_group с опцией my_settings_page_options. В результате три значения хранятся как массив в одной записи. Это проще переносить и удалять, чем набор разрозненных опций.
Имена в HTML имеют вид my_settings_page_options[company_name]. Поэтому обработчик получает массив $input. Функция очистки должна вернуть только ожидаемые ключи, а не сохранять весь входной массив без разбора.
Как проверить результат
- Активируйте плагин. В админке должен появиться пункт «Настройки» → «Мои настройки».
- Введите название компании, email и включите переключатель. Нажмите «Сохранить настройки». WordPress должен вернуть вас на ту же страницу с сообщением о сохранении.
- Обновите страницу. Введённые значения должны остаться в полях, а флажок — сохранить состояние.
- Временно откройте страницу под пользователем без права управлять настройками. Доступ к странице должен быть запрещён.
Почему важны очистка и экранирование
Очистка происходит перед сохранением: sanitize_text_field() убирает недопустимые фрагменты из обычного текста, а sanitize_email() приводит email к безопасному виду. Это не заменяет проверку бизнес-правил. Если email обязателен, одной очистки недостаточно: нужно отдельно решить, что делать с пустым или некорректным значением.
Экранирование происходит при выводе. Для значения внутри атрибута используется esc_attr(), для текста внутри HTML — esc_html(). Не выводите сохранённые параметры напрямую, даже если они уже прошли sanitization: контекст вывода может измениться.
Для обычной страницы настроек не нужно вручную создавать nonce. settings_fields() выводит скрытые поля, необходимые для отправки через options.php. Если вы добавите отдельную форму вне этого механизма, nonce и проверку запроса придётся реализовать самостоятельно.
Что обычно ломается
- Страница не появилась. Проверьте, активирован ли плагин и вызывается ли функция через хук
admin_menu. Пункт добавляется только в административной части WordPress. - Поля видны, но данные не сохраняются. Значения
option_group, имя опции и аргументsettings_fields()должны совпадать по схеме: группа должна быть зарегистрирована черезregister_setting(). - После сохранения флажок всегда выключен. У checkbox нет значения в POST-запросе, если его не отметили. Поэтому в sanitize callback нужно явно превращать отсутствие ключа в
0. - На странице появляется «Sorry, you are not allowed to access this page». У текущего пользователя нет
manage_optionsили capability вadd_options_page()отличается от проверки в callback. - Вместо страницы — белый экран или ошибка PHP. Проверьте синтаксис файла и версию PHP. Если плагин добавлялся через редактор в админке, восстановите файл из резервной копии и включите журналирование на тестовом сайте.
Где этот подход перестаёт быть удобным
Settings API хорошо подходит для нескольких параметров, но не решает все задачи интерфейса. Если в форме десятки повторяющихся строк, загрузка файлов, предпросмотр или многошаговый мастер, стандартные секции быстро превращаются в громоздкую разметку. В такой ситуации сохраняйте тот же принцип безопасности, но рассмотрите отдельный контроллер формы и собственную обработку данных.
Не смешивайте страницу настроек с хранением секретов. API-ключи нельзя показывать в HTML без необходимости и нельзя включать в репозиторий. Для секретных значений используйте отдельную стратегию хранения, ограничьте доступ и не выводите их в диагностические сообщения.
Что делать дальше
Сначала добавьте в пример реальное бизнес-правило: например, обязательную проверку email и понятное сообщение об ошибке. Затем проверьте страницу под ролями с разными capability и посмотрите, что происходит после деактивации и удаления плагина. Для рабочего проекта отдельно спроектируйте миграцию настроек при изменении структуры массива и удаление опции при полном удалении плагина.
[1] Settings API — набор функций WordPress для регистрации параметров, секций и полей административных страниц, а также их сохранения через стандартный обработчик параметров.
Редактор изображений: Убрать лишнее, заменить фон, добавить объект, расширить кадр — на вашем изображении.
Спросить за 20 ₽Источники: Settings API — WordPress Developer Resources, add_options_page() — WordPress Developer Resources
Частые вопросы
Можно ли добавить страницу настроек в верхнее меню админки?
Почему параметры лучше хранить одной опцией?
Нужно ли самостоятельно добавлять nonce в такую форму?
Что произойдёт, если пользователь без прав откроет URL страницы напрямую?
Можно ли использовать этот код на WordPress 5.x?
Как добавить выпадающий список или число?
Материал носит информационный характер и подготовлен редакцией «Агентуры». Он не является офертой, рекламой или индивидуальной консультацией. Упомянутые продукты, компании и торговые знаки принадлежат их правообладателям. Перед принятием решений, влекущих юридические или финансовые последствия, обратитесь к профильному специалисту.