Wordpresses

Как создать страницу настроек темы WordPress через админку

Если логотип, телефон и ссылки темы приходится менять в коде, удобнее собрать их на отдельной странице админки. В WordPress для этого есть Settings API: он создаёт форму, сохраняет значения и применяет стандартные проверки безопасности. Ниже — пример страницы в разделе «Внешний вид» с полями для логотипа, телефона, email и ссылки.

Код добавьте в functions.php дочерней темы, а не родительской: при обновлении родительской темы её файлы могут быть заменены. Если настройки должны оставаться доступными после смены темы, разместите функциональность в собственном плагине. Пример использует обычные функции WordPress и не требует сторонних плагинов.

Создаём страницу и регистрируем настройки

Добавьте следующий код. Префикс mytheme_ замените на уникальный для вашей темы: это снизит риск конфликта с другим кодом сайта. Страница появится в меню «Внешний вид» у пользователей с правом edit_theme_options.

add_action( 'admin_menu', 'mytheme_add_settings_page' );
function mytheme_add_settings_page() {
    add_theme_page(
        'Настройки темы',
        'Настройки темы',
        'edit_theme_options',
        'mytheme-settings',
        'mytheme_render_settings_page'
    );
}

add_action( 'admin_init', 'mytheme_register_settings' );
function mytheme_register_settings() {
    register_setting(
        'mytheme_settings_group',
        'mytheme_options',
        array( 'sanitize_callback' => 'mytheme_sanitize_options' )
    );

    add_settings_section(
        'mytheme_main_section',
        'Основные данные',
        'mytheme_settings_section_text',
        'mytheme-settings'
    );

    add_settings_field( 'mytheme_logo', 'Логотип', 'mytheme_logo_field', 'mytheme-settings', 'mytheme_main_section' );
    add_settings_field( 'mytheme_phone', 'Телефон', 'mytheme_phone_field', 'mytheme-settings', 'mytheme_main_section' );
    add_settings_field( 'mytheme_email', 'Email', 'mytheme_email_field', 'mytheme-settings', 'mytheme_main_section' );
    add_settings_field( 'mytheme_social_url', 'Ссылка на страницу', 'mytheme_social_url_field', 'mytheme-settings', 'mytheme_main_section' );
}

function mytheme_sanitize_options( $input ) {
    if ( ! is_array( $input ) ) {
        return array();
    }

    return array(
        'logo_id'    => isset( $input['logo_id'] ) ? absint( $input['logo_id'] ) : 0,
        'phone'      => isset( $input['phone'] ) ? sanitize_text_field( $input['phone'] ) : '',
        'email'      => isset( $input['email'] ) ? sanitize_email( $input['email'] ) : '',
        'social_url' => isset( $input['social_url'] ) ? esc_url_raw( $input['social_url'] ) : '',
    );
}

function mytheme_settings_section_text() {
    echo '<p>Укажите данные, которые используются в шапке или подвале сайта.</p>';
}

function mytheme_render_settings_page() {
    ?>
    <div class="wrap">
        <h1>Настройки темы</h1>
        <form action="options.php" method="post">
            <?php
            settings_fields( 'mytheme_settings_group' );
            do_settings_sections( 'mytheme-settings' );
            submit_button();
            ?>
        </form>
    </div>
    <?php
}

add_theme_page() создаёт пункт в «Внешний вид», а register_setting() связывает группу формы с опцией mytheme_options. Форма выводит обязательные служебные поля через settings_fields(); не удаляйте этот вызов — он, в частности, добавляет nonce для проверки отправки. Значения всех полей хранятся вместе в одном массиве. Функция очистки приводит каждый элемент к ожидаемому типу: идентификатор изображения — к целому числу, текст — к безопасной строке, URL — к безопасному адресу.

Добавляем поля и выбор логотипа

К тем же функциям добавьте обработчики полей. Для логотипа используется медиабиблиотека WordPress: в настройке сохраняется ID вложения, а не введённый вручную адрес файла.

function mytheme_get_options() {
    $options = get_option( 'mytheme_options', array() );
    return is_array( $options ) ? $options : array();
}

function mytheme_logo_field() {
    $options = mytheme_get_options();
    $logo_id = isset( $options['logo_id'] ) ? absint( $options['logo_id'] ) : 0;
    ?>
    <input type="hidden" id="mytheme-logo-id" name="mytheme_options[logo_id]" value="<?php echo esc_attr( $logo_id ); ?>">
    <div id="mytheme-logo-preview"><?php if ( $logo_id ) { echo wp_get_attachment_image( $logo_id, 'thumbnail' ); } ?></div>
    <button type="button" class="button" id="mytheme-select-logo">Выбрать логотип</button>
    <button type="button" class="button" id="mytheme-remove-logo">Убрать</button>
    <?php
}

function mytheme_phone_field() {
    $options = mytheme_get_options();
    printf( '<input class="regular-text" type="text" name="mytheme_options[phone]" value="%s">', esc_attr( $options['phone'] ?? '' ) );
}

function mytheme_email_field() {
    $options = mytheme_get_options();
    printf( '<input class="regular-text" type="email" name="mytheme_options[email]" value="%s">', esc_attr( $options['email'] ?? '' ) );
}

function mytheme_social_url_field() {
    $options = mytheme_get_options();
    printf( '<input class="regular-text" type="url" name="mytheme_options[social_url]" value="%s">', esc_attr( $options['social_url'] ?? '' ) );
}

add_action( 'admin_enqueue_scripts', 'mytheme_settings_media' );
function mytheme_settings_media( $hook_suffix ) {
    if ( 'appearance_page_mytheme-settings' !== $hook_suffix ) {
        return;
    }

    wp_enqueue_media();
    wp_enqueue_script( 'jquery' );
    $script = <<<'JS'
jQuery(function($) {
    var frame;
    $('#mytheme-select-logo').on('click', function(event) {
        event.preventDefault();
        if (frame) {
            frame.open();
            return;
        }
        frame = wp.media({
            title: 'Выберите логотип',
            button: { text: 'Использовать логотип' },
            multiple: false,
            library: { type: 'image' }
        });
        frame.on('select', function() {
            var image = frame.state().get('selection').first().toJSON();
            $('#mytheme-logo-id').val(image.id);
            $('#mytheme-logo-preview').html('<img src="' + image.url + '" alt="" style="max-width:180px;height:auto;">');
        });
        frame.open();
    });
    $('#mytheme-remove-logo').on('click', function(event) {
        event.preventDefault();
        $('#mytheme-logo-id').val('0');
        $('#mytheme-logo-preview').empty();
    });
});
JS;
    wp_add_inline_script( 'jquery', $script );
}

Проверка $hook_suffix нужна, чтобы загружать медиабиблиотеку и JavaScript только на странице настроек. Если измените slug mytheme-settings в add_theme_page(), обновите и проверяемое значение: для страницы в разделе «Внешний вид» WordPress формирует hook в виде appearance_page_ плюс slug.

Выводим сохранённые значения в теме

Сохранение настройки само по себе не меняет сайт: шаблон темы должен получить значения и вывести их в нужном месте. Например, в файле шапки можно использовать такой код:

<?php
$options = get_option( 'mytheme_options', array() );
$options = is_array( $options ) ? $options : array();

if ( ! empty( $options['logo_id'] ) ) {
    echo wp_get_attachment_image( absint( $options['logo_id'] ), 'full', false, array( 'class' => 'site-logo' ) );
}

if ( ! empty( $options['phone'] ) ) {
    echo '<p>' . esc_html( $options['phone'] ) . '</p>';
}

if ( ! empty( $options['email'] ) ) {
    echo '<p>' . esc_html( $options['email'] ) . '</p>';
}

if ( ! empty( $options['social_url'] ) ) {
    echo '<a href="' . esc_url( $options['social_url'] ) . '">Наша страница</a>';
}
?>

Вставляйте этот фрагмент в подходящий шаблон, например в файл шапки дочерней темы. Если телефон нужен как ссылка для звонка, оформите его отдельно: для атрибута href="tel:..." понадобится подготовить номер без пробелов и скобок. При выводе текстовых значений используйте экранирование, соответствующее контексту: esc_html() для текста, esc_url() для адреса ссылки, esc_attr() для HTML-атрибутов.

Проверяем страницу и сохраняем данные

Откройте в админке «Внешний вид → Настройки темы», выберите изображение, заполните поля и нажмите «Сохранить изменения». После перезагрузки проверьте, что выбранный логотип и введённые значения остались в форме. Затем откройте страницу сайта, в шаблон которой добавлен код вывода.

Если пункта меню нет, проверьте, что код загрузился без PHP-ошибки, текущий пользователь имеет право edit_theme_options, а код страницы и функции регистрации подключены в активной теме. Если данные сохраняются, но не появляются на сайте, проверьте имя опции и ключи массива в шаблоне: в этом примере это mytheme_options, logo_id, phone, email и social_url.

Опция, созданная через register_setting(), сохраняется в базе WordPress и не удаляется при выключении темы. Но страница админки и код вывода перестанут работать, если отключить тему, в которой они находятся. Для темы, предназначенной для распространения, замените общий префикс на уникальный и не меняйте его между версиями: иначе настройки будут сохранены под старым именем и новая версия их не найдёт.

×
11.11 - выгоднее, чем когда-либо!

Скидка -20% на премиум темы и плагины

Воспользуйся скидкой сейчас