Создание страницы настроек в админке WordPress: полное руководство
Создание страницы настроек в WordPress
Страница настроек позволяет администраторам изменять параметры сайта без редактирования кода. В WordPress существует несколько подходов к её реализации. Наиболее эффективным и рекомендуемым является использование встроенного Settings API, который автоматизирует регистрацию, вывод и сохранение полей.
Эффективное решение: Settings API с add_options_page
Как создать стандартную страницу настроек с группами полей и сохранением через Settings API?
Этот метод использует add_options_page() для добавления пункта в меню «Настройки», register_setting() для регистрации опции, add_settings_section() и add_settings_field() для группировки полей.
// Файл functions.php
// 1. Добавляем страницу настроек
add_action('admin_menu', function() {
add_options_page(
'Основные настройки', // заголовок страницы
'Настройки темы', // название пункта меню
'manage_options', // права доступа
'my-theme-settings', // slug страницы
'my_theme_settings_page' // функция вывода
);
});
// 2. Регистрируем опции, секции и поля
add_action('admin_init', function() {
// Регистрация одной опции (хранится в wp_options как массив)
register_setting('my-theme-settings-group', 'my_theme_options', 'my_sanitize_callback');
// Добавляем секцию
add_settings_section(
'my_theme_main_section',
'Основная секция',
'my_section_callback',
'my-theme-settings'
);
// Добавляем поле (текст)
add_settings_field(
'site_title',
'Заголовок сайта',
'my_text_field_callback',
'my-theme-settings',
'my_theme_main_section',
['label_for' => 'site_title', 'option_name' => 'my_theme_options']
);
// Добавляем поле (чекбокс)
add_settings_field(
'show_footer',
'Показывать футер',
'my_checkbox_field_callback',
'my-theme-settings',
'my_theme_main_section',
['label_for' => 'show_footer', 'option_name' => 'my_theme_options']
);
});
// Функция вывода страницы
function my_theme_settings_page() {
?>
<? echo esc_html(get_admin_page_title()); ?>
<?
}
// Коллбеки для вывода полей
function my_text_field_callback($args) {
$options = get_option($args['option_name']);
$value = isset($options[$args['label_for']]) ? $options[$args['label_for']] : '';
echo '<input type="text" id="' . esc_attr($args['label_for']) . '" name="' . esc_attr($args['option_name']) . '[' . esc_attr($args['label_for']) . ']" value="' . esc_attr($value) . '" class="regular-text" />';
}
function my_checkbox_field_callback($args) {
$options = get_option($args['option_name']);
$checked = isset($options[$args['label_for']]) && $options[$args['label_for']] == 1 ? 'checked' : '';
echo '<input type="checkbox" id="' . esc_attr($args['label_for']) . '" name="' . esc_attr($args['option_name']) . '[' . esc_attr($args['label_for']) . ']" value="1" ' . $checked . ' />';
}
// Функция санитизации (валидации)
function my_sanitize_callback($input) {
$output = array();
foreach ($input as $key => $value) {
switch ($key) {
case 'site_title':
$output[$key] = sanitize_text_field($value);
break;
case 'show_footer':
$output[$key] = absint($value);
break;
default:
$output[$key] = sanitize_text_field($value);
}
}
return $output;
}
Wp admin options php (страница настроек в админке wordpress)
Пояснение шагов:
- Хук admin_menu добавляет страницу настроек в раздел «Настройки».
- Хук admin_init регистрирует опцию, секции и поля.
- Функция register_setting() связывает опцию с группой опций для автоматического сохранения.
- do_settings_sections() выводит все зарегистрированные секции и поля.
- Форма отправляется на options.php, который обрабатывает сохранение через Settings API.
- Функция санитизации фильтрует входные данные перед сохранением.
Возможные проблемы:
- Ошибка «Нет прав доступа» – укажите правильную capability (обычно manage_options).
- Поля не сохраняются – проверьте, что имя поля в массиве совпадает с ключом опции.
- После сохранения пустые значения – функция санитизации может обнулять данные, проверьте логику.
- Конфликты с другими плагинами – используйте уникальные имена опций (желательно с префиксом).
Вариант 1: Страница настроек в собственном пункте меню
Как разместить страницу настроек не в разделе «Настройки», а в отдельном пункте главного меню?
Вместо add_options_page() используйте add_menu_page(). Остальная логика Settings API остаётся неизменной.
add_action('admin_menu', function() {
add_menu_page(
'Специальные настройки',
'Мои настройки',
'manage_options',
'my-custom-settings',
'my_custom_settings_page',
'dashicons-admin-generic',
30
);
});
Admin post new php (создание нового поста в админке wordpress)
Параметр $position (30) определяет порядок в меню. Для вывода формы используйте ту же структуру с settings_fields() и do_settings_sections(). Slug страницы должен совпадать с третьим параметром add_menu_page().
Типичные ошибки:
- Страница не отображается – проверьте, что функция вывода определена и не содержит синтаксических ошибок.
- Дублирование пунктов меню – убедитесь, что хук admin_menu не вызывается несколько раз.
Вариант 2: Ручная обработка формы без Settings API
Как реализовать страницу настроек с отправкой данных на свой обработчик, минуя options.php?
Этот подход даёт полный контроль, но требует ручной проверки nonce, прав доступа и сохранения. Подходит для сложной логики или нестандартного хранения.
add_action('admin_menu', function() {
add_options_page('Ручные настройки', 'Ручные', 'manage_options', 'manual-settings', 'manual_settings_page');
});
function manual_settings_page() {
// Обработка сохранения при POST запросе
if (isset($_POST['manual_save']) && check_admin_referer('manual_nonce_action', 'manual_nonce')) {
if (current_user_can('manage_options')) {
$value = sanitize_text_field($_POST['custom_option']);
update_option('manual_custom_option', $value);
echo '<div class="notice notice-success"><p>Настройки сохранены.</p></div>';
}
}
$current = get_option('manual_custom_option', '');
?>
Ручные настройки
<?
}
Wp login php action (действие логина wordpress)
В этом примере данные отправляются на ту же страницу, проверяется nonce и capability, затем опция обновляется вручную через update_option().
Проблемы при ручном подходе:
- Отсутствие автоматической валидации – легко допустить XSS, если не санитизировать.
- Нет встроенных сообщений об успехе/ошибке – нужно реализовывать самостоятельно.
- При редиректе данные могут потеряться – используйте перенаправление с сообщением через transient.
Вариант 3: Использование ACF (Advanced Custom Fields)
Как быстро создать страницу настроек с визуальным интерфейсом через плагин ACF?
Плагин ACF включает функционал «Страницы опций». После активации добавьте поле Options Page через интерфейс или код. Пример регистрации страницы опций:
if (function_exists('acf_add_options_page')) {
acf_add_options_page(array(
'page_title' => 'Настройки темы',
'menu_title' => 'Настройки темы',
'menu_slug' => 'theme-options',
'capability' => 'manage_options',
'redirect' => false
));
}
Admin post php (администрирование post в php)
Затем в админке появится новый пункт. Поля настраиваются через стандартный интерфейс ACF. Значения получаются через get_field('field_name', 'option').
Недостатки:
- Зависимость от стороннего плагина.
- Меньше гибкости в кастомизации поведения (например, сложно добавить произвольные скрипты).
Вариант 4: Современная страница на React (REST API)
Как создать страницу настроек с использованием React и REST API WordPress для динамического интерфейса?
Для этого регистрируется кастомный endpoint REST API, а в админке подключается React-приложение через wp_enqueue_script(). Пример минимальной настройки:
// Регистрация REST маршрута
add_action('rest_api_init', function() {
register_rest_route('mytheme/v1', '/settings', array(
'methods' => 'GET',
'callback' => 'my_get_settings',
'permission_callback' => function() { return current_user_can('manage_options'); }
));
register_rest_route('mytheme/v1', '/settings', array(
'methods' => 'POST',
'callback' => 'my_update_settings',
'permission_callback' => function() { return current_user_can('manage_options'); }
));
});
function my_get_settings() {
return rest_ensure_response(get_option('my_react_options', []));
}
function my_update_settings(WP_REST_Request $request) {
$params = $request->get_json_params();
update_option('my_react_options', $params);
return rest_ensure_response(['status' => 'ok']);
}
После этого создаётся React-компонент, который загружается через wp-admin с помощью wp_set_script_translations() и wp_localize_script().
Сложности:
- Требуется настройка сборки Webpack или другого бандлера.
- Необходимо обрабатывать ошибки сети и аутентификации.
- Не подходит для простых проектов из-за избыточности.
Расширенные примеры использования
Пример с валидацией, несколькими секциями и типами полей
Ниже представлен полный код страницы настроек с тремя секциями: текст, медиа, выбор. Используются поля: текст, textarea, медиа (через Media Uploader), select, чекбоксы.
// functions.php
add_action('admin_menu', function() {
add_options_page('Продвинутые настройки', 'Продвинутые', 'manage_options', 'advanced-settings', 'advanced_settings_page');
});
add_action('admin_init', function() {
register_setting('advanced-settings-group', 'advanced_options', 'advanced_sanitize');
// Секция 1 - Основные
add_settings_section('advanced_main', 'Основные параметры', '', 'advanced-settings');
add_settings_field('header_text', 'Текст в шапке', 'field_text', 'advanced-settings', 'advanced_main', ['id' => 'header_text']);
add_settings_field('footer_text', 'Текст в подвале', 'field_textarea', 'advanced-settings', 'advanced_main', ['id' => 'footer_text']);
// Секция 2 - Медиа
add_settings_section('advanced_media', 'Медиафайлы', '', 'advanced-settings');
add_settings_field('logo_url', 'Логотип (URL)', 'field_media', 'advanced-settings', 'advanced_media', ['id' => 'logo_url']);
// Секция 3 - Дополнительно
add_settings_section('advanced_extra', 'Дополнительные опции', '', 'advanced-settings');
add_settings_field('color_scheme', 'Цветовая схема', 'field_select', 'advanced-settings', 'advanced_extra', ['id' => 'color_scheme']);
add_settings_field('enable_analytics', 'Включить аналитику', 'field_checkbox', 'advanced-settings', 'advanced_extra', ['id' => 'enable_analytics']);
});
function advanced_settings_page() {
?>
Продвинутые настройки
<?
}
// Поле текст
function field_text($args) {
$options = get_option('advanced_options');
$value = isset($options[$args['id']]) ? $options[$args['id']] : '';
echo '<input type="text" id="' . esc_attr($args['id']) . '" name="advanced_options[' . esc_attr($args['id']) . ']" value="' . esc_attr($value) . '" class="regular-text" />';
}
// Поле textarea
function field_textarea($args) {
$options = get_option('advanced_options');
$value = isset($options[$args['id']]) ? $options[$args['id']] : '';
echo '<textarea id="' . esc_attr($args['id']) . '" name="advanced_options[' . esc_attr($args['id']) . ']" rows="5" cols="50" class="large-text">' . esc_textarea($value) . '</textarea>';
}
// Поле медиа (с кнопкой выбора)
function field_media($args) {
$options = get_option('advanced_options');
$value = isset($options[$args['id']]) ? $options[$args['id']] : '';
?>
<input type="text" id="<?php echo esc_attr($args['id']); ?>" name="advanced_options[<?php echo esc_attr($args['id']); ?>]" value="<?php echo esc_url($value); ?>" class="regular-text" />
<button type="button" class="button upload-media-button" data-target="<?php echo esc_attr($args['id']); ?>">Выбрать изображение
<script>
jQuery(document).ready(function($) {
$('.upload-media-button').click(function(e) {
e.preventDefault();
var target = $(this).data('target');
var frame = wp.media({
title: 'Выберите изображение',
button: { text: 'Использовать' },
multiple: false
});
frame.on('select', function() {
var attachment = frame.state().get('selection').first().toJSON();
$('#' + target).val(attachment.url);
});
frame.open();
});
});
</script>
<?
}
// Поле select
function field_select($args) {
$options = get_option('advanced_options');
$selected = isset($options[$args['id']]) ? $options[$args['id']] : 'light';
$choices = array('light' => 'Светлая', 'dark' => 'Тёмная', 'custom' => 'Пользовательская');
echo '<select id="' . esc_attr($args['id']) . '" name="advanced_options[' . esc_attr($args['id']) . ']">';
foreach ($choices as $val => $label) {
echo '<option value="' . esc_attr($val) . '" ' . selected($selected, $val, false) . '>' . esc_html($label) . '</option>';
}
echo '</select>';
}
// Поле чекбокс
function field_checkbox($args) {
$options = get_option('advanced_options');
$checked = isset($options[$args['id']]) && $options[$args['id']] == 1 ? 'checked' : '';
echo '<input type="checkbox" id="' . esc_attr($args['id']) . '" name="advanced_options[' . esc_attr($args['id']) . ']" value="1" ' . $checked . ' />';
}
// Санитизация
function advanced_sanitize($input) {
$output = array();
$output['header_text'] = isset($input['header_text']) ? sanitize_text_field($input['header_text']) : '';
$output['footer_text'] = isset($input['footer_text']) ? sanitize_textarea_field($input['footer_text']) : '';
$output['logo_url'] = isset($input['logo_url']) ? esc_url_raw($input['logo_url']) : '';
$output['color_scheme'] = isset($input['color_scheme']) && in_array($input['color_scheme'], ['light','dark','custom']) ? $input['color_scheme'] : 'light';
$output['enable_analytics'] = isset($input['enable_analytics']) ? 1 : 0;
return $output;
}
Результат: После сохранения в таблице wp_options появится запись с ключом advanced_options и массивом значений.
// Пример сохранённых данных (сериализованный массив)
a:5:{s:11:"header_text";s:13:"Добро пожаловать";s:11:"footer_text";s:9:"2025 год";s:8:"logo_url";s:59:"http://example.com/wp-content/uploads/2025/01/logo.png";s:12:"color_scheme";s:5:"light";s:16:"enable_analytics";i:1;}
Добавление сообщений об ошибках через add_settings_error
Можно отображать кастомные сообщения после сохранения, используя add_settings_error() и settings_errors().
function advanced_sanitize($input) {
// ... валидация
if ( empty($input['header_text']) ) {
add_settings_error('advanced_options', 'header_empty', 'Поле заголовка не должно быть пустым.', 'error');
}
// ...
return $output;
}
function advanced_settings_page() {
?>
Продвинутые настройки
<? settings_errors('advanced_options'); // вывод ошибок ?>
<?
}
Использование кастомной таблицы для хранения настроек
Вместо wp_options можно хранить настройки в отдельной таблице БД. Пример:
// Создание таблицы при активации темы/плагина
function create_custom_settings_table() {
global $wpdb;
$table_name = $wpdb->prefix . 'my_settings';
$charset_collate = $wpdb->get_charset_collate();
$sql = "CREATE TABLE IF NOT EXISTS $table_name (
id mediumint(9) NOT NULL AUTO_INCREMENT,
setting_name varchar(255) NOT NULL,
setting_value text NOT NULL,
PRIMARY KEY (id)
) $charset_collate;";
require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
dbDelta($sql);
}
register_activation_hook(__FILE__, 'create_custom_settings_table');
// Функции для сохранения/получения
function my_custom_setting_get($name) {
global $wpdb;
$table = $wpdb->prefix . 'my_settings';
$row = $wpdb->get_row($wpdb->prepare("SELECT setting_value FROM $table WHERE setting_name = %s", $name));
return $row ? $row->setting_value : false;
}
function my_custom_setting_update($name, $value) {
global $wpdb;
$table = $wpdb->prefix . 'my_settings';
$exists = $wpdb->get_var($wpdb->prepare("SELECT COUNT(*) FROM $table WHERE setting_name = %s", $name));
if ($exists) {
$wpdb->update($table, array('setting_value' => $value), array('setting_name' => $name));
} else {
$wpdb->insert($table, array('setting_name' => $name, 'setting_value' => $value));
}
}
// Использование в обработчике
function my_save_handler() {
if ( isset($_POST['custom_field']) ) {
my_custom_setting_update('custom_field', sanitize_text_field($_POST['custom_field']));
}
}
Преимущества: Производительность при большом количестве настроек, возможность индексирования, изоляция от других опций. Недостатки: Нужно создавать таблицу, нет встроенного кэширования WordPress, больше кода.