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

Владислав Белецкий
Владислав Белецкий .
Категория:
Комментариев: 0

Давно уже меня просили написать пост про создание страниц настроек с использованием 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' ].

Подписаться
Уведомить о
guest
0 комментариев
Межтекстовые Отзывы
Посмотреть все комментарии