В этом уроке я покажу вам два способа, как можно создать поле с возможностью загрузки изображений, и мы сразу добавим его в метабокс и на страницу настроек кстати. В первом способе мы всё сделаем ручками, а во втором – воспользуемся плагином (Carbon Fields).
Также, в этом уроке я подразумеваю, что вы уже знаете, что такое мета-поля в WordPress, если нет, то рекомендую срочно посмотреть мой видеоурок про них.
Давайте же посмотрим, что мы будем создавать!
Если быть точным, то 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(''); } }); });
Хотел бы прояснить несколько моментов по этому коду:
const
и let
вызывают вопросы, то очень рекомендовал бы вам свой видеокурс по JavaScript и jQuery с нуля.wp.media
, он становится для нас доступным именно благодаря тому, что во втором шаге мы воспользуемся функцией wp_enqueue_media()
внутри хука admin_enqueue_scripts
при подключении скриптов.prev()
и parent()
, это на самом деле то, на что нужно обратить внимание в третьем шаге, а если быть точным, то на порядок HTML элементов.admin.js
файл и там и размещу код.customUploader
я задавал параметры title
и button.text
, они позволяют заметить текст заголовка модального окна и текст кнопки добавления изображения соответственно, вот что у нас получится по факту:Если вы не совсем знакомы с тем, что мы делаем в этом шаге, то рекомендую посмотреть видеоинструкцию про правильное подключение 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
, доступную внутри функции.admin.js
должен лежать в папке с текущей темой.Эта функция в первозданном виде тоже отправляется в файл 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
, являющийся единственным аргументом этой функции!
Окей, результат вы уже знаете, но почему бы не показать вам его ещё один раз:
О, а сейчас вас ждёт мега-прикол!
Вы по сути поймёте, почему сейчас редко кто пилит метабоксы и страницы настроек вручную.
Сначала давайте взглянем на то, как создать поле изображения при помощи Carbon Fields для метабокса. И да, вот ссылка на подробное руководство по Carbon Fields.
Container::make( 'post_meta', 'Настройки' ) ->where( 'post_type', '=', 'post' ) ->add_fields( array( Field::make( 'image', 'true_image', 'Изображение' ) ) );
Результат:
А теперь готовый готовый код, как сделать это для страницы настроек.
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', 'Изображение' ) ) );
Чтобы оставить комментарий, пожалуйста, зарегистрируйтесь или войдите.
Хорошая статья, но вот админка реально устаревшего типа, лучше бы под стандартное API настроек подточили.
Больше всего интересовал сам вызов медиа загрузчика) Спасибо!
Относительно последнего примера — да, я так и написал в посту, над будет доработать :)
Классно все, но вопрос такой: как теперь вставить картинку в single? какой командой?
Как обычно, через редактор.
get_option('uploader_custom')
Аффигенно то что надо автору респект!)
Рад помочь :)
А как добавить 2-ю картинку, 3 и т.д
Заранее благодарна..
Ну в заполнении метабокса это делается так:
И в функции сохранения не забудьте указать:
Спасибо все работает :D
Пожалуйста :D
Спасибо за статью! Очень сложно найти инф по использованию стандартного загрузчика.
Пытаюсь переделать пример под свою задачу - прикрепление файлов (инструкций) пользователями к товарам. Т.е. хочу запустить стандартный загрузчик и получить от него ссылку на загруженный файл, и больше ничего. Возможно ли это?
Пожалуйста :) если я вас правильно понял, то да.
Вызываю в теме echo get_option('uploader_custom') и мне выдает числовое значение, копировал все по 10 раз. все пути перепроверил по 50 раз, все правильно, но изображение я вывести не могу
Чтобы заработало, нужно:
- код jQuery из шага 1. Он запускает аплодер вордпресса по клику и получает выбранный файл (в function(props, attachment) {...). Можно написать туда свой код. Аплодер возвращает только 1 файл, хотя выделить в нем можно несколько.
- правильно подключить скрипты в шаге 2 -
admin_enqueue_scripts - только для админки
wp_enqueue_scripts - для внешней части сайта
login_enqueue_scripts - для страницы входа
Добрый день. Не подскажете как вывести картинку в пост.
Пробовал
Он выводит то-ли ID записи то-ли что, вообщем цифры.
Посмотрел в админке значения поле - uploader_custom, те-же цифры что и выводятся.
Заранее благодарен..
Добрый день!
Можете использовать одну из этих функций.
Не могу понять как вывести теперь эти картинки на странице? проовал использовать функции которые вы предложили ничего не получается
Какие пробовали?
Спасибо большое! Работает)
Со знанием PHP у меня не очень.. Так что Как то сделал, но при нажатии кнопки удалить, картинка сразу не удаляется, надо обновить пост тогда картинки не станет. А так все работает, выбираешь картинку (в поле uploader_custom - записывается url картинки). и миниатюра вместо картинки по умолчанию встает как положено. Прошу подправить код.
Заранее благодарен.
В первом листинге кода вместо button должен быть класс или ID элементов.
Smile привет, нашел решение. В первом листинге кода оставляешь все как есть.
Дальше переходишь в файл functions.php
Ищи учаток кода:
И меняй его как у меня.. все работает))
Замечательный мануал, спасибо.
Но все же еще остался не раскрытым вопрос мультивыбора.
В медаизагрузчике есть возможность выбирать сразу несколько файлов.
Как получить в JS все выбранные объекты?
Действительно тема в нете не особо широко освещена, видимо, потому что это уже глубоко узкоспециальный материал :) но все же, мне интересно как организовать мультивыбор, но полчаса поиска не дали результата...
Есть вот такой вариант, не тестировал правда:
Спасибо Вам огромное!
Добрый день, подскажите в какую сторону капать если мне нужно что бы после того как пользователь выбрал картинку появилась еще одна пуская картинка или же был некий плюсик на который когда я клацаю добавляется еще одна картинка.
Я конечно понимаю что этот пример возможно не подходит для моей ситуации но может вы подскажите хоть что то) а то плагины ставить не хочу
Добрый день!
Используйте
after()
для вставки этого плюсика иlive('click', )
для нажатия на него.Вот про это было бы очень интересно почитать. Как твой стандартный класс для метабоксов (https://misha.agency/blog/wordpress/meta-boxes.html) сделать с динамическим добавлением новых произвольных полей, с одним ключом, но разными значениями.
Или может уже есть у тебя статья, ткни в меня ссылкой)).
Сейчас новый класс пишу, может в январе уже опубликую его:)
В js консоли Uncaught TypeError: Cannot read property 'value' of null, версия WP 4.1.1
Спасибо. Я гляну, в чем проблема.
Такая же ошибка и у меня в консоли.. Не подскажите, в чём дело и как поправить? Спасибо.
проблема все еще актуальна
Михаил!Добрый день Михаил! Воспользовался вашим кодом – всё работает,
Но получаю изображение размером 150х150, а нужно в полный размер.
Подскажите пожалуйста, как получить картинку в полный размер.
Разобрался сам :)
$attributes = wp_get_attachment_image_src( $attachment_id, 'full' );
А не могли бы вы подсказать, как реализовать подобный загрузчик в плагине?
Сейчас делаю плагин, в одном из пунктов в котором человек должен выбрать\загрузить картинку и хотелось бы все реализовать родными ресурсами WP.
Правда, отличие в том, что нужно после того как человек загрузил картинку получить ссылку на неё, которая дальше будет вносится в БД плагина и использоваться на сайте.
Ну тут сходу ничего не ответить — нужно писать код. Если у вас будут более конкретные вопросы, постараюсь помочь.
Добрый день! Подскажите, как сделать чтобы эту форму мог видеть только админ сайта? Чтобы редакторы и авторы ее не видели.
Добрый день!
Спасибо очень выручил ваш метод!
А как эту форму добавить вот сюда https://misha.agency/blog/wordpress/option-pages.html
никак не могу понять как его добавть в секцию, например section_3 и использовать в дальнейшем.
Ну в очень общих чертах:
Можно мне объяснить что это или что оно делает wp.media.editor.send.attachment?
Делает AJAX-запрос и получает данные изображения.
Подскажите где можно об это почитать более подробно
Поищите по запросу API media editor WordPress.
Успешно портировал ваш код для того что бы создать Виджет.
Всё отлично работает только через какое то время на странице виджетов в консоли получаю следующую ошибку: TypeError: document.getElementById(...) is null
Она не сильно мешает, но правда при любом действии с любым Виджетом, происходит обновление страницы. Не могли бы вы подсказать с чем это связано ? С этой ошибкой или ещё как ?
Спасибо.
P.S: Могу скинуть код Виджета, вы бы могли бы его добавить в статью.
Сорри за задержку с ответом — был в отъезде.
Проблема явно в JavaScript. Вам нужно искать, где у вас пустое значение
document.getElementById(...)
.Вот что записывает скрипт: http://SSMaker.ru/2b77a594/
И? :) Вижу название произвольного поля и ID аттачмента.
Для всех постом просто записывает "69" и все. не url на картинку, не чего вообще
Тут нужно смотреть код и разбираться, сходу не скажу.
Очень интересная и полезная статья. Попытался сделать добавление через плагин. Не подскажите почему, не отображается список файлов в библиотеке и не могу ничего загрузить.
В функции true_include_myuploadscript() переделал под плагин таким образом
Все скрипты проверяли? 404 нет? порядок верный?
да, все правильно. Сегодня утром зашел, поменял кодировку и все начало работать. Спасибо))
Как сделать чтобы в значении «uploader_custom» прописывался не id картинки а её url?
Спасибо!
ответ нашел
Михаил, здравствуйте. По датам отзывов вижу, что шансов получить ответ мало, но, кто не рискует...Недавно начала изучать WP. Использую Ваш код, спасибо, очень помогло. Для вывода изображений на странице записи использую следующий код:
Проблема, собственно вот в чем. У меня выводятся даже те изображения, которые были удалены/заменены в произвольных полях. Т.е., я так понимаю, в БД или где-то там еще, удаленные/замененные изображения остаются числится за записью, хотя в произвольных полях все замены происходят корректно. Как решить эту проблему, не подскажите? Спасибо.
Добрый день Наталья,
А ведь ваш код выводит все изображения, прикреплённые к посту. Если нужно брать из произвольных полей, используйте функцию get_post_meta().
Спасибо за помощь и за указание верного направления, Миша, большое спасибо!
Пожалуйста! 🙃
Спасибо за этот урок. У меня есть вопрос, могли бы вы мне помочь? :)
Я немного усложнил задачу. К коду из вашего урока я добавил кнопку, по нажатию на которую добавляется столько загрузчиков изображений, сколько мне нужно и все работает, кроме одного.
После добавления нового ряда, не работает кнопка "Загрузить", она просто обновляет страницу. Но после того, как страница перезагрузится, этот новый добавленный загрузчик сохраняется, и если я снова нажму на кнопку "Загрузить" - откроется загрузчик изображений и дальше все ок. Такое происходит с каждой новой кнопкой "Загрузить".
Я думаю, что wordpress сразу не видит html, который я вставляю с помощью jQuery, а при перезагрузки запоминает все произвольные поля и потом может с ними работать. Но я не знаю, так ли это и как это можно исправить. Может вы подскажете?
Доброго времени суток!
Подсакижте, пожалуйста, что-то не до конца понял как привязать метабокс с загрузкой изображений к админке меток товаров. Делал по Вашей инструкции.
Получилось добавить изображения для меток товаров http://prntscr.com/1rrj6yf
Но, не получается добавить метабокс внутрь, чтобы делать привязку http://prntscr.com/1rrjnv8