Создание страницы настроек в админке WordPress: полное руководство

Раздел: Веб-разработка -> Администрирование 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()); ?>

<? settings_fields('my-theme-settings-group'); // скрытые поля безопасности do_settings_sections('my-theme-settings'); // вывод секций и полей submit_button('Сохранить'); ?>
<? } // Коллбеки для вывода полей 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)

Пояснение шагов:

  1. Хук admin_menu добавляет страницу настроек в раздел «Настройки».
  2. Хук admin_init регистрирует опцию, секции и поля.
  3. Функция register_setting() связывает опцию с группой опций для автоматического сохранения.
  4. do_settings_sections() выводит все зарегистрированные секции и поля.
  5. Форма отправляется на options.php, который обрабатывает сохранение через Settings API.
  6. Функция санитизации фильтрует входные данные перед сохранением.

Возможные проблемы:

  • Ошибка «Нет прав доступа» – укажите правильную 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_nonce_field('manual_nonce_action', 'manual_nonce'); ?>
<input type="text" id="custom_option" name="custom_option" value="<?php echo esc_attr($current); ?>" class="regular-text" />
<?php submit_button('Сохранить', 'primary', 'manual_save'); ?>
<? }

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() {
    ?>
    

Продвинутые настройки

<? settings_fields('advanced-settings-group'); do_settings_sections('advanced-settings'); submit_button(); ?>
<? } // Поле текст 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, больше кода.

Страница настроек в админке WordPress - comments

En
Wp admin options php (php)