Подробно про страницы настроек WordPress

Давно уже меня просили написать пост про создание страниц настроек с использованием Settings API, но всё никак не доходили до него руки. Ну что же, вот и дошли.

Прежде всего не забывайте, страницы настроек и настройки темы в Theme Customizer – две разные вещи. Если вы хотите знать, чем они отличаются и заодно научиться добавлять опции в Theme Customizer, то рекомендую этот урок.

Кроме того, свои приколы по добавлению страниц настроек есть у WooCommerce – об этом тоже на сайте отдельный урок.

Обычно, в похожих уроках авторы любят рассматривать все функции по отдельности — в таких случаях их ну очень неудобно копировать и можно запутаться что к чему. Поэтому в конце урока я решил предоставить вам полностью готовый к использованию код — просто вставьте его сами знаете, куда, и страница настроек сразу появится у вас в админке. Ну а потом вы уже сможете отредактировать в ней поля, либо добавить свои собственные.

Ну, а если вам хочется разобраться в этом вместе со мной по шагам, то погнали!

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().

При вставке этого кода, надеюсь, вы знаете, куда, у вас появится меню в админке и даже отдельная страница для него:

Добавление страницы в админку при помощи функции 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 'привет';
}

В итоге:

Добавление вложенного элемента меню WordPress

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>';
 
}

В этом коде я использовал функции:

После обновления кода, страница примет вид:

Страница настроек в WordPress без полей

Если на этом моменте вам уже стало страшно, то возможно стоит рассмотреть возможность создания страниц настроек при помощи плагина Carbon Fields. Урок об этом тоже есть!

3. Добавляем поле

Для добавления поля нам понадобится целых… 5 функций! 🙃

  1. register_setting() – она зарегистрирует нашу опцию,
  2. любая функция очистки значения поля перед сохранением в базу данных, например я буду использовать функцию absint(),
  3. add_settings_section() – добавит секцию (и подзаголовок, если нужно) на страницу настроек,
  4. add_settings_field() – добавит поле,
  5. любая кастомная функция для вывода HTML-поля.

На самом деле может показаться, что очень жёстко, но давайте попробуем!

Все эти функции весело отправляются в хук 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

Добавление опций на стандартные страницы настроек 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',

То наша опция слайдера появится в Настройки > Медиафайлы:

Добавление опций на стандартные страницы настроек WordPress

Также вы можете воспользоваться и другими идентификаторами стандартных страниц настроек:

  • general – Общие,
  • writing – Написание,
  • reading – Чтение,
  • discussion – Обсуждение,
  • media – Медиафайлы,
  • permalink – Постоянные ссылки;

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>';
	}
 
}

Получаем совсем красоту в итоге:

Создание страницы настроек WordPress

5. Валидация полей

Также не могу не рассказать вам про то, как настроить валидацию полей. Для этого нам понадобится использовать две функции settings_errors() для вывода ошибок и add_settings_error() для добавления ошибки. Обе эти функции привязаны к друг к другу при помощи первого параметра-идентификатора, который должен совпадать, например settings_errors( 'hey-error' ) и add_settings_error( 'hey-error', ... ). Попробуем это реализовать!

Валидация полей страниц настроек WordPress

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;
	}
	...

На этом всё! Мы молодцы!

Также рекомендую свой видеокурс по созданию темы WordPress на основе готовой вёрстки.

Готовый код

Решил в качестве небольшого бонуса не только объединить все сниппеты код в один, но и превратить их в 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' ].

Миша

Впервые познакомился с WordPress в 2009 году. Организатор и спикер на конференциях WordCamp. Преподаватель в школе Нетология.

Пишите, если нужна помощь с сайтом или разработка с нуля.

Комментарии — 83

Чтобы оставить комментарий, пожалуйста, зарегистрируйтесь или войдите.

Миша Рудрастых и WordPress

Полезности из мира WordPress и жизни студии.

Мой телеграм-канал