Добавление поля загрузки изображения в метабоксы и на страницы настроек

В этом уроке я покажу вам два способа, как можно создать поле с возможностью загрузки изображений, и мы сразу добавим его в метабокс и на страницу настроек кстати. В первом способе мы всё сделаем ручками, а во втором – воспользуемся плагином (Carbon Fields).

Также, в этом уроке я подразумеваю, что вы уже знаете, что такое мета-поля в WordPress, если нет, то рекомендую срочно посмотреть мой видеоурок про них.

Давайте же посмотрим, что мы будем создавать!

Поле с загрузкой изображения WordPress
Ближе к концу этого урока у нас будет готова полноценная страница настроек с полем загрузки изображения на ней. Кстати, я покажу, как внутри этого модального окна поменять текст кнопки «Вставить в запись» и заголовок «Добавить медиафайл».

Создание поля

1. JavaScript код медиазагрузчика wp.media

Если быть точным, то jQuery. Почему мы не используем чистый JS для этой цели? Да потому что в этом нет большого смысла в админке WordPress, там jQuery и так подключается и поэтому даже правильнее будет использовать его.

jQuery(function($){
	/*
	 * действие при нажатии на кнопку загрузки изображения
	 * вы также можете привязать это действие к клику по самому изображению
	 */
	$('.upload_image_button').click(function( event ){
 
		event.preventDefault();
 
		const button = $(this);
 
		const customUploader = wp.media({
			title: 'Выберите изображение плз',
			library : {
				// uploadedTo : wp.media.view.settings.post.id, // если для метобокса и хотим прилепить к текущему посту
				type : 'image'
			},
			button: {
				text: 'Выбрать изображение' // текст кнопки, по умолчанию "Вставить в запись"
			},
			multiple: false
		});
 
		// добавляем событие выбора изображения
		customUploader.on('select', function() {
 
			const image = customUploader.state().get('selection').first().toJSON();
 
			button.parent().prev().attr( 'src', image.url );
			button.prev().val( image.id );
 
		});
 
		// и открываем модальное окно с выбором изображения
		customUploader.open();
	});
	/*
	 * удаляем значение произвольного поля
	 * если быть точным, то мы просто удаляем value у <input type="hidden">
	 */
	$('.remove_image_button').click(function( event){
 
		event.preventDefault();
 
		if ( true == confirm( "Уверены?" ) ) {
			const src = $(this).parent().prev().data('src');
			$(this).parent().prev().attr('src', src);
			$(this).prev().prev().val('');
		}
	});
});

Хотел бы прояснить несколько моментов по этому коду:

  • Если JavaScript код вводит вас в замешательство, а ключевые слова const и let вызывают вопросы, то очень рекомендовал бы вам свой видеокурс по JavaScript и jQuery с нуля.
  • Мы тут можем заметить объект wp.media, он становится для нас доступным именно благодаря тому, что во втором шаге мы воспользуемся функцией wp_enqueue_media() внутри хука admin_enqueue_scripts при подключении скриптов.
  • Обратите внимание на перемещения по DOM, я неоднократно использовал prev() и parent(), это на самом деле то, на что нужно обратить внимание в третьем шаге, а если быть точным, то на порядок HTML элементов.
  • И я же всё ещё не сказал вам, куда вставлять этот код! Его можно вставить в произвольный .js файл, который мы подключим уже в следующем шаге, я к примеру создам в папке темы пустой admin.js файл и там и размещу код.
  • Вы можете заметить, что при создании фрейма customUploader я задавал параметры title и button.text, они позволяют заметить текст заголовка модального окна и текст кнопки добавления изображения соответственно, вот что у нас получится по факту:
модальное окно загрузки изображения wp.media

2. Подключаем скрипты в админку через wp_enqueue_script() и wp_enqueue_media()

Если вы не совсем знакомы с тем, что мы делаем в этом шаге, то рекомендую посмотреть видеоинструкцию про правильное подключение CSS и JS файлов в WordPress.

add_action( 'admin_enqueue_scripts', 'true_include_myuploadscript' );
 
function true_include_myuploadscript( $hook ) {
	// у вас в админке уже должен быть подключен jQuery, если нет - раскомментируйте следующую строку:
	// wp_enqueue_script('jquery');
	// дальше у нас идут скрипты и стили загрузчика изображений WordPress
	if ( ! did_action( 'wp_enqueue_media' ) ) {
		wp_enqueue_media();
	}
	// само собой - меняем admin.js на название своего файла
 	wp_enqueue_script( 'myuploadscript', get_stylesheet_directory_uri() . '/admin.js', array('jquery'), null, false );
}

Немного прокомментирую код выше.

  • Во-первых, если вы не представляете, куда его вставлять, то читаем это.
  • Во-вторых, если вы не хотите подключать wp_enqueue_media() на всех страницах админки, то это можно обернуть в условие, например использовав переменную $hook, доступную внутри функции.
  • В-третьих, про функцию wp_enqueue_script() и get_stylesheet_directory_uri() можете почитать отдельно, сейчас лишь скажу, что файл admin.js должен лежать в папке с текущей темой.

3. Функция для вывода поля загрузки изображения

Эта функция в первозданном виде тоже отправляется в файл functions.php (предполагая, что мы работаем с темой WordPress), единственное только вы можете поменять URL изображения, которое будет отображаться по умолчанию (вторая строка, переменная $default).

function true_image_uploader_field( $args ) {
	// следующая строчка нужна только для использования на страницах настроек
	$value = get_option( $args[ 'name' ] );
	// следующая строчка нужна только для использования в мета боксах
	$value = $args[ 'value' ];
	$default = get_stylesheet_directory_uri() . '/placeholder.png';
 
	if( $value && ( $image_attributes = wp_get_attachment_image_src( $value, array( 150, 110 ) ) ) ) {
		$src = $image_attributes[0];
	} else {
		$src = $default;
	}
	echo '
	<div>
		<img data-src="' . $default . '" src="' . $src . '" width="150" />
		<div>
			<input type="hidden" name="' . $args[ 'name' ] . '" id="' . $args[ 'name' ] . '" value="' . $value . '" />
			<button type="submit" class="upload_image_button button">Загрузить</button>
			<button type="submit" class="remove_image_button button">×</button>
		</div>
	</div>
	';
}

Вы можете подумать, что это абсолютно произвольная функция, но не спешите себя радовать – я не случайно использовал всего лишь один аргумент $args и передавал параметры в неё в виде массива, почему было принято такое решение, вы узнаете в главе про создание страницы настроек ниже.

Также тут важен порядок элементов всех HTML элементов <div> ,<img>, <button>, и <input type="hidden" />, потому что ещё в первой главе, в JavaScript-коде я перемещаюсь по дереву DOM методами prev() и parent(). Это тоже не случайно! Мы не можем использовать классы для каждого элемента, потому что если вдруг на одной странице у нас будет несколько таких загрузчиков, то работать будет только первый из них!

Использование в метабоксах

Код добавления метабокса — я максимально упростил его, для того, чтобы была понятна суть, но очень рекомендую ознакомиться с руководством по метабоксам на моём сайте.

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

И ещё кое-что, и наверное это очень важный момент! Метабоксы – это то, что мы можем использовать в тех типах записей, в которых отключен редактор Gutenberg! Для Gutenberg метабоксы не поддерживаются и оставлены лишь для обратной совместимости! Там вам следует использовать специальные сайдбары и создавать их да, на JavaScript.

/*
 * Добавляем метабокс
 */
add_action( 'add_meta_boxes', 'true_meta_boxes_u' );
 
function true_meta_boxes_u() {
	add_meta_box( 'truediv', 'Настройки', 'true_print_box_u', 'post', 'normal', 'high' );
}
 
/*
 * Заполняем метабокс
 */
function true_print_box_u( $post ) {
	if( function_exists( 'true_image_uploader_field' ) ) {
		true_image_uploader_field( array(
			'name' => 'uploader_custom',
			'value' => get_post_meta( $post->ID, 'uploader_custom', true ),
		) );
	}
}
 
/*
 * Сохраняем данные произвольного поля
 */
add_action('save_post', 'true_save_box_data_u');
function true_save_box_data_u( $post_id ) {
 
	// ... тут различные проверки на права пользователя, на тип поста, на то, что не автосохранение и т д
 
	if( isset( $_POST[ 'uploader_custom' ] ) ) {
		update_post_meta( $post_id, 'uploader_custom', absint( $_POST[ 'uploader_custom' ] ) );
	}
	return $post_id;
 
}

В результате у меня получился вот такой метабокс:

поле загрузки изображения внутри метабокса

Использование на странице настроек

В этой главе вас ждёт готовый код, который вы можете вставить либо в functions.php текущей темы, либо читайте здесь, куда.

Также у меня есть подробнейший урок про создание страниц настроек в WordPress.

class trueOptionsPage{
 
	public $page_slug;
	public $option_group;
 
	function __construct() {
		// это у нас используется много где, поэтому давайте вынесем как отдельное свойство
		$this->page_slug = 'true_image';
		$this->option_group = 'true_image_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-format-image', 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, 'true_image_field_id', 'absint' );
 
		add_settings_section( 'image_settings_section_id', '', '', $this->page_slug );
 
		add_settings_field(
			'true_image_field_id',
			'Изображение',
			'true_image_uploader_field', // а вот эта наша функция кстати!
			$this->page_slug,
			'image_settings_section_id',
			array( 'name' => 'true_image_field_id' )
		);
 
	}
 
 
	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();

Пожалуй самое интересное, на что тут можно обратить внимание, это использование функции add_settings_field() на строчках 43-50, потому что 3-м аргументом мы передаём в неё название функции, которую мы создавали в шаге 3, а последним параметром – массив $args, являющийся единственным аргументом этой функции!

Окей, результат вы уже знаете, но почему бы не показать вам его ещё один раз:

Поле с загрузкой изображения WordPress

Делаем то же самое при помощи плагина Carbon Fields

О, а сейчас вас ждёт мега-прикол!

Вы по сути поймёте, почему сейчас редко кто пилит метабоксы и страницы настроек вручную.

Сначала давайте взглянем на то, как создать поле изображения при помощи Carbon Fields для метабокса. И да, вот ссылка на подробное руководство по Carbon Fields.

Container::make( 'post_meta', 'Настройки' )
	->where( 'post_type', '=', 'post' )
	->add_fields( array(
 
		Field::make( 'image', 'true_image', 'Изображение' )
 
	) );

Результат:

Создание поля загрузки изображения при помощи плагина Carbon Fields

А теперь готовый готовый код, как сделать это для страницы настроек.

Container::make( 'theme_options', 'Настройки изображения' )
	->set_icon( 'dashicons-format-image' )
	->set_page_menu_title( 'Изображение' )
	->set_page_menu_position( 20 )
	->add_fields( array(
 
		Field::make( 'image', 'true_image', 'Изображение' )
 
	) );
Поле загрузки изображения внутри страницы настроек Carbon Fields
Соглашусь, что страница настроек выглядит чуть менее приятно, чем та, которую мы создавали ручками, но вы только подумайте – всего 9 строчек кода вместо 150!

Миша

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

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

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

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

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

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

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