После освоения пяти базовых типов ввода в WordPress Settings API, следующий логический шаг — изучение вспомогательных функций и шаблонов отрисовки, которые делают эти поля ввода готовыми к промышленному использованию. Это руководство фокусируется на трёх областях, в которых разработчики среднего уровня часто ошибаются: правильное подключение чекбоксов с функцией checked(), построение группированных наборов радиокнопок и создание выпадающих списков, корректно восстанавливающих сохранённое состояние с помощью функции selected(). Также рассматриваются группированные поля ввода — шаблон организации связанных полей, которые логически объединены.
Вспомогательные функции WordPress
WordPress предоставляет три вспомогательные функции, специально разработанные для поддержания состояния формы при перезагрузке страницы. Эти функции сравнивают эталонное значение с сохранённым и выводят соответствующий HTML-атрибут. Они устраняют утомительный и подверженный ошибкам процесс ручного написания условных атрибутов checked или selected.
| Функция | Сигнатура | Вывод при совпадении | Используется с |
|---|---|---|---|
| checked() | checked($checked, $current, $echo = true) | checked='checked' | <input type="checkbox"> и <input type="radio"> |
| selected() | selected($selected, $current, $echo = true) | selected='selected' | <option> внутри <select> |
| disabled() | disabled($disabled, $current, $echo = true) | disabled='disabled' | Любой элемент формы, когда он должен быть неинтерактивным |
Все три функции следуют одному шаблону: сравнить первый аргумент со вторым, и если они совпадают — вывести соответствующий HTML-атрибут. Третий аргумент управляет тем, выводит ли функция результат напрямую или возвращает его как строку. В большинстве случаев вам нужно поведение по умолчанию — вывод — внутри ваших PHP-шаблонов.
| Сценарий | Функция | Пример вызова | Результат при совпадении |
|---|---|---|---|
| Отметка чекбокса | checked() | checked(1, get_option('my_checkbox')) | checked='checked' |
| Выбор радиокнопки | checked() | checked('left', get_option('layout')) | checked='checked' |
| Выбор пункта select | selected() | selected('roboto', get_option('font')) | selected='selected' |
| Блокировка поля | disabled() | disabled('locked', get_option('status')) | disabled='disabled' |
Чекбоксы: углублённое изучение с checked()
Одиночный чекбокс представляет булево состояние — вкл или выкл, включено или отключено, показать или скрыть. Функция checked() гарантирует, что когда пользователь ранее отметил чекбокс и сохранил настройки, чекбокс отображается отмеченным при возвращении на страницу настроек. Без неё каждый чекбокс по умолчанию был бы не отмечен независимо от сохранённого значения, заставляя пользователей переотмечать опции при каждом редактировании настроек.
Базовая отрисовка чекбокса
function mytheme_checkbox_callback() {
$options = get_option('mytheme_options');
$current = isset($options['enable_feature']) ? $options['enable_feature'] : 0;
?>
Включает экспериментальные функции и инструменты разработчика. Используйте с осторожностью.
Функция checked() сравнивает два значения. Когда первый аргумент (1, значение чекбокса при отметке) равен второму аргументу ($current, сохранённое значение опции), она выводит checked='checked' как HTML-атрибут. Это заставляет браузер отображать чекбокс отмеченным. Когда они не совпадают, ничего не выводится, и чекбокс отображается неотмеченным.Множественные чекбоксы (группа чекбоксов)
Несколько связанных чекбоксов представляют другую задачу. В отличие от радиокнопок, где может быть выбрана только одна опция, группы чекбоксов допускают любую комбинацию. Каждый чекбокс должен иметь уникальное имя внутри массива опций:
function mytheme_checkbox_group_callback() {
$options = get_option('mytheme_options');
$features = array(
'lazy_load' => 'Включить ленивую загрузку изображений',
'dark_mode' => 'Включить переключатель тёмной темы',
'breadcrumbs' => 'Показывать хлебные крошки',
'back_to_top' => 'Показывать кнопку «Наверх»',
'sticky_menu' => 'Закреплённое меню шапки',
);
?>
Каждый чекбокс хранит своё состояние независимо под собственным ключом массива. Колбэк очистки должен обрабатывать каждый ключ отдельно, устанавливая значение по умолчанию 0, когда чекбокс не отмечен:
function mytheme_sanitize_checkbox_group($input) {
$output = array();
$feature_keys = array('lazy_load', 'dark_mode', 'breadcrumbs', 'back_to_top', 'sticky_menu');
foreach ($feature_keys as $key) {
$output[$key] = isset($input[$key]) ? absint($input[$key]) : 0;
}
return $output;
}
[/codeblock]
Радиокнопки: построение правильных групп
Радиокнопки обеспечивают взаимоисключающий выбор. Пользователи могут выбрать ровно один вариант из набора. Браузер автоматически обеспечивает исключительность, когда все радиокнопки в группе имеют одинаковый атрибут name. Функция checked(), применённая к каждой радиокнопке индивидуально, гарантирует правильное отображение ранее сохранённого выбора.
Группа радиокнопок с подписями
function mytheme_radio_group_callback() {
$options = get_option('mytheme_options');
$current = isset($options['sidebar_position']) ? $options['sidebar_position'] : 'right';
$positions = array(
'left' => 'Левая боковая панель',
'right' => 'Правая боковая панель',
'none' => 'Без боковой панели (полная ширина)',
);
?>
Определяет положение боковой панели в макете страницы.
Каждая радиокнопка в группе имеет одинаковое имя — mytheme_options[sidebar_position]. Это сообщает браузеру, что они принадлежат к одной группе. Функция checked() сравнивает значение каждой опции с сохранённым значением $current. Только совпадающая радиокнопка получает атрибут checked.Связка label: отношения id и for
Правильная связка label улучшает как доступность, так и удобство использования. Когда атрибут for метки совпадает с атрибутом id поля ввода, клик по тексту метки переключает связанный элемент. Это делает радиокнопки и чекбоксы значительно удобнее в использовании, особенно на мобильных устройствах, где маленькие области клика вызывают раздражение.
/>
Правый макет
[/codeblock]
Выпадающие списки: использование selected()
Выпадающие списки представляют набор вариантов в компактном формате. Функция selected() зеркально отражает checked() для контекста select: она сравнивает значение опции с сохранённым и выводит selected='selected' при совпадении.
Базовый select с итерируемыми опциями
function mytheme_select_dropdown_callback() {
$options = get_option('mytheme_options');
$current = isset($options['primary_font']) ? $options['primary_font'] : 'system-ui';
$fonts = array(
'system-ui' => 'Системный шрифт по умолчанию',
'georgia' => 'Georgia',
'helvetica' => 'Helvetica Neue',
'roboto' => 'Roboto',
'lora' => 'Lora',
'merriweather' => 'Merriweather',
'opensans' => 'Open Sans',
'montserrat' => 'Montserrat',
);
?>
Базовый шрифт для всего текста на сайте.
Шаблон с циклом foreach — стандартный подход для выпадающих списков. Определите варианты как ассоциативный массив, итерируйтесь по ним и вызывайте selected() для каждой опции. Это сохраняет код по принципу DRY и делает добавление или удаление вариантов таким же простым, как редактирование массива.Select с группами optgroup
Для более длинных списков вариантов группировка связанных опций под метками <optgroup> улучшает читаемость:
function mytheme_grouped_select_callback() {
$options = get_option('mytheme_options');
$current = isset($options['content_width']) ? $options['content_width'] : 'medium';
$widths = array(
'Узкий' => array(
'600' => '600px',
'640' => '640px',
),
'Стандартный' => array(
'700' => '700px',
'760' => '760px',
'800' => '800px',
),
'Широкий' => array(
'960' => '960px',
'1100' => '1100px',
'1200' => '1200px',
),
);
?>
Группированные поля: несколько связанных полей
Иногда одна логическая настройка требует нескольких полей ввода. Например, конфигурация социальных сетей может требовать URL и переключатель видимости для каждой платформы. Группировка этих связанных полей визуально и логически улучшает пользовательский опыт и организацию кода.
Группа полей социальных сетей
function mytheme_social_group_callback() {
$options = get_option('mytheme_options');
$platforms = array(
'twitter' => 'Twitter / X',
'facebook' => 'Facebook',
'instagram' => 'Instagram',
'linkedin' => 'LinkedIn',
'youtube' => 'YouTube',
);
?>
Этот группированный подход хранит связанные данные во вложенных массивах: social_urls для URL и social_show для переключателей видимости. Колбэк очистки обрабатывает эти вложенные структуры:
function mytheme_sanitize_social_group($input) {
$output = array();
$platforms = array('twitter', 'facebook', 'instagram', 'linkedin', 'youtube');
if (isset($input['social_urls']) && is_array($input['social_urls'])) {
foreach ($platforms as $key) {
if (isset($input['social_urls'][$key]) && !empty($input['social_urls'][$key])) {
$output['social_urls'][$key] = esc_url_raw($input['social_urls'][$key]);
} else {
$output['social_urls'][$key] = '';
}
}
}
if (isset($input['social_show']) && is_array($input['social_show'])) {
foreach ($platforms as $key) {
$output['social_show'][$key] = isset($input['social_show'][$key])
? absint($input['social_show'][$key])
: 0;
}
}
return $output;
}
[/codeblock]
Объединение всех типов ввода: страница полного набора функций
Соберём полную страницу настроек, использующую чекбоксы, радиокнопки, выпадающие списки и группированные поля вместе. Это реалистичный шаблон для страницы опций темы, управляющей макетом, типографикой и социальной интеграцией:
function mytheme_register_all_settings() {
register_setting(
'mytheme_options_group',
'mytheme_options',
'mytheme_full_sanitize'
);
add_settings_section(
'mytheme_feature_section',
'Переключатели функций',
'mytheme_feature_section_text',
'mytheme-full-settings'
);
add_settings_section(
'mytheme_layout_section',
'Настройки макета',
'mytheme_layout_section_text',
'mytheme-full-settings'
);
add_settings_section(
'mytheme_social_section',
'Социальные сети',
'mytheme_social_section_text',
'mytheme-full-settings'
);
add_settings_field(
'feature_checkboxes',
'Включённые функции',
'mytheme_feature_checkbox_group',
'mytheme-full-settings',
'mytheme_feature_section'
);
add_settings_field(
'sidebar_radio',
'Расположение боковой панели',
'mytheme_sidebar_radio_group',
'mytheme-full-settings',
'mytheme_layout_section'
);
add_settings_field(
'font_select',
'Основной шрифт',
'mytheme_font_select',
'mytheme-full-settings',
'mytheme_layout_section'
);
add_settings_field(
'social_group',
'Социальные профили',
'mytheme_social_group_callback',
'mytheme-full-settings',
'mytheme_social_section'
);
}
add_action('admin_init', 'mytheme_register_all_settings');
[/codeblock]
Каждая секция настроек группирует связанные поля под общим заголовком. Колбэки секций предоставляют пояснительный текст. Колбэки полей отрисовывают фактические элементы ввода. Это разделение обязанностей сохраняет код модульным: вы можете добавлять, удалять или переупорядочивать секции, не затрагивая логику отрисовки отдельных полей.
Регистрация административной страницы
После регистрации всех настроек последний шаг — создание административной страницы, отображающей форму:
function mytheme_full_settings_page() {
?>
Полные настройки MyTheme
Полная очистка для всех типов полей
Колбэк очистки, обрабатывающий чекбоксы, радиокнопки, выпадающие списки и вложенные массивы, должен быть всеобъемлющим и защитным:
function mytheme_full_sanitize($input) {
$output = array();
$feature_keys = array('lazy_load', 'dark_mode', 'breadcrumbs', 'back_to_top', 'sticky_menu');
foreach ($feature_keys as $key) {
$output[$key] = isset($input[$key]) ? absint($input[$key]) : 0;
}
$valid_sidebars = array('left', 'right', 'none');
$output['sidebar_position'] = isset($input['sidebar_position'])
&& in_array($input['sidebar_position'], $valid_sidebars)
? $input['sidebar_position']
: 'right';
$valid_fonts = array('system-ui', 'georgia', 'helvetica', 'roboto', 'lora', 'merriweather', 'opensans', 'montserrat');
$output['primary_font'] = isset($input['primary_font'])
&& in_array($input['primary_font'], $valid_fonts)
? $input['primary_font']
: 'system-ui';
$platforms = array('twitter', 'facebook', 'instagram', 'linkedin', 'youtube');
foreach ($platforms as $key) {
if (isset($input['social_urls'][$key]) && !empty($input['social_urls'][$key])) {
$output['social_urls'][$key] = esc_url_raw($input['social_urls'][$key]);
} else {
$output['social_urls'][$key] = '';
}
$output['social_show'][$key] = isset($input['social_show'][$key])
? absint($input['social_show'][$key])
: 0;
}
return $output;
}
[/codeblock]
Отладка проблем состояния формы
Когда чекбоксы, радиокнопки или выпадающие списки не отражают сохранённое состояние, причина почти всегда в несоответствии между значением, сравниваемым checked() или selected(), и фактическим значением сохранённой опции. Вот систематический подход к отладке:
Шаг 1: Сдампите сохранённую опцию
Добавьте временный var_dump(get_option('mytheme_options')) в начало колбэка отрисовки. Проверьте, что значение действительно существует и имеет ожидаемый тип. Значение "1" (строка) не совпадёт при сравнении с 1 (целое) в checked(1, $current), потому что PHP использует строгое сравнение внутри функции.
Шаг 2: Проверьте соответствие атрибута name
Если ваш input имеет name="mytheme_options[sidebar]" но очиститель проверяет $input['sidebar_position'], значение сохраняется под другим ключом, отличным от того, который вы читаете. Атрибут name, ключ очистителя и ключ get_option() должны полностью совпадать.
Шаг 3: Проверьте выполнение колбэка очистки
Добавьте вызов error_log() в начало колбэка очистки. Если он никогда не появляется в логе отладки, колбэк не вызывается. Обычно это означает, что третий аргумент register_setting() написан с ошибкой или функция не определена на момент вызова register_setting().
Соображения доступности для элементов формы
Административные страницы должны быть доступны всем, включая пользователей, полагающихся на экранные дикторы, клавиатурную навигацию и вспомогательные технологии:
- Каждый <input>, <select> и <textarea> должен иметь связанный элемент <label>. Используйте либо оборачивание, либо подход for/id.
- Группы связанных радиокнопок и чекбоксов должны быть обёрнуты в <fieldset> с элементом <legend>, описывающим группу. Экранные дикторы объявляют legend при входе в fieldset.
- Сообщения об ошибках и обратная связь валидации должны использовать aria-describedby для связывания сообщения с полем ввода.
- Порядок табуляции должен следовать визуальному порядку. Не используйте положительные значения tabindex для переупорядочивания — перестройте HTML.
- Обязательные поля должны использовать атрибут aria-required="true" в дополнение к атрибуту HTML5 required для более широкой поддержки экранными дикторами.
Часто задаваемые вопросы
Почему checked() не отмечает мой чекбокс, хотя значение правильное?
checked() сравнивает значения через нестрогое сравнение (==), так что тип имеет значение. Если сохранённое значение — строка "1", но вы вызываете checked(1, $current), PHP сравнивает строку "1" с целым 1, и они совпадают. Однако если сохраняется целое 1 и вызывается checked('1', $current), сравнение тоже успешно. Реальная проблема обычно не в типе, а в несоответствии между атрибутом name в форме, ключом в очистителе и ключом в массиве опций. Проверьте, что все три используют одинаковое имя ключа.
Как обрабатывать радиокнопки, когда не задано значение по умолчанию?
Всегда предоставляйте значение по умолчанию при чтении опции: $current = isset($options['layout']) ? $options['layout'] : 'значение_по_умолчанию'. Если ни одна радиокнопка не выбрана, ни один вызов checked() ничего не выведет, и браузер оставит все радиокнопки неотмеченными. Это корректный HTML, но сбивает пользователей с толку. Задайте разумное значение по умолчанию, соответствующее настройкам темы или плагина.
Можно ли использовать checked() и для чекбоксов, и для радиокнопок?
Да. Функция checked() работает для обоих типов. Она выводит checked='checked' независимо от того, является ли input type="checkbox" или type="radio". Функция универсальна — она не проверяет тип input — поэтому можно использовать её единообразно для всех элементов формы, нуждающихся в атрибуте checked.
Как обрабатывать выпадающие списки с динамическими опциями из базы данных?
Получайте опции в колбэке отрисовки через запрос к базе или API, стройте массив динамически и итерируйтесь с foreach как для статического массива. Обязательно проверяйте сохранённое значение по динамически построенному списку в колбэке очистки. Если опции могут меняться между сохранениями, храните ярлыки опций, а не отображаемые метки, и перестраивайте список из базы перед валидацией.
Как правильно группировать несколько опций чекбоксов?
Оберните все связанные чекбоксы в <fieldset> с <legend>. Дайте каждому чекбоксу уникальное имя в массиве опций: mytheme_options[feature_lazy], mytheme_options[feature_dark] и т.д. Обрабатывайте каждый ключ независимо в колбэке очистки. В отличие от радиокнопок, чекбоксы в группе могут иметь разные атрибуты name — и должны, потому что каждый представляет независимую булеву настройку под отдельным ключом опции.
Почему выпадающий список всегда показывает первый вариант после сохранения?
Функция selected() сравнивает первый аргумент (значение опции) со вторым (сохранённое значение). Если они не совпадают, атрибут selected не выводится. Частые причины: сохранённое значение содержит лишние пробелы (используйте trim() при сохранении), атрибут value содержит опечатку, отличающуюся от белого списка, или колбэк очистки заменяет значение на умолчание, потому что отправленное значение не проходит проверку in_array().
Как добавить опцию «без выбора» в выпадающий список?
Добавьте option с пустым значением как первый элемент: <option value="">-- Выберите --</option>. Не вызывайте selected() для этой опции, если сохранённое значение явно не пустое. В колбэке очистки либо разрешите пустую строку как допустимое значение, либо замените на значение по умолчанию: if (empty($input['field'])) { $input['field'] = 'default'; }.
Как организовать форму с 20+ полями настроек, чтобы она не стала неуправляемой?
Разделите поля по секциям через add_settings_section(). Группируйте 3-7 связанных полей на секцию. Каждая секция получает свой заголовок и пояснительный текст. Для очень больших конфигураций используйте несколько страниц настроек через подменю. Для экстремально сложных настроек (50+ полей) рассмотрите использование WordPress Customizer вместо отдельной админ-страницы — он изначально поддерживает группировку и управление состоянием.
Нажмите для реакции



