Как выбрать изображение из Медиа Библиотеки в моём плагине?
Я написал плагин, в котором есть маленькая иконка чата в правом нижнем углу, однако я хочу дать пользователю возможность выбирать изображение для этой иконки из Media Library
(Медиа Библиотеки). Как это можно реализовать с помощью WordPress API? Изображение является настройкой плагина (изменяемой только администратором)

Для использования диалогового окна WordPress Media Manager следует использовать wp.media
.
Сначала необходимо подключить скрипты:
// Поскольку мы работаем с настройками плагина,
// предполагаем, что находимся в админке
add_action( 'admin_enqueue_scripts', 'load_wp_media_files' );
function load_wp_media_files( $page ) {
// измените на нужную страницу, где требуется подключить скрипт
if( $page == 'options-general.php' ) {
// Подключаем стандартные скрипты WordPress для медиа
wp_enqueue_media();
// Подключаем кастомный скрипт для взаимодействия с wp.media
wp_enqueue_script( 'myprefix_script', plugins_url( '/js/myscript.js' , __FILE__ ), array('jquery'), '0.1' );
}
}
HTML может выглядеть так (обратите внимание, что в моём коде используется ID вложения в настройках плагина вместо URL изображения, как в вашем ответе - это более правильный подход, так как позволяет получать изображения разных размеров при необходимости):
$image_id = get_option( 'myprefix_image_id' );
if( intval( $image_id ) > 0 ) {
// Укажите нужный размер изображения
$image = wp_get_attachment_image( $image_id, 'medium', false, array( 'id' => 'myprefix-preview-image' ) );
} else {
// Изображение по умолчанию
$image = '<img id="myprefix-preview-image" src="https://some.default.image.jpg" />';
}
echo $image; ?>
<input type="hidden" name="myprefix_image_id" id="myprefix_image_id" value="<?php echo esc_attr( $image_id ); ?>" class="regular-text" />
<input type='button' class="button-primary" value="<?php esc_attr_e( 'Выбрать изображение', 'mytextdomain' ); ?>" id="myprefix_media_manager"/>
myscript.js
jQuery(document).ready( function($) {
jQuery('input#myprefix_media_manager').click(function(e) {
e.preventDefault();
var image_frame;
if(image_frame){
image_frame.open();
}
// Определяем image_frame как объект wp.media
image_frame = wp.media({
title: 'Выбор медиа',
multiple : false,
library : {
type : 'image',
}
});
image_frame.on('close',function() {
// При закрытии получаем выбранные элементы и сохраняем в скрытое поле
// плюс AJAX-запрос для обновления превью изображения
var selection = image_frame.state().get('selection');
var gallery_ids = new Array();
var my_index = 0;
selection.each(function(attachment) {
gallery_ids[my_index] = attachment['id'];
my_index++;
});
var ids = gallery_ids.join(",");
if(ids.length === 0) return true;//если закрыто без выбора изображения
jQuery('input#myprefix_image_id').val(ids);
Refresh_Image(ids);
});
image_frame.on('open',function() {
// При открытии получаем ID из скрытого поля
// и выбираем соответствующие изображения в медиабиблиотеке
var selection = image_frame.state().get('selection');
var ids = jQuery('input#myprefix_image_id').val().split(',');
ids.forEach(function(id) {
var attachment = wp.media.attachment(id);
attachment.fetch();
selection.add( attachment ? [ attachment ] : [] );
});
});
image_frame.open();
});
});
// AJAX-запрос для обновления превью изображения
function Refresh_Image(the_id){
var data = {
action: 'myprefix_get_image',
id: the_id
};
jQuery.get(ajaxurl, data, function(response) {
if(response.success === true) {
jQuery('#myprefix-preview-image').replaceWith( response.data.image );
}
});
}
AJAX-действие для обновления превью изображения:
// AJAX-действие для обновления изображения
add_action( 'wp_ajax_myprefix_get_image', 'myprefix_get_image' );
function myprefix_get_image() {
if(isset($_GET['id']) ){
$image = wp_get_attachment_image( filter_input( INPUT_GET, 'id', FILTER_VALIDATE_INT ), 'medium', false, array( 'id' => 'myprefix-preview-image' ) );
$data = array(
'image' => $image,
);
wp_send_json_success( $data );
} else {
wp_send_json_error();
}
}
Примечание: это быстрый пример, написанный здесь на основе другого ответа. Не тестировался, так как вы не предоставили достаточно информации о точном контексте использования кода или конкретных проблемах, с которыми столкнулись.

Ajax-вызов get_image не обязателен. selection.models[0].attributes.url
содержит URL выбранного изображения при закрытии image_frame
. Если вам нужен определенный размер, тогда потребуется ajax-вызов.

Просто скопируйте и вставьте код в нужное место
<?php
if ( isset( $_POST['submit_image_selector'] ) && isset( $_POST['image_attachment_id'] ) ) :
update_option( 'media_selector_attachment_id', absint( $_POST['image_attachment_id'] ) );
endif;
wp_enqueue_media();
?><form method='post'>
<div class='image-preview-wrapper'>
<img id='image-preview' src='<?php echo wp_get_attachment_url( get_option( 'media_selector_attachment_id' ) ); ?>' width='200'>
</div>
<input id="upload_image_button" type="button" class="button" value="<?php _e( 'Загрузить изображение' ); ?>" />
<input type='hidden' name='image_attachment_id' id='image_attachment_id' value='<?php echo get_option( 'media_selector_attachment_id' ); ?>'>
<input type="submit" name="submit_image_selector" value="Сохранить" class="button-primary">
</form>
<?php
$my_saved_attachment_post_id = get_option( 'media_selector_attachment_id', 0 );
?><script type='text/javascript'>
jQuery( document ).ready( function( $ ) {
// Загрузка файлов
var file_frame;
var wp_media_post_id = wp.media.model.settings.post.id; // Сохраняем старый ID
var set_to_post_id = <?php echo $my_saved_attachment_post_id; ?>; // Устанавливаем этот ID
jQuery('#upload_image_button').on('click', function( event ){
event.preventDefault();
// Если фрейм уже существует, открываем его снова
if ( file_frame ) {
// Устанавливаем нужный post_id
file_frame.uploader.uploader.param( 'post_id', set_to_post_id );
// Открываем фрейм
file_frame.open();
return;
} else {
// Устанавливаем post_id для wp.media, чтобы загрузчик использовал нужный ID при инициализации
wp.media.model.settings.post.id = set_to_post_id;
}
// Создаем медиа-фрейм
file_frame = wp.media.frames.file_frame = wp.media({
title: 'Выберите изображение для загрузки',
button: {
text: 'Использовать это изображение',
},
multiple: false // Установите true, чтобы разрешить выбор нескольких файлов
});
// При выборе изображения выполняем callback
file_frame.on( 'select', function() {
// Мы установили multiple в false, поэтому получаем только одно изображение
attachment = file_frame.state().get('selection').first().toJSON();
// Делаем что-то с attachment.id и/или attachment.url
$( '#image-preview' ).attr( 'src', attachment.url ).css( 'width', 'auto' );
$( '#image_attachment_id' ).val( attachment.id );
// Восстанавливаем основной post ID
wp.media.model.settings.post.id = wp_media_post_id;
});
// Открываем модальное окно
file_frame.open();
});
// Восстанавливаем основной ID при нажатии кнопки добавления медиа
jQuery( 'a.add_media' ).on( 'click', function() {
wp.media.model.settings.post.id = wp_media_post_id;
});
});
</script>

Итак, этот ответ сработал идеально. Но чтобы сделать его переиспользуемым, я преобразовал код в функцию. Таким образом, для использования вам сначала нужно ознакомиться с этим, чтобы enqueue
скрипт. Затем объявите wpOpenGallery
следующим образом:
(function($) {
$(document).ready(function() {
const wpOpenGallery = function(o, callback) {
const options = (typeof o === 'object') ? o : {};
// Предустановленные настройки
const defaultOptions = {
title: 'Выбрать медиафайл',
fileType: 'image',
multiple: false,
currentValue: '',
};
const opt = { ...defaultOptions, ...options };
let image_frame;
if(image_frame){
image_frame.open();
}
// Определяем image_frame как объект wp.media
image_frame = wp.media({
title: opt.title,
multiple : opt.multiple,
library : {
type : opt.fileType,
}
});
image_frame.on('open',function() {
// При открытии получаем ID из скрытого поля
// и выбираем соответствующие изображения в медиабиблиотеке
const selection = image_frame.state().get('selection');
const ids = opt.currentValue.split(',');
ids.forEach(function(id) {
const attachment = wp.media.attachment(id);
attachment.fetch();
selection.add( attachment ? [ attachment ] : [] );
});
});
image_frame.on('close',function() {
// При закрытии получаем выбранные элементы и сохраняем в скрытое поле
// плюс другие AJAX-действия для обновления превью изображения
const selection = image_frame.state().get('selection');
const files = [];
selection.each(function(attachment) {
files.push({
id: attachment.attributes.id,
filename: attachment.attributes.filename,
url: attachment.attributes.url,
type: attachment.attributes.type,
subtype: attachment.attributes.subtype,
sizes: attachment.attributes.sizes,
});
});
callback(files);
});
image_frame.open();
}
})
}(jQuery));
И вызывайте её так:
wpOpenGallery(null, function(data) {
console.log(data);
});

Используйте wordpress-settings-api-class
от Tareq Hasan, URL: https://github.com/tareq1988/wordpress-settings-api-class
- Подключите основной класс
class.settings-api.php
в вашем плагине. (этот файл https://github.com/tareq1988/wordpress-settings-api-class/blob/master/src/class.settings-api.php) - Определите свои настройки. Вам нужно использовать
'type' => 'file'
, так как вы хотите добавить загрузчик медиафайлов. (Смотрите этот пример для лучшего понимания https://github.com/tareq1988/wordpress-settings-api-class/blob/master/example/procedural-example.php)

Я считаю, что решение без дополнительных библиотек лучше, надежнее, например, как wp.media
контрол.

Поскольку вам нужна уникальная иконка для каждого пользователя, вам необходимо сохранять изображение в профиле пользователя. Это означает, что нужно добавить дополнительное поле для пользователя:
// создаем поле
add_action( 'show_user_profile', 'wpse_235406_chaticon' );
add_action( 'edit_user_profile', 'wpse_235406_chaticon' );
function wpse_235406_chaticon ($user) {
echo '
<h3>Иконка чата</h3>
<table class="form-table">
<tr>
<th><label for="chaticon">Иконка чата</label></th>
<td>
<input type="file" name="chaticon" id="chaticon" value="' . esc_attr (get_the_author_meta ('chaticon', $user->ID)) . '" class="file-upload" /><br />
<span class="description">Пожалуйста, выберите иконку для чата.</span>
</td>
</tr>
</table>';
}
// сохраняем поле
add_action( 'personal_options_update', 'wpse_235406_chaticon_save' );
add_action( 'edit_user_profile_update', 'wpse_235406_chaticon_save' );
function wpse_235406_chaticon_save ($user_id) {
if (current_user_can ('edit_user', $user_id))
update_usermeta ($user_id, 'chaticon', $_POST['chaticon']);
}
Теперь у вас есть возможность загружать файл с компьютера пользователя. Если вы хотите, чтобы пользователь выбирал файл из существующих изображений, задача усложняется, так как вам нужно вызвать медиатеку вместо стандартной загрузки файлов. Стивен Слэк написал отличную статью о том, как это сделать, и я не хочу копировать его код, выдавая за свой.
В вашем шаблоне нужно учитывать три варианта: пользователь не авторизован, пользователь авторизован, но без иконки, пользователь авторизован и имеет иконку. Вкратце, добавьте следующее:
$current_user = wp_get_current_user();
if ( 0 == $current_user->ID ) {
... действия для неавторизованных пользователей ...
}
else {
$icon = get_user_meta ($current_user->ID, 'chaticon');
if (empty($icon)) {
... стандартная иконка со ссылкой на возможность загрузки ...
}
else {
... отображение $icon ...
}

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

Это было бы довольно просто. Вот руководство по этому поводу: https://mikejolley.com/2012/12/21/using-the-new-wordpress-3-5-media-uploader-in-plugins/

Я использовал это решение (без использования самой Медиатеки):
Используя библиотеку image-picker внутри модального окна, которая устанавливает значение скрытого input, передаваемое в настройки. Получая все медиафайлы и выводя их как варианты, я позволяю пользователю выбрать изображение.
HTML
<input id="image" name="image" class="validate" type="image" src="<?php echo esc_attr(get_option('image_url')); ?>" id="image_url" width="48" height="48" />
<br>
<a href="#imageModal" class="waves-effect waves-light btn modal-trigger">
изменить
</a>
<input id="image_url" name="image_url" type="text" value="" hidden />
PHP/HTML
<div id="imageModal" class="modal">
<div class="modal-content">
<select class="image-picker show-html">
<option data-img-src="<?php echo CM_PATH . "/img/chat_general.png" ?>" value="0"></option>
<?php
$query_images_args = array(
'post_type' => 'attachment',
'post_mime_type' => 'image',
'post_status' => 'inherit',
'posts_per_page' => - 1,
);
$query_images = new WP_Query( $query_images_args );
$i = 1;
foreach ( $query_images->posts as $image ) {
?>
<option data-img-src="<?php echo wp_get_attachment_url($image->ID); ?>" value="<?php echo $i; ?>"></option>
<?php
$i ;
}
?>
</select>
</div>
<div class="modal-footer">
<a class="waves-effect waves-light btn change">Выбрать</a>
</div>
</div>
</div>
</div>
JS
$(".change").on("click", function() {
+ var url = $(".image-picker > option:selected").attr("data-img-src");
+ $("#image").attr("src", url);
+ $("#image_url").attr("value", url);
+ $("#imageModal").closeModal();
+ });

Я считаю, что решение без дополнительных библиотек лучше, более надежное; например, как элемент управления wp.media
.

@bueltge Я согласен, но никто не дал прямого ответа, а у меня был дефицит времени. Так что если кто-то предложит отличное решение — он получит награду!

Я вижу твой ответ тоже как решение, но не самое оптимальное. Теперь автор вопроса (то есть ты) должен принять решение.

Это решение может быстро стать проблемой по мере увеличения количества изображений. "никто не дал прямого ответа" — это не оправдание; ваш вопрос очень слабый, поэтому вы получаете слабые ответы. Вы не показали нам никаких усилий, исследований или кода, который вы пробовали, просто "я хочу сделать это, дайте готовое решение", что равносильно "сделайте работу за меня". Поищите wp.media, как предложил bueltge; здесь, в WPSE, сотни примеров. Если у вас возникнут проблемы с его использованием, задайте новый вопрос об этом.

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

wp.media
— это лучший вариант, который у вас есть, и именно его я предлагаю; попробуйте использовать его, и если у вас возникнут вопросы, задайте их. Я написал несколько ответов об использовании wp.media
, как и другие люди, попробуйте воспользоваться поиском (или Google), попробуйте сами и задавайте вопросы о проблемах, с которыми столкнётесь. Извините, если мои комментарии показались вам грубыми, вы жаловались на отсутствие хороших ответов, я просто попытался объяснить, почему. Честно говоря, я думаю, вам стоит воспринимать мой комментарий без обид и научиться избегать плохих вопросов.

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