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

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

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

Я же предоставляю вам полностью готовый к использованию код — просто вставьте его в functions.php и страница настроек сразу появится у вас в админке. Ну а потом вы уже сможете отредактировать в ней поля, либо добавить свои собственные.

<?php
$true_page = 'myparameters.php'; // это часть URL страницы, рекомендую использовать строковое значение, т.к. в данном случае не будет зависимости от того, в какой файл вы всё это вставите
 
/*
 * Функция, добавляющая страницу в пункт меню Настройки
 */
function true_options() {
	global $true_page;
	add_options_page( 'Параметры', 'Параметры', 'manage_options', $true_page, 'true_option_page');  
}
add_action('admin_menu', 'true_options');
 
/**
 * Возвратная функция (Callback)
 */ 
function true_option_page(){
	global $true_page;
	?><div class="wrap">
		<h2>Дополнительные параметры сайта</h2>
		<form method="post" enctype="multipart/form-data" action="options.php">
			<?php 
			settings_fields('true_options'); // меняем под себя только здесь (название настроек)
			do_settings_sections($true_page);
			?>
			<p class="submit">  
				<input type="submit" class="button-primary" value="<?php _e('Save Changes') ?>" />  
			</p>
		</form>
	</div><?php
}
 
/*
 * Регистрируем настройки
 * Мои настройки будут храниться в базе под названием true_options (это также видно в предыдущей функции)
 */
function true_option_settings() {
	global $true_page;
	// Присваиваем функцию валидации ( true_validate_settings() ). Вы найдете её ниже
	register_setting( 'true_options', 'true_options', 'true_validate_settings' ); // true_options
 
	// Добавляем секцию
	add_settings_section( 'true_section_1', 'Текстовые поля ввода', '', $true_page );
 
	// Создадим текстовое поле в первой секции
	$true_field_params = array(
		'type'      => 'text', // тип
		'id'        => 'my_text',
		'desc'      => 'Пример обычного текстового поля.', // описание
		'label_for' => 'my_text' // позволяет сделать название настройки лейблом (если не понимаете, что это, можете не использовать), по идее должно быть одинаковым с параметром id
	);
	add_settings_field( 'my_text_field', 'Текстовое поле', 'true_option_display_settings', $true_page, 'true_section_1', $true_field_params );
 
	// Создадим textarea в первой секции
	$true_field_params = array(
		'type'      => 'textarea',
		'id'        => 'my_textarea',
		'desc'      => 'Пример большого текстового поля.'
	);
	add_settings_field( 'my_textarea_field', 'Большое текстовое поле', 'true_option_display_settings', $true_page, 'true_section_1', $true_field_params );
 
	// Добавляем вторую секцию настроек
 
	add_settings_section( 'true_section_2', 'Другие поля ввода', '', $true_page );
 
	// Создадим чекбокс
	$true_field_params = array(
		'type'      => 'checkbox',
		'id'        => 'my_checkbox',
		'desc'      => 'Пример чекбокса.'
	);
	add_settings_field( 'my_checkbox_field', 'Чекбокс', 'true_option_display_settings', $true_page, 'true_section_2', $true_field_params );
 
	// Создадим выпадающий список
	$true_field_params = array(
		'type'      => 'select',
		'id'        => 'my_select',
		'desc'      => 'Пример выпадающего списка.',
		'vals'		=> array( 'val1' => 'Значение 1', 'val2' => 'Значение 2', 'val3' => 'Значение 3')
	);
	add_settings_field( 'my_select_field', 'Выпадающий список', 'true_option_display_settings', $true_page, 'true_section_2', $true_field_params );
 
	// Создадим радио-кнопку
	$true_field_params = array(
		'type'      => 'radio',
		'id'      => 'my_radio',
		'vals'		=> array( 'val1' => 'Значение 1', 'val2' => 'Значение 2', 'val3' => 'Значение 3')
	);
	add_settings_field( 'my_radio', 'Радио кнопки', 'true_option_display_settings', $true_page, 'true_section_2', $true_field_params );
 
}
add_action( 'admin_init', 'true_option_settings' );
 
/*
 * Функция отображения полей ввода
 * Здесь задаётся HTML и PHP, выводящий поля
 */
function true_option_display_settings($args) {
	extract( $args );
 
	$option_name = 'true_options';
 
	$o = get_option( $option_name );
 
	switch ( $type ) {  
		case 'text':  
			$o[$id] = esc_attr( stripslashes($o[$id]) );
			echo "<input class='regular-text' type='text' id='$id' name='" . $option_name . "[$id]' value='$o[$id]' />";  
			echo ($desc != '') ? "<br /><span class='description'>$desc</span>" : "";  
		break;
		case 'textarea':  
			$o[$id] = esc_attr( stripslashes($o[$id]) );
			echo "<textarea class='code large-text' cols='50' rows='10' type='text' id='$id' name='" . $option_name . "[$id]'>$o[$id]</textarea>";  
			echo ($desc != '') ? "<br /><span class='description'>$desc</span>" : "";  
		break;
		case 'checkbox':
			$checked = ($o[$id] == 'on') ? " checked='checked'" :  '';  
			echo "<label><input type='checkbox' id='$id' name='" . $option_name . "[$id]' $checked /> ";  
			echo ($desc != '') ? $desc : "";
			echo "</label>";  
		break;
		case 'select':
			echo "<select id='$id' name='" . $option_name . "[$id]'>";
			foreach($vals as $v=>$l){
				$selected = ($o[$id] == $v) ? "selected='selected'" : '';  
				echo "<option value='$v' $selected>$l</option>";
			}
			echo ($desc != '') ? $desc : "";
			echo "</select>";  
		break;
		case 'radio':
			echo "<fieldset>";
			foreach($vals as $v=>$l){
				$checked = ($o[$id] == $v) ? "checked='checked'" : '';  
				echo "<label><input type='radio' name='" . $option_name . "[$id]' value='$v' $checked />$l</label><br />";
			}
			echo "</fieldset>";  
		break; 
	}
}
 
/*
 * Функция проверки правильности вводимых полей
 */
function true_validate_settings($input) {
	foreach($input as $k => $v) {
		$valid_input[$k] = trim($v);
 
		/* Вы можете включить в эту функцию различные проверки значений, например
		if(! задаем условие ) { // если не выполняется
			$valid_input[$k] = ''; // тогда присваиваем значению пустую строку
		}
		*/
	}
	return $valid_input;
}

После вставки этого кода перейдите в Настройки > Параметры:

Страница настроек в WordPress

Несколько советов по работе с новым API настроек WordPress

В коде я оставил столько комментариев, сколько смог, но некоторые вещи всё ещё остались без внимания.

  1. В примере я использовал add_options_page(), которая добавляла ссылку на страницу внутри пункта меню «Настройки», но вы также можете использовать и некоторые другие функции, в результате чего страница с настройками (а точнее ссылка на неё) поменяет расположение в меню, например:
    • add_menu_page() — благодаря этой функции вы сможете сделать так:
      Пример использования функции add_menu_page
    • add_submenu_page() позволит сделать ваши настройки подпунктом для любого другого элемента меню, например:
      Пример использования add_submenu_page()

      Частными случаями функции add_submenu_page() являются add_dashboard_page() (под пунктом меню «Консоль»), add_posts_page() (под «Записи»), add_media_page() (под «Медиафайлы»), add_links_page() (под «Ссылки»), add_pages_page() (под «Страницы»), add_comments_page() (под «Комментарии»), add_theme_page() (под «Внешний вид»), add_plugins_page() (под «Плагины»), add_users_page() (под «Пользователи»), add_management_page() (под «Инструменты») и конечно же add_options_page() (под «Настройки»), которую я использовал в примере.

  2. В примере я не стал рассматривать поле с возможностью загрузки изображения, но вы можете почитать об этом тут.
  3. Также могу предложить вам готовый PHP-класс для быстрого и простого создания страниц настроек на сайте, либо (что немаловажно) добавления полей в уже существующие страницы, например в «Написание» или в «Общие».

Получение настроек из базы данных

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

$all_options = get_option('true_options'); // это массив
echo $all_options['my_text']; // это значение текстового поля
// чтобы посмотреть все ключи и значения вы можете сделать так: print_r( $options );

Если вам что-то непонятно, пожалуйста, оставьте свой вопрос в комментариях и мы вместе разберёмся, что к чему.

Подпишитесь, чтобы раз в неделю получать свежие статьи с блога по email.

Смотрите также

Комментарии 66

  • Артем12 ноября 2014 в 15:11 #

    Спасибо за статью. У меня вот какой вопрос, при разработке тем одни авторы используют Theme options, другие же Theme Customizer, при этом, и первые и вторые решают с помощью них одни и те же задачи, есть вообще между ними какое то функциональное разграничение, что определяет: какой из способов более приемлем для той или иной темы?

    • Миша13 ноября 2014 в 02:11 #

      Одно и то же это, если я правильно понял вопрос.

      • Артем13 ноября 2014 в 15:11 #

        В попытках хоть как то разобраться в этом вопросе наткнулся на ребят активно дискутирующих на эту тему (если автор сайта не будет против ссылка на статью перелагается ): http://wordpress.stackexchange.com/questions/97929/settings-api-vs-theme-customizer

        В целом я пришел к выводу, что это не совсем одно и тоже, но такое впечатление неизбежно возникает из за некоторого функционального перекрытия, в общем эта тема — бездна.

        • Миша13 ноября 2014 в 15:11 #

          Всё, я понял суть вопроса :)

          Options API — нужно для добавления настроек через тему или плагин.

          Theme Customizer же настроек не добавляет, он позволяет просмотреть изменения уже существующих настроек «вживую» на сайте.

  • Артем13 ноября 2014 в 15:11 #

    « Theme Customizer же настроек не добавляет », почему же? Если правильно понял то вот так можно через

    $wp_customize->add_control($id, $args);

    можно добавить любые поля по настройке темы и ввода данных:

    /**
      * Настройка фоновой картинки
     */
    	$wp_customize->add_setting(
    		'my_theme_bg_image_repeat',
    		array(
    			'default'		=> 'no-repeat',
    		)
    	);
    	$wp_customize->add_control(
    		'my_theme_bg_image_repeat',
    		array(
    			'section'  => 'my_theme',
    			'label'    => 'Повторение фоновой картинки',
    			'type'     => 'radio',
    			'choices'  => array(
    				'no-repeat'   => 'Не повторять',
    				'repeat-x'    => 'Повторять по горизонтали',
    				'repeat-y'    => 'Повторять по вертикали',
    				'repeat'    => 'Замостить',
    			)
    		)
    	);

    и да, как вы и сказали, в отличи от Theme options, Theme Customizer — позволяет тут же просмотреть изменения

  • Сергей25 ноября 2014 в 04:11 #

    А что у вас за плагин для комментирования записей в этом блоге?

  • amira26 ноября 2014 в 15:11 #

    Спасибо за очередную полезную статью. Не-могли опубликовать пост, ли что то вроде того как добавить поле для логотипа, что-бы можно было загрузить картинку?

  • amira27 ноября 2014 в 20:11 #

    а как это сюда добавить?

    • Миша28 ноября 2014 в 07:11 #

      Боюсь, что придётся пошаманить. Если вы более-менее хорошо знаете PHP, то проблем у вас не возникнет.

  • amira28 ноября 2014 в 18:11 #

    Может пост. :D

    • Миша29 ноября 2014 в 00:11 #

      Да, надо будет дополнить/изменить старый пост про загрузчик изображений :)

  • amira29 ноября 2014 в 14:11 #

    Спасибо.. Когда примерно ждать?

    • Миша30 ноября 2014 в 07:11 #

      Как будет время.

      • Роман26 мая 2015 в 15:05 #

        в true_option_display_settings добавить:

        case 'image':
        $o[$id] = esc_attr( stripslashes($o[$id]) );
        if( function_exists( 'true_image_uploader_field' ) ) {
            true_image_uploader_field( $option_name . '[' . $id . ']', $o[$id] );
        }
        echo ($desc != '') ? "<br /><span class='description'>$desc</span>" : "";
        break;

        использовать аналогично:

        $true_field_params = array(
            'type'      => 'image',
            'id'        => 'logotype_img',
            'desc'      => '',
            'label_for' => 'logotype_img'
        );
        add_settings_field( 'logotype_img_field', 'Логотип', 'true_option_display_settings', $true_page, 'true_section_1', $true_field_params );
  • Владимир29 ноября 2014 в 22:11 #

    Здравствуйте, Михаил! Говорят, кто ищет тот найдёт. Нашёл Ваш сайт, чему очень рад, хотя многое не понимаю о чём разговор продвинутых. Однако буду учиться. Тем более, что Вам в личку написал про проблемы с сайтом! Подписку оформил.

  • Дмитрий25 июля 2015 в 20:07 #

    Привет. Не совсем понял как применять эти поля в самом шаблоне. Не понятно как добавить свое поле и что при этом можно менять а что нет. Честно говоря - ничего не понятно) готовый код так пугает.

  • Артем28 сентября 2015 в 00:09 #

    Здравствуйте Михаил, такой вопрос, может подскажите, хочу сделать сброс настроек на дефолтные, но не пойму как перезаписать можно, почему-то так

    $all_options = get_option('true_options');
    echo $all_options['my_text'];
    update_option( $all_options['my_text'], 'Текст по умолчанию' );

    Не перезаписывает, может я что-то не так делаю? или с помощью какой функции можно перезаписать.

    Создал кнопку такую

    		<form method="post" enctype="multipart/form-data" action="">
    			<span class="submit">
    				<input name="gpson_payment-reset" class="button button-secondary" type="submit" value="Сбросить все настройки" >
    				<input type="hidden" name="action" value="reset" />
    			</span>
    		</form>

    Хочу по клику устанавливать в дефолтные настройки.

    Может есть вообще упрощенный вариант? Буду признателен за помощь.

  • Сергей8 октября 2015 в 07:10 #

    Михаил, спасибо за статью. Но сейчас возникла необходимость использовать чекбокс. Ранее, я использовал другой аналогичный способ (theme-option.php) и там у меня получилось использовать чекбокс. Тут я не пойму как. Чекбокс должен вывести текст, если он включен. Буду очень благодарен за ответ.

  • Александр17 октября 2015 в 07:10 #

    Добрый день, Михаил!

    Спасибо за статью, за ваши труды, очень пригодилось!

    У меня вопрос, как мне между секциями настроек вставить свой HTML код, описание настроек, в общем информационный блок?

    с уважением, Александр

  • Николай17 октября 2015 в 15:10 #

    Дико извиняюсь за свою ограниченность, но как мне теперь текст текстового поля из настроек вывести в шаблон?

    Что-то не выходит... :(

    Пишу так:

    <?php echo true_options ( 'my_text' ); ?>
  • Александр19 октября 2015 в 23:10 #

    Михаил, а не подскажете, как можно реализовать, что бы после выбора настройки в селекте появлялись настройки согласно выбранному?

  • Александр19 октября 2015 в 23:10 #

    Сделал добавление секции с настройками по выбору селекта, вот только она появляется после сохранения настроек, а вот как сделать, что бы она появлялась сразу после выбора?

    Вот в чем вопрос!

    Понимаю, что нужно использовать JS, но в этом я уж совсем тяжко...

    Может поможете?

    • Миша20 октября 2015 в 07:10 #

      Ну что я могу сказать, нужно разбираться в JS/jQuery

      $('select').change(function(){
      	$('#settings').show();
      });
      • Александр20 октября 2015 в 08:10 #

        Ок, скрипт я смогу написать, а куда мне его вставить и каким образом лучше всего это сделать?

      • Александр20 октября 2015 в 12:10 #

        Вот скрипт и разметка http://pastebin.com/KFAQpuZG , что позволяет открывать или скрывать содержимое. Не подскажете, как его внедрить можно?

        • Миша21 октября 2015 в 08:10 #

          Скрипты в админку WP добавляйте через хук admin_footer.

          • Александр21 октября 2015 в 19:10 #

            Михаил, скрипты подключил, вот ни как допетрить не могу как мне скрывать поля настроек, как их заключить в див?

            В принципе само поле настроек во второй колонке могу скрыть, а вот как скрыть с название настройки из первой колонки, не пойму?

            • Миша22 октября 2015 в 07:10 #

              Почитайте про такие методы jQuery, как parent(), next(), prev(), find().

              • Александр22 октября 2015 в 08:10 #

                Почитал, вашу мысль понял, я не селен в JS, но вроде из прочтенного ни чего сложно, будем пилить!

                Как говорят: "Пилите, Шура, они же золотые!"...

                Спасибо, ваш сайт прям превращается в домовую книгу!

                • Миша22 октября 2015 в 09:10 #

                  У вас всё получится!

                  Не знаю, что такое домовая книга, но спасибо:)

                  • Александр22 октября 2015 в 09:10 #

                    Домовая книга - это книга с рецептами к которой сразу обращаются, в случае чего, еще ее называют поваренной

                    • Миша22 октября 2015 в 09:10 #

                      Ок, буду знать. Рад, что мой сайт как книга рецептов)

                      Без понятия, почему яндекс на меня АГС повесил///

  • Николай20 октября 2015 в 02:10 #

    Михаил, что делаю не так, не могу включить чекбоксом это:

    function dw_post($content){
    	global $all_options;
     
    	if (!is_page()){		
    		if($all_options['on_off_post_dw']){ $dw_content = dw_function();}};
     
    return $content . $dw_content;	
    }

    ???

  • Николай20 октября 2015 в 03:10 #

    Во я тупень, разобрался, нужно было не глобал писать, а

    $all_options = get_option('dw_options');

    :)))

  • Петр20 октября 2015 в 14:10 #

    Михаил, сделал по вашему коду два плагина, но вот ерунда какая получается, настройки обоих плагинов отображается вместе в каждом плагине, а если один из них деактивирую, то соответственно пропадают настройки того. который деактивировал!

    Функции, секции, настройки и т.д. т.п., не совпадают, все уникальные!

  • Дмитрий22 ноября 2015 в 16:11 #

    Как-то можно задать значения по умолчанию? Например, чтобы чекбокс скарзу после установки темы был активирован. Если да, то не подскажете как?

    • Миша23 ноября 2015 в 15:11 #

      Тогда лучше всего обновить настройки после активации темы хуком after_switch_theme.

  • Артем27 ноября 2015 в 13:11 #

    Приветствую, Михаил! Отличное решение. Вопрос: если настройки записываются в бд, то как их удалить при удалении плагина? Где почитать об этом?

    • Миша28 ноября 2015 в 09:11 #

      Приветствую! Спасибо!

      Где почитать не знаю (по крайней мере в рунете), но на словах могу объяснить — просто на хук удаления плагина вешаем функцию delete_option().

  • VRS30 декабря 2015 в 05:12 #

    Миш, если найдешь минутку, подскажи, пожалуйста, как лучше:
    Часть настроек используется в шапке сайта и часть настроек - в подвале. Получается, что два раза необходимо выполнить get_option('true_options'). Как этого избежать?

    • Миша30 декабря 2015 в 06:12 #

      И подвал и шапка — это функции внутри какого-то файла, например index.php, поэтому настройки можно записать в глобальную переменную в самом начале файла и потом обращаться к ней из подвала / шапки (теоретически).

  • Алекс19 января 2016 в 13:01 #

    Привет, почему может выдавать ошибку
    Fatal error: Cannot redeclare true_options()
    в on line 10

  • Артем30 ноября 2016 в 14:11 #

    Привет! Подскажи два момента по данному функционалу:
    1. Откуда берутся переменные $args, $type, $input
    2. Зачем нужна функция extract($args); если в переменной $args ничего нет

    Или как-то не правильно понимаю как это работает

    • Миша30 ноября 2016 в 17:11 #

      Привет!

      Функция add_settings_field() передаёт параметры в колбэк функцию true_option_display_settings() в виде переменной $args.

      • Артем30 ноября 2016 в 19:11 #

        Ага, понял. Вот только почему $args? Она же нигде не определена, по логике должна быть переменная $true_field_params или что-то не так понимаю?

        • Миша30 ноября 2016 в 21:11 #

          Ну как не определена - это аргумент функции. Или я просто вас не до конца понимаю.

Оставить комментарий / вопрос

phpjsHTMLCSSSQLПросто код
  Для того, чтобы оставить комментарий, пожалуйста, зарегистрируйтесь или авторизуйтесь на сайте.
Получайте новости блога по email или следите за мной в социальных сетях.
  • Миша: Да, точно)

  • Владимир: и на третьей строке не хватает скобки ) закрывающей if :)

  • Миша: Добрый вечер! Рекомендую получить ID пользователя через функцию get_current_user_id().

  • Дмитрий: Миша, подскажите пожалуйста, я использую такой редирект, но он не срабатывает: add_action( 'template_redirect', funct...

  • Миша: Ну как не определена - это аргумент функции. Или я просто вас не до конца понимаю.