¿Cómo selecciono una imagen de la Biblioteca de Medios en mi plugin?
He escrito un plugin que tiene un pequeño ícono de chat en la esquina inferior derecha, sin embargo, quiero que el usuario pueda elegir una imagen como ícono desde la Biblioteca de Medios
. ¿Cómo puedo hacer esto con la API de WordPress? La imagen es un ajuste en el plugin (solo modificable por el administrador)

Deberías usar wp.media
para utilizar el cuadro de diálogo del Gestor de Medios de WordPress.
Primero, necesitas encolar los scripts:
// Como estás trabajando con ajustes del plugin,
// asumo que estás en el área de administración
add_action( 'admin_enqueue_scripts', 'load_wp_media_files' );
function load_wp_media_files( $page ) {
// cambia a la $page donde quieras encolar el script
if( $page == 'options-general.php' ) {
// Encolar scripts de medios de WordPress
wp_enqueue_media();
// Encolar script personalizado que interactuará con wp.media
wp_enqueue_script( 'myprefix_script', plugins_url( '/js/myscript.js' , __FILE__ ), array('jquery'), '0.1' );
}
}
Tu HTML podría ser algo como esto (nota que mi código usa el ID del adjunto en el ajuste del plugin en lugar de la URL de la imagen como hiciste en tu respuesta, creo que es mucho mejor. Por ejemplo, usar el ID te permite obtener diferentes tamaños de imagen cuando los necesites):
$image_id = get_option( 'myprefix_image_id' );
if( intval( $image_id ) > 0 ) {
// Cambia con el tamaño de imagen que quieras usar
$image = wp_get_attachment_image( $image_id, 'medium', false, array( 'id' => 'myprefix-preview-image' ) );
} else {
// Alguna imagen por defecto
$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( 'Seleccionar una imagen', '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();
}
// Definir image_frame como objeto wp.media
image_frame = wp.media({
title: 'Seleccionar Medio',
multiple : false,
library : {
type : 'image',
}
});
image_frame.on('close',function() {
// Al cerrar, obtener selecciones y guardar en el input oculto
// además de otras cosas AJAX para refrescar la vista previa de la imagen
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;//si se cierra sin seleccionar una imagen
jQuery('input#myprefix_image_id').val(ids);
Refresh_Image(ids);
});
image_frame.on('open',function() {
// Al abrir, obtener el ID del input oculto
// y seleccionar las imágenes apropiadas en el gestor de medios
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();
});
});
// Solicitud Ajax para refrescar la vista previa de la imagen
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 );
}
});
}
Y la acción Ajax para refrescar la vista previa de la imagen:
// Acción Ajax para refrescar la imagen del usuario
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();
}
}
PD: es un ejemplo rápido escrito aquí basado en otra respuesta. No probado porque no proporcionaste suficiente información sobre el contexto exacto en el que se usará el código o los problemas exactos que tienes.

La llamada ajax get_image no es necesaria. El selection.models[0].attributes.url
contiene la URL de la imagen seleccionada al cerrar el image_frame
. Si deseas usar un tamaño específico, necesitarás la llamada ajax.

Fácil de usar, solo copia y pega el código en el lugar requerido
<?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' alt="Vista previa de imagen" title="Vista previa de la imagen seleccionada">
</div>
<input id="upload_image_button" type="button" class="button" value="<?php _e( 'Subir imagen' ); ?>" />
<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="Guardar" 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( $ ) {
// Carga de archivos
var file_frame;
var wp_media_post_id = wp.media.model.settings.post.id; // Almacena el ID antiguo
var set_to_post_id = <?php echo $my_saved_attachment_post_id; ?>; // Establece este
jQuery('#upload_image_button').on('click', function( event ){
event.preventDefault();
// Si el marco de medios ya existe, reabrirlo
if ( file_frame ) {
// Establecer el ID de publicación que queremos
file_frame.uploader.uploader.param( 'post_id', set_to_post_id );
// Abrir marco
file_frame.open();
return;
} else {
// Establecer el ID de publicación de wp.media para que el cargador obtenga el ID deseado al inicializarse
wp.media.model.settings.post.id = set_to_post_id;
}
// Crear el marco de medios
file_frame = wp.media.frames.file_frame = wp.media({
title: 'Selecciona una imagen para subir',
button: {
text: 'Usar esta imagen',
},
multiple: false // Establecer en true para permitir selección múltiple
});
// Cuando se selecciona una imagen, ejecutar una devolución de llamada
file_frame.on( 'select', function() {
// Establecemos múltiple a false para obtener solo una imagen del cargador
attachment = file_frame.state().get('selection').first().toJSON();
// Hacer algo con attachment.id y/o attachment.url aquí
$( '#image-preview' ).attr( 'src', attachment.url ).css( 'width', 'auto' );
$( '#image_attachment_id' ).val( attachment.id );
// Restaurar el ID de publicación principal
wp.media.model.settings.post.id = wp_media_post_id;
});
// Finalmente, abrir el modal
file_frame.open();
});
// Restaurar el ID principal cuando se presiona el botón agregar medios
jQuery( 'a.add_media' ).on( 'click', function() {
wp.media.model.settings.post.id = wp_media_post_id;
});
});
</script>

Así que esta respuesta funcionó perfectamente. Pero para hacerla reutilizable, convertí el código en una función. Entonces, para usar esto, primero debes revisar esto para enqueue
el script. Y luego declarar wpOpenGallery
así:
(function($) {
$(document).ready(function() {
const wpOpenGallery = function(o, callback) {
const options = (typeof o === 'object') ? o : {};
// Configuraciones predefinidas
const defaultOptions = {
title: 'Seleccionar medios',
fileType: 'image',
multiple: false,
currentValue: '',
};
const opt = { ...defaultOptions, ...options };
let image_frame;
if(image_frame){
image_frame.open();
}
// Define image_frame como objeto wp.media
image_frame = wp.media({
title: opt.title,
multiple : opt.multiple,
library : {
type : opt.fileType,
}
});
image_frame.on('open',function() {
// Al abrir, obtén el id del input oculto
// y selecciona las imágenes apropiadas en el administrador de medios
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() {
// Al cerrar, obtén las selecciones y guárdalas en el input oculto
// más otras cosas AJAX para actualizar la vista previa de la imagen
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));
Y llámalo así:
wpOpenGallery(null, function(data) {
console.log(data);
});

Utiliza wordpress-settings-api-class
de Tareq Hasan, URL: https://github.com/tareq1988/wordpress-settings-api-class
- Incluye la clase principal
class.settings-api.php
en tu plugin. (este archivo https://github.com/tareq1988/wordpress-settings-api-class/blob/master/src/class.settings-api.php) - Define tus opciones. Necesitas usar
'type' => 'file'
ya que deseas agregar un cargador de medios. (Consulta este ejemplo para una mejor comprensión https://github.com/tareq1988/wordpress-settings-api-class/blob/master/example/procedural-example.php)

Creo que una solución sin bibliotecas adicionales es mejor, más sólida; como el wp.media
control.

Como deseas que el ícono sea diferente para cada usuario, tendrás que almacenar la imagen en el perfil del usuario. Esto significa que necesitas agregar un campo de usuario adicional:
// crear el campo
add_action( 'show_user_profile', 'wpse_235406_chaticon' );
add_action( 'edit_user_profile', 'wpse_235406_chaticon' );
function wpse_235406_chaticon ($user) {
echo '
<h3>Ícono de Chat</h3>
<table class="form-table">
<tr>
<th><label for="chaticon">Ícono de Chat</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">Por favor selecciona tu ícono de chat.</span>
</td>
</tr>
</table>';
}
// guardar el campo
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']);
}
Ahora, esto te da la posibilidad de subir un archivo desde la computadora del usuario. Si deseas que el usuario seleccione el archivo de imágenes existentes, las cosas se complican más, porque entonces necesitas llamar a la biblioteca de medios en lugar de la carga de archivos predeterminada. Steven Slack ha escrito un excelente artículo sobre cómo hacer esto, cuyo código no quiero copiar y pegar aquí para no apropiarme del crédito.
En tu plantilla debes distinguir tres posibilidades: usuario no conectado, usuario conectado pero sin ícono, usuario conectado y con ícono. Básicamente, incluye esto:
$current_user = wp_get_current_user();
if ( 0 == $current_user->ID ) {
... haz lo que quieras hacer para usuarios no conectados ...
}
else {
$icon = get_user_meta ($current_user->ID, 'chaticon');
if (empty($icon)) {
... ícono predeterminado con enlace a la posibilidad de subir uno ...
}
else {
... muestra $icon ...
}

¿Te refieres a que solo el administrador del sitio debería poder cambiar el icono y será el mismo para cada visitante/usuario?

Eso sería bastante trivial. Aquí hay un tutorial para eso: https://mikejolley.com/2012/12/21/using-the-new-wordpress-3-5-media-uploader-in-plugins/

Utilicé esta solución (sin usar directamente la Biblioteca de Medios):
Usando image-picker-lib dentro de un modal que establece el valor de un input oculto, el cual se envía a las opciones. Al obtener todos los medios y mostrarlos como opciones, permito que el usuario seleccione una imagen.
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">
cambiar
</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">Elegir</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();
+ });

Creo que una solución sin bibliotecas adicionales es mejor, sólida; como el wp.media
control.

@bueltge Estoy de acuerdo, pero nadie dio una respuesta directa y necesitaba una solución rápida. Así que si alguien da una gran respuesta, ¡se lleva la recompensa!

Veo tu respuesta también como una solución, pero no la mejor manera. Ahora es parte del autor de la pregunta, tú ;), tomar la decisión.

Esta solución puede convertirse rápidamente en un problema a medida que aumenta el número de imágenes. "nadie dio una respuesta directa" no es una excusa; tu pregunta es muy pobre, por eso obtienes respuestas pobres. No nos muestras ningún esfuerzo, investigación o código que hayas intentado, solo "quiero hacer esto, dame una solución lista para usar", que es lo mismo que "haz el trabajo por mí". Busca wp.media como sugirió bueltge; hay cientos de ejemplos aquí en WPSE. Si tienes problemas al usarlo, publica una nueva pregunta al respecto.

@cybmeta lo intenté y este es mi mejor intento, así que no seas grosero al respecto. Si no te gusta, propón una mejor solución.

wp.media
es la mejor opción que tienes y eso es lo que propongo; intenta usarlo y, si tienes dudas al respecto, pregúntalas. He escrito varias respuestas sobre el uso de wp.media
al igual que otras personas, intenta usar el cuadro de búsqueda (o Google), intenta tú mismo y publica preguntas sobre los problemas que puedas encontrar al usarlo. Lamento si mis comentarios te parecen malos, te quejaste de no obtener buenas respuestas, solo intenté explicarte por qué. Honestamente, creo que deberías tomar mi comentario sin ofenderte y aprender a evitar malas preguntas.

Por cierto, cuando dije "no nos muestras ningún esfuerzo, investigación o código que hayas intentado" me refería a tu pregunta. Pensé que mi comentario era claro al respecto, tal vez no lo fue y debería haber publicado ese comentario en la pregunta y no en la respuesta. De todos modos, he añadido una respuesta; espero que te sea útil.
