Добавление загрузчика изображений в метабокс и на страницу настроек WordPress

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

Итак, что в итоге у нас получится. Во-первых, вот так будет выглядеть поле для загрузки изображения (само собой, вы можете оформить его и по-другому):

Произвольное поле загрузки изображения

При нажатии на кнопку «Загрузить» будет открываться всплывающее окно загрузчика медиафайлов WordPress:

Загрузчик медиафайлов WordPress

Окей, выбираем картинку из медиатеки или загружаем новую и нажимаем кнопу «Вставить в запись». В итоге:

Изображение загружено, но еще не сохранено

Вот и всё, осталось только сохранить пост.

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

Если же вы ищете готовое решение, то могу предложить вам три PHP класса (метабоксы постов, метабоксы таксономий, страницы настроек), в которых загрузчик изображений уже реализован, тогда вам сюда.

Шаг 1. Код jQuery

Хочу обратить ваше внимание, что данный jQuery-код будет отлично работать только с тем кодом HTML, который предоставлен в шаге 3. Поэтому, если вы не разбираетесь в jQuery, старайтесь в нем ничего не менять, не переставлять элементы местами и т.д.

Что делать с этим кодом? Создайте какой-нибудь файл с расширением .js, затем залейте его в папку с вашей темой WordPress. Я например создал файл admin.js.

Код можете скопировать как есть, он полностью рабочий и не требует какой-либо настройки.

jQuery(function($){
	/*
	 * действие при нажатии на кнопку загрузки изображения
	 * вы также можете привязать это действие к клику по самому изображению
	 */
	$('.upload_image_button').click(function(){
		var send_attachment_bkp = wp.media.editor.send.attachment;
		var button = $(this);
		wp.media.editor.send.attachment = function(props, attachment) {
			$(button).parent().prev().attr('src', attachment.url);
			$(button).prev().val(attachment.id);
			wp.media.editor.send.attachment = send_attachment_bkp;
		}
		wp.media.editor.open(button);
		return false;    
	});
	/*
	 * удаляем значение произвольного поля
	 * если быть точным, то мы просто удаляем value у input type="hidden"
	 */
	$('.remove_image_button').click(function(){
		var r = confirm("Уверены?");
		if (r == true) {
			var src = $(this).parent().prev().attr('data-src');
			$(this).parent().prev().attr('src', src);
			$(this).prev().prev().val('');
		}
		return false;
	});
});

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

Если на моём блоге вы совсем недавно и еще не знаете про правильное подключение JavaScript и CSS в WordPress, можете сперва почитать про wp_enqueue_script(), wp_enqueue_style() и wp_enqueue_media() или же можете сразу вставить следующий код в ваш файл темы functions.php:

1
2
3
4
5
6
7
8
9
10
11
12
function true_include_myuploadscript() {
	// у вас в админке уже должен быть подключен 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 );
}
 
add_action( 'admin_enqueue_scripts', 'true_include_myuploadscript' );

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

Шаг 3. PHP-функция добавления полей в форму

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

function true_image_uploader_field( $name, $value = '', $w = 115, $h = 90) {
	$default = get_stylesheet_directory_uri() . '/img/no-image.png';
	if( $value ) {
		$image_attributes = wp_get_attachment_image_src( $value, array($w, $h) );
		$src = $image_attributes[0];
	} else {
		$src = $default;
	}
	echo '
	<div>
		<img data-src="' . $default . '" src="' . $src . '" width="' . $w . 'px" height="' . $h . 'px" />
		<div>
			<input type="hidden" name="' . $name . '" id="' . $name . '" value="' . $value . '" />
			<button type="submit" class="upload_image_button button">Загрузить</button>
			<button type="submit" class="remove_image_button button">&times;</button>
		</div>
	</div>
	';
}

Готово! Функционал загрузчика добавлен. Теперь только осталось задействовать его в метабоксе или на странице настроек (в зависимости от того, какая задача перед вами стоит).

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

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

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

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

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

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

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

<?php
function true_add_options_page_u() {
	if ( isset( $_GET['page'] ) && $_GET['page'] == 'uplsettings' ) {
		if ( isset( $_REQUEST['action'] ) && 'save' == $_REQUEST['action'] ) {
			update_option('uploader_custom', $_REQUEST[ 'uploader_custom' ]);
			header("Location: ". site_url() ."/wp-admin/options-general.php?page=uplsettings&saved=true");
			die;
		}
	}
	add_submenu_page('options-general.php','Дополнительные настройки','Настройки','edit_posts', 'uplsettings', 'true_print_options_u');
}
 
function true_print_options_u() {
	if ( isset( $_REQUEST['saved'] ) ){
		echo '<div class="updated"><p>Сохранено.</p></div>';
	}
	?><div class="wrap">
		<form method="post">
			<?php 
			if( function_exists( 'true_image_uploader_field' ) ) {
				true_image_uploader_field('uploader_custom', get_option('uploader_custom'));
			}
			?><p class="submit">
				<input name="save" type="submit" class="button-primary" value="Сохранить изменения" />
				<input type="hidden" name="action" value="save" />
			</p>
		</form>
 
	</div><?php
}
 
add_action('admin_menu', 'true_add_options_page_u');

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

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

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

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

  • Андрей26 июля 2014 в 09:07 #

    Хорошая статья, но вот админка реально устаревшего типа, лучше бы под стандартное API настроек подточили.
    Больше всего интересовал сам вызов медиа загрузчика) Спасибо!

    • Миша26 июля 2014 в 10:07 #

      Относительно последнего примера — да, я так и написал в посту, над будет доработать :)

  • Dima7 августа 2014 в 20:08 #

    Классно все, но вопрос такой: как теперь вставить картинку в single? какой командой?

  • егор19 августа 2014 в 06:08 #

    Аффигенно то что надо автору респект!)

  • Амира25 сентября 2014 в 02:09 #

    А как добавить 2-ю картинку, 3 и т.д
    Заранее благодарна..

    • Миша25 сентября 2014 в 08:09 #

      Ну в заполнении метабокса это делается так:

      true_image_uploader_field( 'uploader_custom1', get_post_meta($post->ID, 'uploader_custom1',true) );
      true_image_uploader_field( 'uploader_custom2', get_post_meta($post->ID, 'uploader_custom2',true) );

      И в функции сохранения не забудьте указать:

      update_post_meta( $post_id, 'uploader_custom1', $_POST['uploader_custom1']);
      update_post_meta( $post_id, 'uploader_custom2', $_POST['uploader_custom2']);
  • Амира27 сентября 2014 в 00:09 #

    Спасибо все работает :D

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

    Спасибо за статью! Очень сложно найти инф по использованию стандартного загрузчика.
    Пытаюсь переделать пример под свою задачу - прикрепление файлов (инструкций) пользователями к товарам. Т.е. хочу запустить стандартный загрузчик и получить от него ссылку на загруженный файл, и больше ничего. Возможно ли это?

  • Александр26 октября 2014 в 13:10 #

    Вызываю в теме echo get_option('uploader_custom') и мне выдает числовое значение, копировал все по 10 раз. все пути перепроверил по 50 раз, все правильно, но изображение я вывести не могу

    • Александр II26 октября 2014 в 16:10 #

      Чтобы заработало, нужно:
      - код jQuery из шага 1. Он запускает аплодер вордпресса по клику и получает выбранный файл (в function(props, attachment) {...). Можно написать туда свой код. Аплодер возвращает только 1 файл, хотя выделить в нем можно несколько.

      - правильно подключить скрипты в шаге 2 -

      add_action( 'admin_enqueue_scripts', 'true_include_myuploadscript' );

      admin_enqueue_scripts - только для админки
      wp_enqueue_scripts - для внешней части сайта
      login_enqueue_scripts - для страницы входа

  • Smile14 января 2015 в 01:01 #

    Добрый день. Не подскажете как вывести картинку в пост.
    Пробовал

    <?php echo get_post_meta($post->ID, 'uploader_custom', true); ?>

    Он выводит то-ли ID записи то-ли что, вообщем цифры.
    Посмотрел в админке значения поле - uploader_custom, те-же цифры что и выводятся.
    Заранее благодарен..

    • Миша14 января 2015 в 09:01 #

      Добрый день!
      Можете использовать одну из этих функций.

      • Сергей11 апреля 2015 в 21:04 #

        Не могу понять как вывести теперь эти картинки на странице? проовал использовать функции которые вы предложили ничего не получается

    • Артем15 апреля 2015 в 12:04 #
      <?php
      $attachment_id = get_post_meta($post->ID, 'landshaft_uploader_custom',true);
      $attributes = wp_get_attachment_image_src( $attachment_id, array(32, 32) );
       
      if (!empty($attachment_id)) {
           echo '<img src="' . $attributes[0] . '" width="' . $attributes[1] . '" height="' . $attributes[2] . '" alt="" />';
      } else {
           echo 'Нету прикрепленного файла.';
      }
      ?>
  • Smile14 января 2015 в 03:01 #

    Со знанием PHP у меня не очень.. Так что Как то сделал, но при нажатии кнопки удалить, картинка сразу не удаляется, надо обновить пост тогда картинки не станет. А так все работает, выбираешь картинку (в поле uploader_custom - записывается url картинки). и миниатюра вместо картинки по умолчанию встает как положено. Прошу подправить код.

    Заранее благодарен.

    wp.media.editor.send.attachment = function(props, attachment) {
    $(button).parent().prev().attr('src', attachment.url);
    /*$(button).prev().val(attachment.id);*/
    $(button).prev().val(attachment.url);  /*Тут вместо ID поставил url*/
    wp.media.editor.send.attachment = send_attachment_bkp;
    // Тут добавил условие if else
    function amira_image_uploader_field( $name, $value = '', $w = 115, $h = 90) {
    	$default = get_stylesheet_directory_uri() . '/img/logo.png';
    	if( $value ) {
    		$image_attributes = wp_get_attachment_image_src( $value, array($w, $h) );
    		$src = $image_attributes[0];
    	} 
    	else {
    		$src = $value;
    	}
    	if ($value) {
    		$src = $value;
    	}
    	else {
    		$src = $default;
    	}
    	echo '
    	<div>
    		<img data-src="' . $value . '" src="' . $src . '" width="' . $w . 'px" height="' . $h . 'px" />
    		<div>
    			<input type="hidden" name="' . $name . '" id="' . $name . '" value="' . $value . '" />
    			<button type="submit" class="upload_image_button button">Загрузить</button>
    			<button type="submit" class="remove_image_button button">&times;</button>
    		</div>
    	</div>
    	';
    }
    • Миша14 января 2015 в 08:01 #

      В первом листинге кода вместо button должен быть класс или ID элементов.

    • Иван25 марта 2016 в 21:03 #

      Smile привет, нашел решение. В первом листинге кода оставляешь все как есть.
      Дальше переходишь в файл functions.php
      Ищи учаток кода:

      function true_image_uploader_field( $name, $value = '', $w = 253, $h = 132) {
      	$default = 'http://mysite.com/thumbnail.png';//Если картинка не установлена, выбирает эту фотку
      	if( $value ) {
      		$image_attributes = wp_get_attachment_image_src( $value, array($w, $h) );
      		$src = $value;

      И меняй его как у меня.. все работает))

  • Thorny6 февраля 2015 в 00:02 #

    Замечательный мануал, спасибо.
    Но все же еще остался не раскрытым вопрос мультивыбора.
    В медаизагрузчике есть возможность выбирать сразу несколько файлов.
    Как получить в JS все выбранные объекты?

    Действительно тема в нете не особо широко освещена, видимо, потому что это уже глубоко узкоспециальный материал :) но все же, мне интересно как организовать мультивыбор, но полчаса поиска не дали результата...

    • Миша6 февраля 2015 в 08:02 #

      Есть вот такой вариант, не тестировал правда:

      $('.upload_image_button').click(function(e) {
      	e.preventDefault();
      	var button = $(this);
      	var custom_uploader = wp.media({
      		title: 'Заголовок',
      		button: {
      			text: 'Текст кнопки'
      		},
      		multiple: false  // Тут и нужно установить true для мультизагрузки
      	}).on('select', function() {
      		var attachment = custom_uploader.state().get('selection').first().toJSON();
      		$(button).parent().prev().attr('src', attachment.url);
      		$(button).prev().val(attachment.id);
      	}).open();
      });
  • Максим12 февраля 2015 в 13:02 #

    Спасибо Вам огромное!

  • Алексей16 февраля 2015 в 03:02 #

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

    Я конечно понимаю что этот пример возможно не подходит для моей ситуации но может вы подскажите хоть что то) а то плагины ставить не хочу

    • Миша16 февраля 2015 в 08:02 #

      Добрый день!
      Используйте after() для вставки этого плюсика и live('click', ) для нажатия на него.

      • VRS8 декабря 2015 в 04:12 #

        Вот про это было бы очень интересно почитать. Как твой стандартный класс для метабоксов (https://truemisha.ru/blog/wordpress/meta-boxes.html) сделать с динамическим добавлением новых произвольных полей, с одним ключом, но разными значениями.
        Или может уже есть у тебя статья, ткни в меня ссылкой)).

  • Гость19 апреля 2015 в 01:04 #

    В js консоли Uncaught TypeError: Cannot read property 'value' of null, версия WP 4.1.1

  • Михаил6 мая 2015 в 17:05 #

    Михаил!Добрый день Михаил! Воспользовался вашим кодом – всё работает,
    Но получаю изображение размером 150х150, а нужно в полный размер.
    Подскажите пожалуйста, как получить картинку в полный размер.

  • Михаил6 мая 2015 в 18:05 #

    Разобрался сам :)
    $attributes = wp_get_attachment_image_src( $attachment_id, 'full' );

  • Андрей9 мая 2015 в 23:05 #

    А не могли бы вы подсказать, как реализовать подобный загрузчик в плагине?
    Сейчас делаю плагин, в одном из пунктов в котором человек должен выбрать\загрузить картинку и хотелось бы все реализовать родными ресурсами WP.

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

    • Миша10 мая 2015 в 09:05 #

      Ну тут сходу ничего не ответить — нужно писать код. Если у вас будут более конкретные вопросы, постараюсь помочь.

  • Матвей15 мая 2015 в 21:05 #

    Добрый день! Подскажите, как сделать чтобы эту форму мог видеть только админ сайта? Чтобы редакторы и авторы ее не видели.

  • Андрей12 июня 2015 в 19:06 #

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

  • Алекксандр28 июля 2015 в 17:07 #

    А как эту форму добавить вот сюда https://truemisha.ru/blog/wordpress/option-pages.html
    никак не могу понять как его добавть в секцию, например section_3 и использовать в дальнейшем.

    • Миша28 июля 2015 в 21:07 #

      Ну в очень общих чертах:

      case 'uploader':
      	echo "<fieldset>";
      	if( function_exists( 'true_image_uploader_field' ) ) {
      		true_image_uploader_field( $option_name . '[$id]', $v );
      	}
      	echo "</fieldset>";
      break;
  • Афоня6 августа 2015 в 12:08 #

    Можно мне объяснить что это или что оно делает wp.media.editor.send.attachment?

  • Джамал25 августа 2015 в 23:08 #

    Успешно портировал ваш код для того что бы создать Виджет.
    Всё отлично работает только через какое то время на странице виджетов в консоли получаю следующую ошибку: TypeError: document.getElementById(...) is null
    Она не сильно мешает, но правда при любом действии с любым Виджетом, происходит обновление страницы. Не могли бы вы подсказать с чем это связано ? С этой ошибкой или ещё как ?

    Спасибо.

    P.S: Могу скинуть код Виджета, вы бы могли бы его добавить в статью.

    • Миша31 августа 2015 в 14:08 #

      Сорри за задержку с ответом — был в отъезде.

      Проблема явно в JavaScript. Вам нужно искать, где у вас пустое значение document.getElementById(...).

  • Rodion31 августа 2015 в 23:08 #

    Вот что записывает скрипт: http://SSMaker.ru/2b77a594/

  • Александр9 ноября 2015 в 18:11 #

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

    public function true_include_myuploadscript() {
    			// у вас в админке уже должен быть подключен jQuery, если нет - раскомментируйте следующую строку:
    			// wp_enqueue_script('jquery');
    			// дальше у нас идут скрипты и стили загрузчика изображений WordPress
    			if ( !did_action( 'wp_enqueue_media' ) ) {
    				wp_enqueue_media();
    			}
    			// само собой - меняем admin.js на название своего файла
    			wp_enqueue_script( 'myuploadscript', plugins_url('assets/js/uploader.js', dirname(__FILE__)), array('jquery'), null, false );
    		}
  • Александр10 ноября 2015 в 09:11 #

    да, все правильно. Сегодня утром зашел, поменял кодировку и все начало работать. Спасибо))

  • Иван25 марта 2016 в 19:03 #

    Как сделать чтобы в значении «uploader_custom» прописывался не id картинки а её url?
    Спасибо!

  • Иван25 марта 2016 в 21:03 #

    ответ нашел

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

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

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

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

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

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