Давно уже меня просили написать пост про создание страниц настроек с использованием Settings API, но всё никак не доходили до него руки. Ну что же, вот и дошли.
Обычно, в похожих уроках авторы любят рассматривать все функции по отдельности — в таких случаях их ну очень неудобно копировать и можно запутаться что к чему. Поэтому в конце урока я решил предоставить вам полностью готовый к использованию код — просто вставьте его сами знаете, куда, и страница настроек сразу появится у вас в админке. Ну а потом вы уже сможете отредактировать в ней поля, либо добавить свои собственные.
Ну, а если вам хочется разобраться в этом вместе со мной по шагам, то погнали!
1. Создание страницы в админке для новых опций сайта
Хорошая новость – вы можете разместить вашу страницу настроек абсолютно где угодно в меню в админке – это может быть как элемент меню верхнего уровня, так и вложенный в уже существующий элемент меню, например в «Инструменты» или в «Настройки».
Рассмотрим оба случая!
1.1 Элемент меню верхнего уровня
Для этого можно воспользоваться функцией add_menu_page() и только ей. Про неё следует помнить, что она должны находиться внутри хука admin_menu
, иначе у вас просто возникнут проблемки.
Пример:
add_action( 'admin_menu', 'true_top_menu_page', 25 ); function true_top_menu_page(){ add_menu_page( 'Настройки слайдера', // тайтл страницы 'Слайдер', // текст ссылки в меню 'manage_options', // права пользователя, необходимые для доступа к странице 'true_slider', // ярлык страницы 'true_slider_page_callback', // функция, которая выводит содержимое страницы 'dashicons-images-alt2', // иконка, в данном случае из Dashicons 20 // позиция в меню ); } function true_slider_page_callback(){ echo 'привет'; }
Если у вас возникают вопросы по параметрам функции, то они все у меня описаны в документации функции add_menu_page().
При вставке этого кода, надеюсь, вы знаете, куда, у вас появится меню в админке и даже отдельная страница для него:
1.2 Вложенный элемент меню
Но вполне возможно, что для добавления своей страницы настроек вы не хотите перегружать админку новыми элементами, поэтому вы можете захотеть добавить свою страницу настроек в уже какой-то существующий пункт меню – логичнее всего конечно же в «Настройки».
Для этого вы можете воспользоваться функцией add_submenu_page(), либо какой-либо из альтернативных функций, в зависимости от того, куда будете добавлять вложенный пункт меню.
Пробуем видоизменить код выше:
add_action( 'admin_menu', 'true_top_menu_page', 25 ); function true_top_menu_page(){ add_submenu_page( 'options-general.php', 'Настройки слайдера', // тайтл страницы 'Слайдер', // текст ссылки в меню 'manage_options', // права пользователя, необходимые для доступа к странице 'true_slider', // ярлык страницы 'true_slider_page_callback' // функция, которая выводит содержимое страницы ); } function true_slider_page_callback(){ echo 'привет'; }
В итоге:
2. Подготовка страницы настроек под Settings API
Теперь, вместо того, чтобы выводить «привет» в нашей колбэк-функции, мы добавим в неё следующее:
function true_slider_page_callback(){ echo '<div class="wrap"> <h1>' . get_admin_page_title() . '</h1> <form method="post" action="options.php">'; settings_fields( 'true_slider_settings' ); // название настроек do_settings_sections( 'true_slider' ); // ярлык страницы, не более submit_button(); // функция для вывода кнопки сохранения echo '</form></div>'; }
В этом коде я использовал функции:
После обновления кода, страница примет вид:
3. Добавляем поле
Для добавления поля нам понадобится целых… 5 функций! 🙃
На самом деле может показаться, что очень жёстко, но давайте попробуем!
Все эти функции весело отправляются в хук admin_init
.
add_action( 'admin_init', 'true_slider_fields' ); function true_slider_fields(){ // регистрируем опцию register_setting( 'true_slider_settings', // название настроек из предыдущего шага 'number_of_slider_slides', // ярлык опции 'absint' // функция очистки ); // добавляем секцию без заголовка add_settings_section( 'slider_settings_section_id', // ID секции, пригодится ниже '', // заголовок (не обязательно) '', // функция для вывода HTML секции (необязательно) 'true_slider' // ярлык страницы ); // добавление поля add_settings_field( 'number_of_slider_slides', 'Количество слайдов в слайдере', 'true_number_field', // название функции для вывода 'true_slider', // ярлык страницы 'slider_settings_section_id', // // ID секции, куда добавляем опцию array( 'label_for' => 'number_of_slider_slides', 'class' => 'misha-class', // для элемента <tr> 'name' => 'number_of_slider_slides', // любые доп параметры в колбэк функцию ) ); } function true_number_field( $args ){ // получаем значение из базы данных $value = get_option( $args[ 'name' ] ); printf( '<input type="number" min="1" id="%s" name="%s" value="%d" />', esc_attr( $args[ 'name' ] ), esc_attr( $args[ 'name' ] ), absint( $value ) ); }
printf()
и sprintf()
это две PHP-функции, которые очень часто используются в разработке на WordPress. Вы можете почитать о них в PHP-документации. Например в примере выше мы видим первый параметр, который представляет собой строку-шаблон, в ней все вхождения %s
и %d
будут заменены на следующие параметры функции в соответствующем порядке, где %s
должно представлять собой строковое значение, а %d
– целое число. Кроме того, я добавил очистку absint(), потому что мы также должны исключить отрицательные числа.
Итак:
Добавление опций на стандартные страницы настроек WordPress
Если в предыдущем коде вы сделаете несколько изменений, а именно:
// регистрируем опцию register_setting( 'media', 'number_of_slider_slides', 'absint' ); // добавляем секцию без заголовка add_settings_section( 'slider_settings_section_id', 'Настройка слайдера', '', 'media' ); // добавление поля add_settings_field( 'number_of_slider_slides', 'Количество слайдов в слайдере', 'true_number_field', 'media', 'slider_settings_section_id',
То наша опция слайдера появится в Настройки > Медиафайлы:
Также вы можете воспользоваться и другими идентификаторами стандартных страниц настроек:
4. Уведомление о сохранении
Последний шаг – при нажатии на кнопку «Сохранить изменения» неплохо бы сообщить об этом пользователю!
add_action( 'admin_notices', 'true_custom_notice' ); function true_custom_notice() { if( isset( $_GET[ 'page' ] ) && 'true_slider' == $_GET[ 'page' ] && isset( $_GET[ 'settings-updated' ] ) && true == $_GET[ 'settings-updated' ] ) { echo '<div class="notice notice-success is-dismissible"><p>Слайдер сохранён!</p></div>'; } }
Получаем совсем красоту в итоге:
5. Валидация полей
Также не могу не рассказать вам про то, как настроить валидацию полей. Для этого нам понадобится использовать две функции settings_errors() для вывода ошибок и add_settings_error() для добавления ошибки. Обе эти функции привязаны к друг к другу при помощи первого параметра-идентификатора, который должен совпадать, например settings_errors( 'hey-error' )
и add_settings_error( 'hey-error', ... )
. Попробуем это реализовать!
5.1. Вывод ошибок
Прежде всего подготовим в нашем коде место для вывода ошибок. Для этого я возьму код из второй части урока и добавлю там функцию settings_errors() непосредственно в то место, где я хочу вывести ошибки! Например:
function true_slider_page_callback(){ echo '<div class="wrap"> <h1>' . get_admin_page_title() . '</h1> <form method="post" action="options.php">'; settings_errors( 'true_slider_settings_errors' ); // ярлык – любой settings_fields( 'true_slider_settings' ); ...
5.2. Превращаем колбэк-функцию очистки в функцию валидации и добавления ошибок.
Здесь мы возвращаемся к функции register_setting() из третьего шага, в котором мы регистрировали опцию настроек:
// регистрируем опцию register_setting( 'true_slider_settings', // название настроек из предыдущего шага 'number_of_slider_slides', // ярлык опции 'absint' // функция очистки );
Меняем название функции очистки (у меня это absint()) на любую кастомную функцию, которую мы сейчас и создадим:
// регистрируем опцию register_setting( 'true_slider_settings', // название настроек из предыдущего шага 'number_of_slider_slides', // ярлык опции 'true_validate' // функция валидации );
И создаём эту функцию:
function true_validate( $input ) { // сначала можно сразу же очистить $input = absint( $input ); if( $input < 2 ) { // добавляем свои условия валидация add_settings_error( 'true_slider_settings_errors', 'malo-slides', // часть ID, добавляемый к сообщению об ошибке id="setting-error-malo-slides" 'В слайдере должно быть хотя бы два слайда иначе это и не слайдер вовсе!', 'error' // может быть success, warning, info ); // получаем и возвращаем старое значение поля, если валидация не прошла $input = get_option( 'number_of_slider_slides' ); } return $input; }
3. Допиливаем уведомление о сохранении
Теоретически, мы можем не отображать уведомление о сохранении полей, если существуют ошибки:
add_action( 'admin_notices', 'true_custom_notice' ); function true_custom_notice() { // получаем ошибки $settings_errors = get_settings_errors( 'true_slider_settings_errors' ); // если они есть, то уведомление о сохранении выводить не будем if ( ! empty( $settings_errors ) ) { return; } ...
На этом всё! Мы молодцы!
Готовый код
Решил в качестве небольшого бонуса не только объединить все сниппеты код в один, но и превратить их в PHP-класс. Да, в этом коде нет валидации, только очистка.
class trueOptionsPage{ public $page_slug; public $option_group; function __construct() { // это у нас используется много где, поэтому давайте вынесем как отдельное свойство $this->page_slug = 'true_slider'; $this->option_group = 'true_slider_settings'; add_action( 'admin_menu', array( $this, 'add' ), 25 ); add_action( 'admin_init', array( $this, 'settings' ) ); add_action( 'admin_notices', array( $this, 'notice' ) ); } function add(){ add_menu_page( 'Настройки слайдера', 'Слайдер', 'manage_options', $this->page_slug, array( $this, 'display' ), 'dashicons-images-alt2', 20 ); } function display() { echo '<div class="wrap"> <h1>' . get_admin_page_title() . '</h1> <form method="post" action="options.php">'; settings_fields( $this->option_group ); do_settings_sections( $this->page_slug ); submit_button(); echo '</form></div>'; } function settings(){ register_setting( $this->option_group, 'number_of_slider_slides', 'absint' ); add_settings_section( 'slider_settings_section_id', '', '', $this->page_slug ); add_settings_field( 'number_of_slider_slides', 'Количество слайдов в слайдере', array( $this, 'field' ), $this->page_slug, 'slider_settings_section_id', array( 'label_for' => 'number_of_slider_slides', 'class' => 'misha-class', 'name' => 'number_of_slider_slides', ) ); } function field( $args ){ // получаем значение из базы данных $value = get_option( $args[ 'name' ] ); printf( '<input type="number" min="1" id="%s" name="%s" value="%s" />', esc_attr( $args[ 'name' ] ), esc_attr( $args[ 'name' ] ), absint( $value ) ); } function notice() { if( isset( $_GET[ 'page' ] ) && $this->page_slug == $_GET[ 'page' ] && isset( $_GET[ 'settings-updated' ] ) && true == $_GET[ 'settings-updated' ] ) { echo '<div class="notice notice-success is-dismissible"><p>Слайдер сохранён!</p></div>'; } } } new trueOptionsPage();
Получение и вывод опций во фронтенде темы
Так получилось, что когда мои англоязычные читатели и клиенты говорят слово «frontend», то они подразумевают непосредственно страницы самого сайта, не считая админку. Хм, не уверен, что это 100% правильно, но пусть будет так.
Для того, чтобы получить значение какой-либо опции настроек WordPress достаточно использовать функцию get_option(). На этом всё, до свидания.
Рассмотрим на нашем примере. В саму функцию нам нужно передать единственный параметр – ярлык (ключ) опции, который мы задавали, когда добавляли поле (строчки 8 и 22).
// регистрируем опцию register_setting( 'true_slider_settings', // название настроек из предыдущего шага 'number_of_slider_slides', // ярлык опции
// добавление поля add_settings_field( 'number_of_slider_slides',
Воспользуемся этим ярлыком, чтобы получить значение опции:
$num_slides = get_option( 'number_of_slider_slides' ); echo 'Количество слайдов: ' . $num_slides;
Про очистку тоже помним, да?
$num_slides = get_option( 'number_of_slider_slides' ); echo 'Количество слайдов: ' . absint( $num_slides );
Или вот так:
echo sprintf( 'Количество слайдов: %d', get_option( 'number_of_slider_slides' ) );
Возможно, что тут вам захочется почитать про документацию PHP-функции sprintf()
, но если коротко: то в шаблоне %d
– целое число, %s
– строка.
Использование массивов при добавлении нескольких полей настроек как одну опцию
Также хотел обратить ваше внимание на то, что если в вашей теме или плагине вы используете несколько полей настроек, то вам необязательно использовать отдельные строчки в базе данных для хранения значений каждого из них.
То есть да, вы вполне можете зарегистрировать каждое значение, как отдельную опцию, вот так:
register_setting( 'true_option_group', 'color' ); register_setting( 'true_option_group', 'size' ); register_setting( 'true_option_group', 'quantity' );
Но возможно, что будет легче и эффективнее использовать всего лишь одну опцию и хранить все значения сразу в ней. Тогда нам будет достаточно одного-единственного вызова функции register_setting().
register_setting( 'true_option_group', 'true_option' );
Но что же дальше? А вот что. Допустим дальше мы создаём колбэк-функцию вывода поля цвета color
:
function field(){ // получаем массив значений опции из базы данных $options = (array) get_option( 'true_option' ); printf( '<input type="text" name="true_option[color]" value="%s" />', esc_attr( $options[ 'color' ] ); ); }
То же самое произойдёт и при выводе опции где-либо на сайте, т.е сначала получаем всю группу опций: $options = (array) get_option( 'true_option' );
а затем обращаемся к интересующему нас элементу массива $options[ 'color' ]
.