Settings API WordPress: страница настроек темы с нуля
← Блог
WordPress · 05.10.2026 · 7 мин чтения

Settings API WordPress: страница настроек темы с нуля

Settings API позволяет создать страницу настроек WordPress без дополнительной библиотеки. Он связывает форму в админке с сохранением значений в базе и проверкой прав пользователя.

Соберём страницу настроек темы с тремя полями. Значения будут храниться в одной опции-массиве, проходить проверку при сохранении и выводиться в шаблоне.

Как устроен Settings API

  • register_setting() объявляет группу, тип и функцию очистки опции. Значение хранится в wp_options после сохранения; сама регистрация не создаёт строку со значением.
  • add_settings_section() и add_settings_field() описывают, из каких разделов и полей состоит страница.
  • Форма отправляется на options.php. WordPress сам проверяет nonce и права, вызывает функцию очистки, сохраняет опцию и возвращает на страницу с сообщением.

В примере три значения объединены в одну опцию-массив. Код добавляй в functions.php или вынеси в inc/settings.php и подключи его из functions.php. Все фрагменты ниже — части одного примера.

function mytheme_add_settings_page() {
    add_theme_page(
        'Настройки темы',              // заголовок страницы
        'Настройки темы',              // пункт меню
        'edit_theme_options',          // право доступа
        'mytheme-settings',            // ярлык страницы
        'mytheme_render_settings_page' // функция вывода
    );
}
add_action( 'admin_menu', 'mytheme_add_settings_page' );

add_theme_page() добавляет пункт в «Внешний вид» — логичное место для настроек темы. Для настроек плагина обычно используют add_options_page(): пункт появится в разделе «Настройки», а правом доступа будет manage_options.

2. Регистрация опции, раздела и полей

function mytheme_settings_init() {
    register_setting( 'mytheme_settings', 'mytheme_options', array(
        'type'              => 'array',
        'sanitize_callback' => 'mytheme_sanitize_options',
        'default'           => array(),
    ) );

    add_settings_section(
        'mytheme_contacts',
        'Контакты',
        'mytheme_render_contacts_section',
        'mytheme-settings'
    );

    add_settings_field( 'phone', 'Телефон', 'mytheme_render_text_field', 'mytheme-settings', 'mytheme_contacts', array(
        'key'       => 'phone',
        'type'      => 'tel',
        'label_for' => 'mytheme-phone',
    ) );

    add_settings_field( 'telegram', 'Telegram', 'mytheme_render_text_field', 'mytheme-settings', 'mytheme_contacts', array(
        'key'       => 'telegram',
        'type'      => 'url',
        'label_for' => 'mytheme-telegram',
    ) );

    add_settings_field( 'footer_text', 'Текст в подвале', 'mytheme_render_textarea_field', 'mytheme-settings', 'mytheme_contacts', array(
        'key'       => 'footer_text',
        'label_for' => 'mytheme-footer-text',
    ) );
}
add_action( 'admin_init', 'mytheme_settings_init' );

// Страница принадлежит «Внешнему виду», поэтому сохранять её может тот же круг пользователей.
function mytheme_settings_capability() {
    return 'edit_theme_options';
}
add_filter( 'option_page_capability_mytheme_settings', 'mytheme_settings_capability' );
  • Первый аргумент register_setting() — группа настроек. Её же получит settings_fields() в форме. Второй аргумент — имя опции в базе.
  • Четвёртый аргумент разделов и полей — ярлык страницы из add_theme_page(). По нему do_settings_sections() найдёт, что выводить.
  • label_for превращает название поля в <label for="…">. Клик по подписи ставит курсор в поле, а экранные дикторы читают подпись вместе с полем.
  • По умолчанию options.php сохраняет любую группу только для пользователей с правом manage_options. Фильтр option_page_capability_{группа} меняет право на то, которое указано у пункта меню.

3. HTML-поля и чтение настроек

function mytheme_get_option( $key, $default = '' ) {
    $options = get_option( 'mytheme_options', array() );
    return isset( $options[ $key ] ) ? $options[ $key ] : $default;
}

function mytheme_render_contacts_section() {
    echo '<p>Контакты выводятся в шапке и подвале сайта.</p>';
}

function mytheme_render_text_field( $args ) {
    printf(
        '<input type="%1$s" id="%2$s" name="mytheme_options[%3$s]" value="%4$s" class="regular-text">',
        esc_attr( $args['type'] ),
        esc_attr( $args['label_for'] ),
        esc_attr( $args['key'] ),
        esc_attr( mytheme_get_option( $args['key'] ) )
    );
}

function mytheme_render_textarea_field( $args ) {
    printf(
        '<textarea id="%1$s" name="mytheme_options[%2$s]" rows="4" class="large-text">%3$s</textarea>',
        esc_attr( $args['label_for'] ),
        esc_attr( $args['key'] ),
        esc_textarea( mytheme_get_option( $args['key'] ) )
    );
}

Имена полей вида mytheme_options[phone] PHP собирает в массив, и он целиком попадает в одну опцию. mytheme_get_option() пригодится и в шаблонах: она возвращает значение по ключу или пустую строку, если настройку ещё не сохраняли.

4. Форма сохранения настроек

function mytheme_render_settings_page() {
    if ( ! current_user_can( 'edit_theme_options' ) ) {
        return;
    }
    ?>
    <div class="wrap">
        <h1><?php echo esc_html( get_admin_page_title() ); ?></h1>
        <?php settings_errors(); ?>
        <form action="options.php" method="post">
            <?php
            settings_fields( 'mytheme_settings' );
            do_settings_sections( 'mytheme-settings' );
            submit_button();
            ?>
        </form>
    </div>
    <?php
}
  • settings_fields() выводит скрытые поля группы и действия, nonce и служебное поле с адресом исходной страницы.
  • do_settings_sections() выводит разделы и поля таблицей в стиле админки.
  • settings_errors() показывает «Настройки сохранены» и ошибки проверки. На страницах раздела «Настройки» WordPress выводит их сам, а в «Внешнем виде» и в своих разделах меню без этого вызова сообщений не будет.

5. Проверка и очистка значений

Функция очистки принимает данные формы и возвращает массив для сохранения. Собери его только из ожидаемых ключей: посторонние значения не должны попадать в опцию.

Для каждого поля отдельно задай правило. Например, текст очищается от разметки, URL проверяется как адрес, а неверный телефон сохранять не нужно.

function mytheme_sanitize_options( $input ) {
    $input = is_array( $input ) ? $input : array();

    $clean = array(
        'phone'       => sanitize_text_field( $input['phone'] ?? '' ),
        'telegram'    => esc_url_raw( $input['telegram'] ?? '' ),
        'footer_text' => sanitize_textarea_field( $input['footer_text'] ?? '' ),
    );

    if ( '' !== $clean['phone'] && ! preg_match( '/^[\d\s()+-]{6,20}$/', $clean['phone'] ) ) {
        add_settings_error(
            'mytheme_options',
            'mytheme-phone',
            'Телефон может содержать только цифры, пробелы, скобки, плюс и дефис.'
        );
        $clean['phone'] = mytheme_get_option( 'phone' );
    }

    return $clean;
}
  • sanitize_text_field() убирает теги и переводы строк, sanitize_textarea_field() — теги, но сохраняет переводы строк.
  • esc_url_raw() очищает URL и отсекает недопустимые протоколы. Она не проверяет, существует ли страница по этому адресу.
  • Если телефон не прошёл проверку, функция показывает ошибку через add_settings_error() и оставляет прежнее значение. Остальные поля при этом сохраняются.

6. Вывод настроек в шаблоне темы

<?php
$phone       = mytheme_get_option( 'phone' );
$telegram    = mytheme_get_option( 'telegram' );
$footer_text = mytheme_get_option( 'footer_text' );
?>

<?php if ( $phone ) : ?>
    <a href="tel:<?php echo esc_attr( preg_replace( '/[^\d+]/', '', $phone ) ); ?>"><?php echo esc_html( $phone ); ?></a>
<?php endif; ?>

<?php if ( $telegram ) : ?>
    <a href="<?php echo esc_url( $telegram ); ?>">Telegram</a>
<?php endif; ?>

<?php if ( $footer_text ) : ?>
    <p class="footer-text"><?php echo nl2br( esc_html( $footer_text ) ); ?></p>
<?php endif; ?>

Для ссылки tel: из номера убираются пробелы, скобки и дефисы, а на экране он остаётся в привычном виде. nl2br( esc_html() ) сохраняет переводы строк из текстового поля и не пропускает HTML.

Когда выбрать другой способ

  • В классической теме настройки внешнего вида можно вынести в Customizer («Внешний вид → Настроить») с предпросмотром. В блочной теме для оформления обычно используют редактор сайта и глобальные стили. Так, например, настраивается логотип — об этом статья о кастомном логотипе.
  • Если полей много, нужны картинки, повторяющиеся блоки или вкладки, быстрее собрать страницу на Carbon Fields: Container::make( 'theme_options', 'Настройки темы' ), а читать значения через carbon_get_theme_option(). Как подключить библиотеку, описано в статье о метабоксах.
  • Settings API хорош, когда полей немного и не хочется зависимостей: это часть ядра, и работать он будет в любой теме.

Документация

Есть вопрос или дополнение?

Обсудить в Telegram

Добавить комментарий