Когда вы когда-нибудь захотите создать свой цифровой объект, вам нужно выяснить, что ваш объект должен содержать и как он будет себя вести. Лично мне нравится делать это на бумаге, потому что я привык делать что-то с ручкой и бумагой, ты делаешь то, что у тебя получается лучше всего.

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

Поэтому при создании наших подстраниц мы создадим экземпляр класса SettingsSubageBuilder, который будет содержать имя нашей подстраницы и массив настроек, которые будут отображаться на подстранице. То, как мы создаем наш массив, также важно. В данном случае я добавил в массив два основных ключа: description и settings_control. Описание будет иметь общее описание подстраницы, которая появится под заголовком, а settings_control будет другим массивом, в котором будут элементы управления (другой массив), состоящий из имени, control_type и описания. Конечно, в зависимости от типа элемента управления вы будете настраивать массив элементов управления. Например, массив настроек заголовка будет выглядеть так:

$header_settings_array = array(
	'description'      => esc_html__( 'Set up settings for different headers', 'twentysixteen' ),
	'settings_control' => array(
		'control_1' => array(
			'name'         => esc_html__( 'Fixed Header', 'twentysixteen' ),
			'description'  => esc_html__( 'Make the menu always fixed on top.', 'twentysixteen' ),
			'control_type' => 'checkbox',
		),
		'control_2' => array(
			'name'         => esc_html__( 'Logo', 'twentysixteen' ),
			'control_type' => 'image',
		),
		'control_3' => array(
			'name'         => esc_html__( 'Retina Logo', 'twentysixteen' ),
			'description'  => esc_html__( 'This logo is used only if the retina screens are detected.', 'twentysixteen' ),
			'control_type' => 'image',
		),
		'control_4' => array(
			'name'         => esc_html__( 'Retina Logo Width', 'twentysixteen' ),
			'description'  => esc_html__( 'Set the width of the original logo.', 'twentysixteen' ),
			'control_type' => 'input',
		),
		'control_5' => array(
			'name'         => esc_html__( 'Retina Logo Height', 'twentysixteen' ),
			'description'  => esc_html__( 'Set the height of the original logo.', 'twentysixteen' ),
			'control_type' => 'input',
		),
		'control_6' => array(
			'name'         => esc_html__( 'Background Image', 'twentysixteen' ),
			'control_type' => 'image',
		),
		'control_7' => array(
			'name'         => esc_html__( 'Background Color', 'twentysixteen' ),
			'description'  => esc_html__( 'Set the menu background color.', 'twentysixteen' ),
			'control_type' => 'colorpicker',
		),
		'control_8' => array(
			'name'         => esc_html__( 'Text Color', 'twentysixteen' ),
			'description'  => esc_html__( 'Set the menu items color.', 'twentysixteen' ),
			'control_type' => 'colorpicker',
		),
		'control_9' => array(
			'name'         => esc_html__( 'Text Hover Color', 'twentysixteen' ),
			'description'  => esc_html__( 'Set the menu items hover color.', 'twentysixteen' ),
			'control_type' => 'colorpicker',
		),
		'control_10' => array(
			'name'         => esc_html__( 'Options Select', 'twentysixteen' ),
			'description'  => esc_html__( 'Select the header options.', 'twentysixteen' ),
			'control_type' => 'select',
			'options' => array(
				'option_1' => esc_html__( 'Option 1', 'twentysixteen' ),
				'option_2' => esc_html__( 'Option 2', 'twentysixteen' ),
				'option_3' => esc_html__( 'Option 3', 'twentysixteen' ),
				'option_4' => esc_html__( 'Option 4', 'twentysixteen' ),
			),
		),
	),
);

Нам нужно все это иметь в виду, чтобы мы знали, как обращаться с этим в нашем классе. Как я уже говорил, объект получит имя и этот массив в качестве аргументов, и из него создаст нашу страницу. Приступим к созданию нашего класса. в php создать класс легко, просто добавьте класс и имя в CamelCase (Pascal Caps) и добавьте фигурные скобки, и все. Класс создан. Пустой, но класс тем не менее. Поскольку мы хотим внести некоторые данные в инициализацию нашего класса, нам нужно использовать магический метод под названием __construct(). Что он делает, так это то, что он будет автоматически вызываться при первом создании объекта. В нем мы также можем добавить наши действия. Магические методы позволят вашему классу реагировать на определенные события, такие как строительство, разрушение, сон и т. д. И они всегда начинаются с двух символов подчеркивания перед их именами. Поэтому, когда мы создаем нашу подстраницу, мы можем передать необходимые параметры, которые будут внедрены в метод __construct(), и тем самым сделать эти параметры доступными для нас, чтобы мы могли использовать их позже в наших методах. Продолжая работать с нашим файлом theme-settings.php, мы получим

/**
 * Builds Settings subpage
 *
 * @package WordPress
 * @subpackage twentysixteen/inc/theme-settings
 * @version 1.0.0
 * @author  Made by Denis <http://madebydenis.com/>
 * @license https://www.gnu.org/licenses/gpl-3.0.txt GNU/GPLv3
 * @link https://twentysixteen.io
 * @since  1.0.0
 */
class SettingsSubageBuilder {
	/**
	 * Name of the subpage menu
	 *
	 * @var string $subpage_name The name of the subpage.
	 */
	private $subpage_name;

	/**
	 * Array of elements to be used in the HTML render of the settings page
	 *
	 * @var string $subpage_name The name of the subpage.
	 */
	private $html_array;

	/**
	 * Initialization of the class
	 *
	 * @param  string $subpage_name The name of the settings page, e.g. Header Settings.
	 * @param  array  $html_array The HTML array details for building the settings page.
	 */
	public function __construct( $subpage_name, $html_array ) {
		$this->subpage_name = $subpage_name;
		$this->html_array   = $html_array;
                $ajax_hook = 'wp_ajax_twentysixteen_' . strtolower( str_replace( ' ', '_', $this->subpage_name ) ) . '_save_action';		add_action( 'admin_menu', array( $this, 'create_submenu_pages' ) );
		add_action( $ajax_hook, array( $this, 'twentysixteen_all_settings_save' ) );
	}
}

Мы добавили два свойства — имя подстраницы и массив, который создаст наш html. Обратите внимание на частные и общедоступные ключевые слова. Они будут описывать видимость свойства или метода. Как описано в руководстве, члены класса, объявленные общедоступными, доступны везде. Члены, объявленные защищенными, доступны только внутри самого класса и унаследованных классов. Члены, объявленные как частные, могут быть доступны только классу, который определяет член. Поэтому будьте осторожны при объявлении видимости ваших свойств и методов. Мы объявили свойства как приватные, а магический метод — как общедоступный. Это связано с тем, что свойства, которые мы объявляем внутри класса, должны использоваться только внутри этого класса, а метод конструкции можно использовать, даже если мы расширяем класс SettingsSubpageBuilder.

В нашем методе __construct () мы сослались на наше имя и настройки, а также добавили два действия — одно будет действием для добавления страницы подменю, а другое — для сохранения ajax. Конструктивный массив ($this, ‘function_name’) — это просто способ обратного вызова метода, определенного в классе, в котором вы находитесь. Вскоре вы увидите методы create_submenu_pages и двадцатьшестнадцать_все_настройки_сохранить. Следующее, что нам нужно, это добавить метод, который добавит нашу подстраницу.

/**
 * Create submenu page for each settings
 *
 * @return void
 */
public function create_submenu_pages() {
	$page_hook = 'twentysixteen_theme_' . strtolower( str_replace( ' ', '_', $this->subpage_name ) );

	add_submenu_page( 'twentysixteen_theme_settings', $this->subpage_name, $this->subpage_name, 'edit_theme_options', $page_hook, array( $this, 'twentysixteen_settings_render_subpage' ) );
}

Мы хотим, чтобы хук страницы был уникальным для каждого экземпляра нашего класса, поэтому мы преобразуем имя нашей подстраницы в нижний регистр и заменим пустые пробелы символами подчеркивания. Затем воспользуемся встроенной в WordPress функцией add_submenu_page(). Это позаботится о нашей подстранице. Обратите внимание, что мы сами ссылаемся на имя подстраницы, используя ключевое слово $this. Далее мы хотим создать метод, который будет создавать наши HTML-элементы. Мы хотим, чтобы наш метод принимал два аргумента — значение по умолчанию, определенное в массиве, и сохраненные значения из базы данных. Метод выглядит так

/**
 * Settings control render function
 *
 * This function takes the single control value, and based on what that control is
 * renders the appropriate control.
 *
 * @param  array $default_value   Array of the associated default controls with all the details of the controls.
 * @param  array $saved_values    Array of the values from the database.
 * @return string 				  HTML of controls.
 */
public function twentysixteen_theme_settings_control_render( $default_value, $saved_values ) {
	$name             = ( isset( $default_value['name'] ) && '' !== $default_value['name'] ) ? $default_value['name'] : '';
	$control_type     = ( isset( $default_value['control_type'] ) && '' !== $default_value['control_type'] ) ? $default_value['control_type'] : '';
	$description      = ( isset( $default_value['description'] ) && '' !== $default_value['description'] ) ? '<p class="description">' . $default_value['description'] . '</p>' : '';
	$control_slug     = 'twentysixteen_' . str_replace( ' ', '_', strtolower( $name ) );
	$control_settings = ( isset( $saved_values ) && '' !== $saved_values ) ? $saved_values : '';
	$value            = ( isset( $control_settings[$control_slug] ) && '' !== $control_settings[$control_slug] ) ? $control_settings[$control_slug] : '';

	$out = '';

	switch ( $control_type ) {
		case 'input':
			$out .= '<div class="twentysixteen_options_wrapper">
						<div class="twentysixteen_options_left">
							<h4>' . esc_html( $name ) . '</h4>
						</div>
						<div class="twentysixteen_options_right">
							<input type="text" name="' . esc_attr( $control_slug ) . '" value="' . esc_attr( $value ) . '" class="twentysixteen_setting">
							' . wp_kses_post( $description ) . '
						</div>
					</div>';
			break;

		case 'image':
			$out .= '<div class="twentysixteen_options_wrapper">
						<div class="twentysixteen_options_left">
							<h4>' . esc_html( $name ) . '</h4>
						</div>
						<div class="twentysixteen_options_right">
							<div class="twentysixteen_uploaded_image">
								<img src="' . esc_url( $value ) . '" />
							</div>
							<input type="text" name="' . esc_attr( $control_slug ) . '" value="' . esc_url( $value ) . '" class="twentysixteen_setting twentysixteen_image_upload">
							<input type="button" name="image_upload" value="' . esc_html__( 'Upload Image', 'twentysixteen' ) . '" class="button upload_image_button">
							<input type="button" name="remove_image_upload" value="' . esc_html__( 'Remove Image', 'twentysixteen' ) . '" class="button remove_image_button">
							' . wp_kses_post( $description ) . '
						</div>
					</div>';
			break;

		case 'checkbox':
			$checked = '';
			if ( isset( $value ) && '1' === $value ) {
				$checked = 'checked';
			}
			$out .= '<div class="twentysixteen_options_wrapper">
						<div class="twentysixteen_options_left">
							<h4>' . esc_html( $name ) . '</h4>
						</div>
						<div class="twentysixteen_options_right">
							<input type="checkbox" name="' . esc_attr( $control_slug ) . '" value="' . esc_attr( $value ) . '" ' . checked( $value, 1, false ) . ' class="twentysixteen_setting">
							<label class="checkbox_label"><span class="twentysixteen_setting checkbox ' . $checked . '"></span>' . esc_html( $name ) . '</label>
							' . wp_kses_post( $description ) . '
						</div>
					</div>';
			break;

		case 'colorpicker':
			$out .= '<div class="twentysixteen_options_wrapper">
						<div class="twentysixteen_options_left">
							<h4>' . esc_html( $name ) . '</h4>
						</div>
						<div class="twentysixteen_options_right">
							<input type="text" name="' . esc_html( $control_slug ) . '" value="' . esc_attr( $value ) . '" class="twentysixteen_setting twentysixteen_color_picker"/>
							' . wp_kses_post( $description ) . '
						</div>
					</div>';
			break;

		case 'select':
			$out .= '<div class="twentysixteen_options_wrapper">
						<div class="twentysixteen_options_left">
							<h4>' . esc_html( $name ) . '</h4>
						</div>
						<div class="twentysixteen_options_right">
							<select class="twentysixteen_setting" name="' . esc_html( $control_slug ) . '">
								<option value=""> -- </option>';
			if ( isset( $default_value['options'] ) && '' !== $default_value['options'] ) {
				foreach ( $default_value['options'] as $option_name => $option_value ) {
					$selected = ( isset( $value ) && '' !== $value && $option_name === $value ) ? 'selected="selected"' : '';
					$out .= '<option value="' . esc_attr( $option_name ) . '" ' . esc_attr( $selected ) . ' >' . esc_html( $option_value ) . '</option>';
				}
			}
					$out .= '</select>
							' . wp_kses_post( $description ) . '
						</div>
					</div>';
			break;

		default:
			break;
	}

	return $out;

}

Сначала мы определяем наши имена, типы элементов управления, описания из значений по умолчанию и берем фактическое сохраненное значение из массива $saved_values. Затем, в зависимости от типа элемента управления, мы выведем желаемый HTML-код элемента управления. Идея, стоящая за этим, заключается в том, что мы пройдемся по нашему массиву элементов управления, который мы определили вверху, через элементы управления и для каждого из них мы выведем желаемое поле. Здесь я добавил элементы управления, которые появляются в массиве.

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

/**
 * Rendering function for settings subpage
 *
 * @return void HTML rendered content.
 */
public function twentysixteen_settings_render_subpage() {
	$settings_array = $this->html_array;

	if ( isset( $settings_array ) && ! empty( $settings_array ) ) {

		$set_options = json_decode( json_decode( get_option( 'twentysixteen_' . str_replace( ' ', '_', strtolower( $this->subpage_name ) ), '' ) ) ); // Get options from the database.

		?>
		<div class="wrap">
			<h2 class="page_title"><?php echo esc_html( $this->subpage_name ); ?></h2>
			<p class="description"><?php echo esc_html( $settings_array['description'] ); ?></p>
			<div class="settings_above_meta">
				<a href="#" class="save_all" id="twentysixteen_settings_save_subpage"><?php esc_html_e( 'Save All', 'twentysixteen' ) ?></a>
				<span class="spinner"></span><span class="saved_options"></span>
			</div>
			<ul class="theme_settings_inner_content">
				<?php
				if ( isset( $set_options ) && '' !== $set_options ) {
					foreach ( (array) $set_options as $options_key => $options_value ) {
						?>
						<li class="settings_container <?php echo ( '0' === $options_key ) ? 'show' : '' // WPCS: XSS ok. ?>">
						<?php
						foreach ( $settings_array['settings_control'] as $control_name => $default_value ) {
							echo $this->twentysixteen_theme_settings_control_render( $default_value, (array) $options_value ); // WPCS: XSS ok.
						}
						wp_nonce_field( 'twentysixteen_settings_nonce_action', 'twentysixteen_settings_nonce' );
						?>
						</li>
						<?php
					}
				} else {
					?>
					<li class="settings_container show">
					<?php
					foreach ( $settings_array['settings_control'] as $control_name => $default_value ) {
						echo $this->twentysixteen_theme_settings_control_render( $default_value, null ); // WPCS: XSS ok.
					}
					wp_nonce_field( 'twentysixteen_settings_nonce_action', 'twentysixteen_settings_nonce' );
					?>
					</li>
					<?php
				} ?>
			</ul>
		</div>
		<?php
	} else {
		?>
		<div class="wrap">
			<h2 class="page_title"><?php echo esc_html( $this->subpage_name ); ?></h2>
			<p class="description"><?php esc_html_e( 'The options array seems to be empty. Please fill it up with settings to render the page.', 'twentysixteen' ); ?></p>
		</div>
		<?php
	}
}

Последний метод, который нам нужен, — это функция обратного вызова ajax.

/**
 * Settings save AJAX callback function
 *
 * @return void
 */
public function twentysixteen_all_settings_save() {
	if ( isset( $_POST['data'], $_POST['twentysixteen_settings_nonce'] ) && wp_verify_nonce( sanitize_key( $_POST['twentysixteen_settings_nonce'] ), 'twentysixteen_settings_nonce_action' ) && '' !== $_POST['data'] ) { // Input var okay.
		$twentysixteen_settings = wp_json_encode( sanitize_text_field( wp_unslash( $_POST['data'] ) ) ); // Input var okay.
		$settings_name = 'twentysixteen_' . str_replace( ' ', '_', strtolower( $this->subpage_name ) );
		update_option( $settings_name, $twentysixteen_settings );
	}
	wp_die();
}

Убедитесь, что вы проверяете сохраненные поля, проверяете одноразовый номер и очищаете текст, прежде чем помещать его в базу данных. Это очень важный аспект безопасности, потому что вы никогда не знаете, когда вы можете получить нарушение безопасности. В наш settings-style.css мы можем добавить

.twentysixteen_options_left {
	width: 30%;
	margin-left: 30px;
	display: inline-block;
	vertical-align: top;
	margin-bottom: 20px;
}

.twentysixteen_options_right {
	width: 60%;
	display: inline-block;
	vertical-align: top;
	margin-bottom: 20px;
}

и для нашего имиджа

/*****---------- 1.3 Image Field ----------*****/

.twentysixteen_uploaded_image img {
	max-width: 30%;
	margin-bottom: 20px;
}

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

Теперь, чтобы добавить вашу подстраницу, нам нужно создать новый экземпляр класса

$header_settings = new SettingsSubageBuilder( esc_html__( 'Header Settings', 'twentysixteen' ), $header_settings_array );

Вы получите что-то похожее на это:

Экран параметров заголовка настроек темы

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

add_action( 'admin_enqueue_scripts', 'twentysixteen_theme_settings_admin_scripts' );
/**
 * Enqueue style and scripts for Theme Settings page
 *
 * @since  1.0.0
 * @param  string $hook Page hook suffix where the scripts and styles should be loaded.
 * @return void
 */
function twentysixteen_theme_settings_admin_scripts( $hook ) {
	$screen = get_current_screen();
	$screen_id = $screen->id;
	if ( strpos( $screen_id, 'page_twentysixteen_theme' ) !== false ) {
		wp_enqueue_style( 'twentysixteen_theme_settings_css', get_template_directory_uri() . '/inc/theme-settings/css/settings-style.css', '', '1.0.0' );

		wp_enqueue_style( 'wp-color-picker' );
		wp_enqueue_media();
		wp_enqueue_script( 'twentysixteen_theme_settings_js', get_template_directory_uri() . '/inc/theme-settings/js/settings-custom.js', array( 'jquery', 'wp-color-picker' ), '1.0.0', true );
		wp_localize_script( 'twentysixteen_theme_settings_js', 'twentysixteen_settings_object', array(
			'saved'	 => esc_html__( 'Settings Saved', 'twentysixteen' ),
			'delete' => esc_html__( 'Delete', 'twentysixteen' ),
			'save'	 => esc_html__( 'Save', 'twentysixteen' ),
		) );
	}
}

Мы добавили палитру цветов и загрузку мультимедиа. В наш файл settings-custom.js мы добавим несколько элементов управления:

jQuery( document ).ready(function( $) {
	"use strict";

	$( document ).on('click', '#twentysixteen_settings_save', settings_save )
				 .on('click', '#twentysixteen_settings_save_subpage', settings_save_subpage )
				 .on('click', '.upload_image_button', upload_image_button )
				 .on('click', '.remove_image_button', remove_image_button )
				 .on('click', '.checkbox_label', checkbox_switch );

	color_picker();

	function checkbox_switch(e) {
		e.preventDefault();
		var $this = $(this);
		var hide_layout = $this.data('settings');
		var $hidden_input = $this.prev('input');
		var $checkbox = $this.find('.checkbox');

		if ( $checkbox.hasClass('checked') ) {
			$checkbox.removeClass('checked');
			$hidden_input.val('0');
			$( hide_layout ).hide();
		} else {
			$checkbox.addClass('checked');
			$hidden_input.val('1');
			$( hide_layout ).show();
		}
	}

	function settings_save(e) {
		e.preventDefault();
		var $saved = $('.settings_above_meta .saved_options');
		var $spinner = $('.settings_above_meta .spinner');
		var settings_out = {};
		settings_out['settings'] = {};
		settings_out['settings']['google_api_key'] = $('.twentysixteen_options_wrapper .google_api_key').val();
		settings_out['settings']['google_maps_enable'] = $('.twentysixteen_options_wrapper .google_maps_enable').val();
		$.ajax({
			type: 'POST',
			url: ajaxurl,
			data: {
				'action' : 'twentysixteen_settings_save',
				'data' : JSON.stringify( settings_out, null, 2 ),
				'twentysixteen_settings_nonce' : $('#twentysixteen_settings_nonce').val()
			},
			success: function(data) {
				$saved.text( twentysixteen_settings_object.saved ).delay( 2000 ).fadeOut();
			},
			beforeSend : function () {
				$saved.text('').show();
				$spinner.css('visibility', 'visible');
			},
			error : function (jqXHR, textStatus, errorThrown) {
				$loader.html( jqXHR + ' :: ' + textStatus + ' :: ' + errorThrown );
			},
			complete : function () {
				$spinner.css('visibility', 'hidden');
			}
		});
	}

	function settings_save_subpage(e) {
		e.preventDefault();
		var $saved = $('.settings_above_meta .saved_options');
		var $spinner = $('.settings_above_meta .spinner');                   
                var page_name = $('.page_title')[0].innerHTML; // For the ajax hook issue we had earlier
                var hook_name = 'twentysixteen_'+page_name.toLowerCase().replace(/ /g, '_' )+'_save_action';
		var settings_out = {};
		settings_out['settings'] = {};
		$('.twentysixteen_setting').each(function(){
			var $setting = $(this);
			var settings_name = $setting.attr('name');
			var settings_value;
			if ('undefined' !== typeof settings_name ) {
				if ( settings_name.indexOf('_layout') !== -1 ) {
					if ( $setting.is(':checked') ) {
						settings_value = $setting.val();
						settings_out['settings'][settings_name] = settings_value;
					}
				} else {
					settings_value = $setting.val();
					settings_out['settings'][settings_name] = settings_value;
				}
			}
		});
		$.ajax({
			type: 'POST',
			url: ajaxurl,
			data: {
				'action' : hook_name,
				'data' : JSON.stringify( settings_out, null, 2 ),
				'twentysixteen_settings_nonce' : $('#twentysixteen_settings_nonce').val()
			},
			success: function(data) {
				$saved.text( twentysixteen_settings_object.saved ).delay( 2000 ).fadeOut();
			},
			beforeSend : function () {
				$saved.text('').show();
				$spinner.css('visibility', 'visible');
			},
			error : function (jqXHR, textStatus, errorThrown) {
				$saved.html( jqXHR + ' :: ' + textStatus + ' :: ' + errorThrown );
			},
			complete : function () {
				$spinner.css('visibility', 'hidden');
				$('.save.settings_changed').removeClass('settings_changed');

			}
		});
	}

	function color_picker(e) {
		$('.twentysixteen_color_picker').each( function(){
			$(this).wpColorPicker();
		});
	}

	function upload_image_button(e) {
		e.preventDefault();
		var $this = $(e.currentTarget);
		var $input_field = $this.prev();
		var $image = $this.parent().find('.twentysixteen_uploaded_image');
		var custom_uploader = wp.media.frames.file_frame = wp.media({
			title: 'Add Image',
			button: {
				text: 'Add Image'
			},
			multiple: false
		});
		custom_uploader.on('select', function() {
			var attachment = custom_uploader.state().get('selection').first().toJSON();
			$input_field.val( attachment.url );
			$image.html('<img src="' + attachment.url + '" />');
		});
		custom_uploader.open();
	}

	function remove_image_button(e) {
		e.preventDefault();
		var $this = $(e.currentTarget);
		var $input_field = $this.parent().find('.twentysixteen_image_upload');
		var $image = $this.parent().find('.twentysixteen_uploaded_image');

		$input_field.val('');
		$image.html('');
	}

});

Мы добавили функцию сохранения ajax, палитру цветов и способ добавить изображение, вызвав загрузчик мультимедиа WordPress. Если это включено, наша страница настроек будет выглядеть так

Экран параметров заголовка настроек темы завершен

Итак, теперь, когда мы закончили это, что мы можем с этим сделать? Ну а остальное просто — вам нужны варианты нижнего колонтитула? Укажите массив настроек нижнего колонтитула и создайте экземпляр нового класса:

$footer_settings_array = array(
	'description'      => esc_html__( 'Set up settings your footer', 'twentysixteen' ),
	'settings_control' => array(
		'control_1' => array(
			'name'         => esc_html__( 'Logo', 'twentysixteen' ),
			'control_type' => 'image',
		),
		'control_2' => array(
			'name'         => esc_html__( 'Copyright', 'twentysixteen' ),
			'description'  => esc_html__( 'Set the copyright text.', 'twentysixteen' ),
			'control_type' => 'input',
		),
	),
);

$footer_settings = new SettingsSubageBuilder( esc_html__( 'Footer Settings', 'twentysixteen' ), $footer_settings_array );

Параметры нижнего колонтитула были созданы путем создания нового объекта.

Мы указали только две вещи и получили совершенно новую страницу. Гораздо проще, чем писать все с нуля, не так ли? Вот готовый файл полностью

<?php
/**
 * Theme Settings
 *
 * @package WordPress
 * @subpackage twentysixteen/inc/theme-settings
 * @version 1.0.0
 * @author  Made by Denis <http://madebydenis.com/>
 * @license https://www.gnu.org/licenses/gpl-3.0.txt GNU/GPLv3
 * @link https://twentysixteen.io
 * @since  1.0.0
 */

/**
 * Theme Settings
 *
 * @package WordPress
 * @subpackage twentysixteen/inc/theme-settings
 * @version 1.0.0
 * @author  Made by Denis <http://madebydenis.com/>
 * @license https://www.gnu.org/licenses/gpl-3.0.txt GNU/GPLv3
 * @link https://twentysixteen.io
 * @since  1.0.0
 */

add_filter( 'admin_init', 'twentysixteen_theme_settings_capability' );
/**
 * Restrict access to the theme settings page to admins
 *
 * @since  1.0.0
 * @return void If user is not administrator they won't see Theme Settings
 */
function twentysixteen_theme_settings_capability() {
	if ( ! current_user_can( 'manage_options' ) ) {
		return;
	}
}

add_action( 'admin_menu', 'twentysixteen_theme_settings_add_page' );
/**
 * Theme Settings add menu page
 *
 * @since  1.0.0
 * @return void The resulting page's hook_suffix
 */
function twentysixteen_theme_settings_add_page() {
	add_menu_page( esc_html__( 'Theme Settings', 'twentysixteen' ), esc_html__( 'Theme Settings', 'twentysixteen' ), 'edit_theme_options', 'twentysixteen_theme_settings', 'twentysixteen_settings_render_page' );
}

/**
 * Theme Settings page builder function
 *
 * @param  string $title  The title of the page.
 * @param  array  $values Array of the setting values from the database.
 * @return string         Returned compiled HTML of the page
 */
function twentysixteen_build_settings_html( $title, $values = null ) {
	$out = '';

	$value = 0;
	$checked = '';
	$maps_enabled = ( isset( $values ) && '' !== $values ) ? $values->google_maps_enable : '';

	if ( isset( $maps_enabled ) && '1' === $maps_enabled ) {
		$value = 1;
		$checked = 'checked';
	}

	$out .= '<h3>' . esc_html__( 'Settings', 'twentysixteen' ) . '</h3>
			<div class="twentysixteen_options_wrapper">
				<h4>' . esc_html__( 'Enable Google Maps', 'twentysixteen' ) . '</h4>
				<input type="hidden" class="twentysixteen_setting google_maps_enable" name="google_maps_enable" value="' . $value . '">
				<label class="checkbox_label" for="google_maps_enable" data-settings=".twentysixteen_google_maps_api_key"><span class="twentysixteen_setting checkbox ' . $checked . '"></span>' . esc_html__( 'Enable google map', 'twentysixteen' ) . '</label>
				<p class="info">' . esc_html__( 'Use this if you are not using external plugin to power the Google Maps . ', 'twentysixteen' ) . '</p>
			</div>';

	if ( isset( $maps_enabled ) && '1' === $maps_enabled ) {
		$out .= '<div class="twentysixteen_options_wrapper twentysixteen_google_maps_api_key show">
					<h4>' . esc_html__( 'Add Google Maps API key', 'twentysixteen' ) . '</h4>
					<input type="text" class="twentysixteen_setting google_api_key" name="google_api_key" value="' . esc_attr( $values->google_api_key ) . '" />
					<p class="info">' . esc_html__( 'You need to find your API key? Just click on this link: ', 'twentysixteen' ) . '<a href="https://console.developers.google.com/">' . esc_html__( 'Google API keys', 'twentysixteen' ) . '</a>.</p>
				</div>';
	} else {
		$out .= '<div class="twentysixteen_options_wrapper twentysixteen_google_maps_api_key" style="display:none;">
					<h4>' . esc_html__( 'Add Google Maps API key', 'twentysixteen' ) . '</h4>
					<input type="text" class="twentysixteen_setting google_api_key" name="google_api_key" value="" />
					<p class="info">' . esc_html__( 'You need to find your API key? Just click on this link: ', 'twentysixteen' ) . '<a href="https://console.developers.google.com/">' . esc_html__( 'Google API keys', 'twentysixteen' ) . '</a>.</p>
				</div>';
	}

	return $out;
}

/**
 * Theme Settings page render function
 *
 * @return void
 */
function twentysixteen_settings_render_page() {
	?>
	<div class="wrap">
		<h2 class="page_title"><?php esc_html_e( 'Theme Settings', 'twentysixteen' ) ?></h2>
		<p class="description"><?php esc_html_e( 'General theme settings', 'twentysixteen' ) ?></p>
		<div class="settings_above_meta">
			<a href="#" class="save_all" id="twentysixteen_settings_save"><?php esc_html_e( 'Save All', 'twentysixteen' ) ?></a>
			<span class="spinner"></span><span class="saved_options"></span>
		</div>
		<div class="theme_settings_inner_content">
			<?php
			$twentysixteen_settings = get_option( 'twentysixteen_settings', '' );
			if ( isset( $twentysixteen_settings ) && '' !== $twentysixteen_settings ) {
				foreach ( $twentysixteen_settings as $key => $values ) {
					echo twentysixteen_build_settings_html( 'Settings', $values ); // WPCS: XSS ok.
				}
			} else {
				echo twentysixteen_build_settings_html( 'Settings' ); // WPCS: XSS ok.
			}
			wp_nonce_field( 'twentysixteen_settings_nonce_action', 'twentysixteen_settings_nonce' ); ?>
		</div>
	</div><?php
}

add_action( 'wp_ajax_twentysixteen_settings_save', 'twentysixteen_settings_save_callback' );
/**
 * Settings save AJAX callback function
 *
 * @return void
 */
function twentysixteen_settings_save_callback() {
	if ( isset( $_POST['data'], $_POST['twentysixteen_settings_nonce'] ) && wp_verify_nonce( sanitize_key( $_POST['twentysixteen_settings_nonce'] ), 'twentysixteen_settings_nonce_action' ) && '' !== $_POST['data'] ) { // Input var okay.
		$twentysixteen_settings = json_decode( sanitize_text_field( wp_unslash( $_POST['data'] ) ) ); // Input var okay.
		update_option( 'twentysixteen_settings', $twentysixteen_settings );
	}
	wp_die();
}

add_action( 'admin_enqueue_scripts', 'twentysixteen_theme_settings_admin_scripts' );
/**
 * Enqueue style and scripts for Theme Settings page
 *
 * @since  1.0.0
 * @param  string $hook Page hook suffix where the scripts and styles should be loaded.
 * @return void
 */
function twentysixteen_theme_settings_admin_scripts( $hook ) {
	$screen = get_current_screen();
	$screen_id = $screen->id;
	if ( strpos( $screen_id, 'page_twentysixteen_theme' ) !== false ) {
		wp_enqueue_style( 'twentysixteen_theme_settings_css', get_template_directory_uri() . '/inc/theme-settings/css/settings-style.css', '', '1.0.0' );

		wp_enqueue_style( 'wp-color-picker' );
		wp_enqueue_media();
		wp_enqueue_script( 'twentysixteen_theme_settings_js', get_template_directory_uri() . '/inc/theme-settings/js/settings-custom.js', array( 'jquery', 'wp-color-picker' ), '1.0.0', true );
		wp_localize_script( 'twentysixteen_theme_settings_js', 'twentysixteen_settings_object', array(
			'saved'	 => esc_html__( 'Settings Saved', 'twentysixteen' ),
			'delete' => esc_html__( 'Delete', 'twentysixteen' ),
			'save'	 => esc_html__( 'Save', 'twentysixteen' ),
		) );
	}
}


/**
 * Builds Settings subpage
 *
 * @package WordPress
 * @subpackage twentysixteen/inc/theme-settings
 * @version 1.0.0
 * @author  Made by Denis <http://madebydenis.com/>
 * @license https://www.gnu.org/licenses/gpl-3.0.txt GNU/GPLv3
 * @link https://twentysixteen.io
 * @since  1.0.0
 */
class SettingsSubageBuilder {
	/**
	 * Name of the subpage menu
	 *
	 * @var string $subpage_name The name of the subpage.
	 */
	private $subpage_name;

	/**
	 * Array of elements to be used in the HTML render of the settings page
	 *
	 * @var string $subpage_name The name of the subpage.
	 */
	private $html_array;

	/**
	 * Initialization of the class
	 *
	 * @param  string $subpage_name The name of the settings page, e.g. Header Settings.
	 * @param  array  $html_array The HTML array details for building the settings page.
	 */
	public function __construct( $subpage_name, $html_array ) {
		$this->subpage_name = $subpage_name;
		$this->html_array   = $html_array;
		add_action( 'admin_menu', array( $this, 'create_submenu_pages' ) );
		add_action( 'wp_ajax_twentysixteen_settings_save_action', array( $this, 'twentysixteen_all_settings_save' ) );
	}

	/**
	 * Create submenu page for each settings
	 *
	 * @return void
	 */
	public function create_submenu_pages() {
		$page_hook = 'twentysixteen_theme_' . strtolower( str_replace( ' ', '_', $this->subpage_name ) );

		add_submenu_page( 'twentysixteen_theme_settings', $this->subpage_name, $this->subpage_name, 'edit_theme_options', $page_hook, array( $this, 'twentysixteen_settings_render_subpage' ) );
	}

	/**
	 * Settings control render function
	 *
	 * This function takes the single control value, and based on what that control is
	 * renders the appropriate control.
	 *
	 * @param  array $default_value   Array of the associated default controls with all the details of the controls.
	 * @param  array $saved_values    Array of the values from the database.
	 * @return string 				  HTML of controls.
	 */
	public function twentysixteen_theme_settings_control_render( $default_value, $saved_values ) {
		$name             = ( isset( $default_value['name'] ) && '' !== $default_value['name'] ) ? $default_value['name'] : '';
		$control_type     = ( isset( $default_value['control_type'] ) && '' !== $default_value['control_type'] ) ? $default_value['control_type'] : '';
		$description      = ( isset( $default_value['description'] ) && '' !== $default_value['description'] ) ? '<p class="description">' . $default_value['description'] . '</p>' : '';
		$control_slug     = 'twentysixteen_' . str_replace( ' ', '_', strtolower( $name ) );
		$control_settings = ( isset( $saved_values ) && '' !== $saved_values ) ? $saved_values : '';
		$value            = ( isset( $control_settings[$control_slug] ) && '' !== $control_settings[$control_slug] ) ? $control_settings[$control_slug] : '';

		$out = '';

		switch ( $control_type ) {
			case 'input':
				$out .= '<div class="twentysixteen_options_wrapper">
							<div class="twentysixteen_options_left">
								<h4>' . esc_html( $name ) . '</h4>
							</div>
							<div class="twentysixteen_options_right">
								<input type="text" name="' . esc_attr( $control_slug ) . '" value="' . esc_attr( $value ) . '" class="twentysixteen_setting">
								' . wp_kses_post( $description ) . '
							</div>
						</div>';
				break;

			case 'image':
				$out .= '<div class="twentysixteen_options_wrapper">
							<div class="twentysixteen_options_left">
								<h4>' . esc_html( $name ) . '</h4>
							</div>
							<div class="twentysixteen_options_right">
								<div class="twentysixteen_uploaded_image">
									<img src="' . esc_url( $value ) . '" />
								</div>
								<input type="text" name="' . esc_attr( $control_slug ) . '" value="' . esc_url( $value ) . '" class="twentysixteen_setting twentysixteen_image_upload">
								<input type="button" name="image_upload" value="' . esc_html__( 'Upload Image', 'twentysixteen' ) . '" class="button upload_image_button">
								<input type="button" name="remove_image_upload" value="' . esc_html__( 'Remove Image', 'twentysixteen' ) . '" class="button remove_image_button">
								' . wp_kses_post( $description ) . '
							</div>
						</div>';
				break;

			case 'checkbox':
				$checked = '';
				if ( isset( $value ) && '1' === $value ) {
					$checked = 'checked';
				}
				$out .= '<div class="twentysixteen_options_wrapper">
							<div class="twentysixteen_options_left">
								<h4>' . esc_html( $name ) . '</h4>
							</div>
							<div class="twentysixteen_options_right">
								<input type="checkbox" name="' . esc_attr( $control_slug ) . '" value="' . esc_attr( $value ) . '" ' . checked( $value, 1, false ) . ' class="twentysixteen_setting">
								<label class="checkbox_label"><span class="twentysixteen_setting checkbox ' . $checked . '"></span>' . esc_html( $name ) . '</label>
								' . wp_kses_post( $description ) . '
							</div>
						</div>';
				break;

			case 'colorpicker':
				$out .= '<div class="twentysixteen_options_wrapper">
							<div class="twentysixteen_options_left">
								<h4>' . esc_html( $name ) . '</h4>
							</div>
							<div class="twentysixteen_options_right">
								<input type="text" name="' . esc_html( $control_slug ) . '" value="' . esc_attr( $value ) . '" class="twentysixteen_setting twentysixteen_color_picker"/>
								' . wp_kses_post( $description ) . '
							</div>
						</div>';
				break;

			case 'select':
				$out .= '<div class="twentysixteen_options_wrapper">
							<div class="twentysixteen_options_left">
								<h4>' . esc_html( $name ) . '</h4>
							</div>
							<div class="twentysixteen_options_right">
								<select class="twentysixteen_setting" name="' . esc_html( $control_slug ) . '">
									<option value=""> -- </option>';
				if ( isset( $default_value['options'] ) && '' !== $default_value['options'] ) {
					foreach ( $default_value['options'] as $option_name => $option_value ) {
						$selected = ( isset( $value ) && '' !== $value && $option_name === $value ) ? 'selected="selected"' : '';
						$out .= '<option value="' . esc_attr( $option_name ) . '" ' . esc_attr( $selected ) . ' >' . esc_html( $option_value ) . '</option>';
					}
				}
						$out .= '</select>
								' . wp_kses_post( $description ) . '
							</div>
						</div>';
				break;

			default:
				break;
		}

		return $out;

	}

	/**
	 * Rendering function for settings subpage
	 *
	 * @return void HTML rendered content.
	 */
	public function twentysixteen_settings_render_subpage() {
		$settings_array = $this->html_array;

		if ( isset( $settings_array ) && ! empty( $settings_array ) ) {

			$set_options = json_decode( json_decode( get_option( 'twentysixteen_' . str_replace( ' ', '_', strtolower( $this->subpage_name ) ), '' ) ) ); // Get options from the database.

			?>
			<div class="wrap">
				<h2 class="page_title"><?php echo esc_html( $this->subpage_name ); ?></h2>
				<p class="description"><?php echo esc_html( $settings_array['description'] ); ?></p>
				<div class="settings_above_meta">
					<a href="#" class="save_all" id="twentysixteen_settings_save_subpage"><?php esc_html_e( 'Save All', 'twentysixteen' ) ?></a>
					<span class="spinner"></span><span class="saved_options"></span>
				</div>
				<ul class="theme_settings_inner_content">
					<?php
					if ( isset( $set_options ) && '' !== $set_options ) {
						foreach ( (array) $set_options as $options_key => $options_value ) {
							?>
							<li class="settings_container <?php echo ( '0' === $options_key ) ? 'show' : '' // WPCS: XSS ok. ?>">
							<?php
							foreach ( $settings_array['settings_control'] as $control_name => $default_value ) {
								echo $this->twentysixteen_theme_settings_control_render( $default_value, (array) $options_value ); // WPCS: XSS ok.
							}
							wp_nonce_field( 'twentysixteen_settings_nonce_action', 'twentysixteen_settings_nonce' );
							?>
							</li>
							<?php
						}
					} else {
						?>
						<li class="settings_container show">
						<?php
						foreach ( $settings_array['settings_control'] as $control_name => $default_value ) {
							echo $this->twentysixteen_theme_settings_control_render( $default_value, null ); // WPCS: XSS ok.
						}
						wp_nonce_field( 'twentysixteen_settings_nonce_action', 'twentysixteen_settings_nonce' );
						?>
						</li>
						<?php
					} ?>
				</ul>
			</div>
			<?php
		} else {
			?>
			<div class="wrap">
				<h2 class="page_title"><?php echo esc_html( $this->subpage_name ); ?></h2>
				<p class="description"><?php esc_html_e( 'The options array seems to be empty. Please fill it up with settings to render the page.', 'twentysixteen' ); ?></p>
			</div>
			<?php
		}
	}

	/**
	 * Settings save AJAX callback function
	 *
	 * @return void
	 */
	public function twentysixteen_all_settings_save() {
		if ( isset( $_POST['data'], $_POST['twentysixteen_settings_nonce'] ) && wp_verify_nonce( sanitize_key( $_POST['twentysixteen_settings_nonce'] ), 'twentysixteen_settings_nonce_action' ) && '' !== $_POST['data'] ) { // Input var okay.
			$twentysixteen_settings = wp_json_encode( sanitize_text_field( wp_unslash( $_POST['data'] ) ) ); // Input var okay.
			$settings_name = 'twentysixteen_' . str_replace( ' ', '_', strtolower( $this->subpage_name ) );
			update_option( $settings_name, $twentysixteen_settings );
		}
		wp_die();
	}
}

$header_settings_array = array(
	'description'      => esc_html__( 'Set up settings for different headers', 'twentysixteen' ),
	'settings_control' => array(
		'control_1' => array(
			'name'         => esc_html__( 'Fixed Header', 'twentysixteen' ),
			'description'  => esc_html__( 'Make the menu always fixed on top.', 'twentysixteen' ),
			'control_type' => 'checkbox',
		),
		'control_2' => array(
			'name'         => esc_html__( 'Logo', 'twentysixteen' ),
			'control_type' => 'image',
		),
		'control_3' => array(
			'name'         => esc_html__( 'Retina Logo', 'twentysixteen' ),
			'description'  => esc_html__( 'This logo is used only if the retina screens are detected.', 'twentysixteen' ),
			'control_type' => 'image',
		),
		'control_4' => array(
			'name'         => esc_html__( 'Retina Logo Width', 'twentysixteen' ),
			'description'  => esc_html__( 'Set the width of the original logo.', 'twentysixteen' ),
			'control_type' => 'input',
		),
		'control_5' => array(
			'name'         => esc_html__( 'Retina Logo Height', 'twentysixteen' ),
			'description'  => esc_html__( 'Set the height of the original logo.', 'twentysixteen' ),
			'control_type' => 'input',
		),
		'control_6' => array(
			'name'         => esc_html__( 'Background Image', 'twentysixteen' ),
			'control_type' => 'image',
		),
		'control_7' => array(
			'name'         => esc_html__( 'Background Color', 'twentysixteen' ),
			'description'  => esc_html__( 'Set the menu background color.', 'twentysixteen' ),
			'control_type' => 'colorpicker',
		),
		'control_8' => array(
			'name'         => esc_html__( 'Text Color', 'twentysixteen' ),
			'description'  => esc_html__( 'Set the menu items color.', 'twentysixteen' ),
			'control_type' => 'colorpicker',
		),
		'control_9' => array(
			'name'         => esc_html__( 'Text Hover Color', 'twentysixteen' ),
			'description'  => esc_html__( 'Set the menu items hover color.', 'twentysixteen' ),
			'control_type' => 'colorpicker',
		),
		'control_10' => array(
			'name'         => esc_html__( 'Options Select', 'twentysixteen' ),
			'description'  => esc_html__( 'Select the header options.', 'twentysixteen' ),
			'control_type' => 'select',
			'options' => array(
				'option_1' => esc_html__( 'Option 1', 'twentysixteen' ),
				'option_2' => esc_html__( 'Option 2', 'twentysixteen' ),
				'option_3' => esc_html__( 'Option 3', 'twentysixteen' ),
				'option_4' => esc_html__( 'Option 4', 'twentysixteen' ),
			),
		),
	),
);

$footer_settings_array = array(
	'description'      => esc_html__( 'Set up settings your footer', 'twentysixteen' ),
	'settings_control' => array(
		'control_1' => array(
			'name'         => esc_html__( 'Logo', 'twentysixteen' ),
			'control_type' => 'image',
		),
		'control_2' => array(
			'name'         => esc_html__( 'Copyright', 'twentysixteen' ),
			'description'  => esc_html__( 'Set the copyright text.', 'twentysixteen' ),
			'control_type' => 'input',
		),
	),
);

$header_settings = new SettingsSubageBuilder( esc_html__( 'Header Settings', 'twentysixteen' ), $header_settings_array );
$footer_settings = new SettingsSubageBuilder( esc_html__( 'Footer Settings', 'twentysixteen' ), $footer_settings_array );

И css (файл JavaScript приведен выше)

/*

[Table of Contents]

1. Theme Settings General
	1.1 Checkbox
	1.2 Input Field
	1.3 Image Field

*/

/*************** 1. Theme Settings General ***************/
.theme_settings_inner_content {
	padding: 30px;
	background: #fff;
	margin-top: 20px;
}

.settings_above_meta .save_all {
	text-decoration: none;
	background: #ddd;
	border-radius: 3px;
	margin-top: 15px;
	text-transform: uppercase;
	padding: 8px 10px;
	display: inline-block;
	color: #4e4a4a;
	-webkit-transition: all 200ms ease-in;
	transition: all 200ms ease-in;
}

.settings_above_meta .save_all:hover {
	background: #ccc;
}

.settings_above_meta .save_all:active,
.settings_above_meta .save_all:focus {
	border: 0;
	box-shadow: none;
	outline: 0;
}

.settings_above_meta .spinner {
	background: url(spinner.gif) no-repeat;
	-webkit-background-size: 20px 20px;
	background-size: 20px 20px;
	display: inline-block;
	visibility: hidden;
	float:none;
	vertical-align: middle;
	opacity: .7;
	filter: alpha(opacity=70);
	width: 20px;
	height: 20px;
	margin: -2px 10px 0;
}

.settings_above_meta .saved_options {
	color: #3eb72f;
	font-weight: 600;
	text-transform: uppercase;
}

.twentysixteen_options_left {
	width: 30%;
	margin-left: 30px;
	display: inline-block;
	vertical-align: top;
	margin-bottom: 20px;
}

.twentysixteen_options_right {
	width: 60%;
	display: inline-block;
	vertical-align: top;
	margin-bottom: 20px;
}

/*****---------- 1.1 Checkbox ----------*****/
input[type="checkbox"].twentysixteen_setting {
	display: none;
}

.checkbox_label{
	-webkit-touch-callout: none;
	-webkit-user-select: none;
	-khtml-user-select: none;
	-moz-user-select: none;
	-ms-user-select: none;
	user-select: none;
}

.twentysixteen_setting.checkbox {
	width: 25px;
	height: 25px;
	background: #fff;
	border: 1px solid #ddd;
	border-radius: 3px;
	margin-right: 20px;
	display: inline-block;
	vertical-align: middle;
	position: relative;
}

.twentysixteen_setting.checkbox:before {
	content: '✔';
	color: transparent;
	position: absolute;
	top: 5px;
	left: 6px;
	font-size: 19px;
	line-height: 0.8;
	-webkit-transition: all 150ms ease-in;
	transition: all 150ms ease-in;
}

.twentysixteen_setting.checkbox.checked:before {
	content: '✔';
	color: #2bb1ef;
}

/*****---------- 1.2 Input Field ----------*****/
.twentysixteen_options_wrapper input[type="text"] {
	background: #fff;
	border: 1px solid #ddd;
	padding: 3px 10px;
	border-radius: 3px;
	box-shadow: none;
}

.twentysixteen_options_wrapper input[type="text"]:active,
.twentysixteen_options_wrapper input[type="text"]:focus {
	border: 1px solid #ddd;
	box-shadow: none;
	outline: 0;
}

/*****---------- 1.3 Image Field ----------*****/

.twentysixteen_uploaded_image img {
	max-width: 30%;
	margin-bottom: 20px;
}

Теперь все, что вам нужно сделать при вызове опций из базы данных, это вытащить ее с помощью

$header_options = json_decode( json_decode( get_option( 'twentysixteen_header_settings', '' ) ), true );

Помните, что вы сохранили свой параметр в функции обратного вызова ajax, которая использовала ярлык вашей темы, и имя подстраницы параметра (нижние заглавные буквы и подчеркивание вместо пробела).

Вот и все, надеюсь, вы узнали что-то новое, и что объектно-ориентированное программирование теперь не кажется таким страшным. Это отличный способ решить некоторые проблемы. Конечно, это лишь малая часть того, на что способен oop, но это отличное начало для новичков. Если у вас есть какие-либо вопросы, оставьте их ниже, и, как всегда: удачного кодирования :)

Первоначально опубликовано на сайте Сделано Денисом.