I have written a plugin in which you have a small chat icon in the bottom right corner, however I want the user to be able to choose an image as the icon from the Media Library
. How can I do this with the Wordpress API? The image is a setting in the plugin (only changable by the admin)
6 Answers
You should use wp.media
to use the WordPress Media Manager dialog.
First, you need to enqueue the scritps:
// As you are dealing with plugin settings,
// I assume you are in admin side
add_action( 'admin_enqueue_scripts', 'load_wp_media_files' );
function load_wp_media_files( $page ) {
// change to the $page where you want to enqueue the script
if( $page == 'options-general.php' ) {
// Enqueue WordPress media scripts
wp_enqueue_media();
// Enqueue custom script that will interact with wp.media
wp_enqueue_script( 'myprefix_script', plugins_url( '/js/myscript.js' , __FILE__ ), array('jquery'), '0.1' );
}
}
Your HTML could be something like this (note my code use attachment ID in the plugin setting instead of image url as you did in your answer, I think it is much better. For example, using ID allows you to get different images sizes when you need them):
$image_id = get_option( 'myprefix_image_id' );
if( intval( $image_id ) > 0 ) {
// Change with the image size you want to use
$image = wp_get_attachment_image( $image_id, 'medium', false, array( 'id' => 'myprefix-preview-image' ) );
} else {
// Some default image
$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( 'Select a image', '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();
}
// Define image_frame as wp.media object
image_frame = wp.media({
title: 'Select Media',
multiple : false,
library : {
type : 'image',
}
});
image_frame.on('close',function() {
// On close, get selections and save to the hidden input
// plus other AJAX stuff to refresh the image preview
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;//if closed withput selecting an image
jQuery('input#myprefix_image_id').val(ids);
Refresh_Image(ids);
});
image_frame.on('open',function() {
// On open, get the id from the hidden input
// and select the appropiate images in the media manager
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 request to refresh the image preview
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 );
}
});
}
And the Ajax action to refresh the image preview:
// Ajax action to refresh the user image
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: it is a quick sample written here based on other answer. Not tested because you didn't provide enough information about the exact context the code will be used or the exact problems you have.
-
3The get_image ajax call is not necessary. The
selection.models[0].attributes.url
holds the selected image url onimage_frame
close. If you want to use a certain size, you'll need the ajax call.– BjornCommented Apr 17, 2020 at 17:48 -
Thanks! Small adjustment, I think on "close" it should not do any changes to the selected image, but only on "select".– NikolayCommented Jun 14, 2022 at 12:48
Easy for use just only copy paste the code in your required place
<?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( 'Upload image' ); ?>" />
<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="Save" 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( $ ) {
// Uploading files
var file_frame;
var wp_media_post_id = wp.media.model.settings.post.id; // Store the old id
var set_to_post_id = <?php echo $my_saved_attachment_post_id; ?>; // Set this
jQuery('#upload_image_button').on('click', function( event ){
event.preventDefault();
// If the media frame already exists, reopen it.
if ( file_frame ) {
// Set the post ID to what we want
file_frame.uploader.uploader.param( 'post_id', set_to_post_id );
// Open frame
file_frame.open();
return;
} else {
// Set the wp.media post id so the uploader grabs the ID we want when initialised
wp.media.model.settings.post.id = set_to_post_id;
}
// Create the media frame.
file_frame = wp.media.frames.file_frame = wp.media({
title: 'Select a image to upload',
button: {
text: 'Use this image',
},
multiple: false // Set to true to allow multiple files to be selected
});
// When an image is selected, run a callback.
file_frame.on( 'select', function() {
// We set multiple to false so only get one image from the uploader
attachment = file_frame.state().get('selection').first().toJSON();
// Do something with attachment.id and/or attachment.url here
$( '#image-preview' ).attr( 'src', attachment.url ).css( 'width', 'auto' );
$( '#image_attachment_id' ).val( attachment.id );
// Restore the main post ID
wp.media.model.settings.post.id = wp_media_post_id;
});
// Finally, open the modal
file_frame.open();
});
// Restore the main ID when the add media button is pressed
jQuery( 'a.add_media' ).on( 'click', function() {
wp.media.model.settings.post.id = wp_media_post_id;
});
});
</script>
-
-
-
This works well. Is there a way to pass a category to the Media Library selector?– TARKUSCommented Aug 27, 2022 at 18:05
So this answer worked perfectly. But in order to make it reusable, I converted the code to a function. So, to use this, you have to first check this out to enqueue
the script. And then declare wpOpenGallery
like this:
(function($) {
$(document).ready(function() {
const wpOpenGallery = function(o, callback) {
const options = (typeof o === 'object') ? o : {};
// Predefined settings
const defaultOptions = {
title: 'Select Media',
fileType: 'image',
multiple: false,
currentValue: '',
};
const opt = { ...defaultOptions, ...options };
let image_frame;
if(image_frame){
image_frame.open();
}
// Define image_frame as wp.media object
image_frame = wp.media({
title: opt.title,
multiple : opt.multiple,
library : {
type : opt.fileType,
}
});
image_frame.on('open',function() {
// On open, get the id from the hidden input
// and select the appropiate images in the media manager
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() {
// On close, get selections and save to the hidden input
// plus other AJAX stuff to refresh the image preview
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));
And call it like this:
wpOpenGallery(null, function(data) {
console.log(data);
});
Use wordpress-settings-api-class
by Tareq Hasan, Url: https://github.com/tareq1988/wordpress-settings-api-class
- Include the main class
class.settings-api.php
in your plugin. ( this file https://github.com/tareq1988/wordpress-settings-api-class/blob/master/src/class.settings-api.php) - Define your options. You need to use
'type' => 'file'
as you want to add a media uploader. (See this example for better understanding https://github.com/tareq1988/wordpress-settings-api-class/blob/master/example/procedural-example.php)
-
2I think a solution without additional libraries is better, solid; like the
wp.media
control.– bueltgeCommented Aug 17, 2016 at 12:27
Since you want the icon to be different for every user, you will have to store the image in the user profile. This means you need to add an extra user field:
// create the field
add_action( 'show_user_profile', 'wpse_235406_chaticon' );
add_action( 'edit_user_profile', 'wpse_235406_chaticon' );
function wpse_235406_chaticon ($user) {
echo '
<h3>Chat Icon</h3>
<table class="form-table">
<tr>
<th><label for="chaticon">Chat Icon</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">Please select your chat icon.</span>
</td>
</tr>
</table>';
}
// save the field
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']);
}
Now, this gives you the possibility to upload a file from the user's computer. If you want the user to select the file frome existing images, things become more complicated, because then you need to call the media library in stead of the default file upload. Steven Slack has written an excellent post how to do this, which I don't want to take credit for by copy-pasting his code here.
In your template you must distinguish three possibilities: user not logged in, user logged in but has no icon, user logged in and has icon. Roughly, include this:
$current_user = wp_get_current_user();
if ( 0 == $current_user->ID ) {
... do what you want to do for not logged in users ...
}
else {
$icon = get_user_meta ($current_user->ID, 'chaticon');
if (empty($icon)) {
... default icon with link to upload possibility ...
}
else {
... display $icon ...
}
-
-
You mean only the admin of the site should be able to change the icon and it will be the same for every visitor/user?– cjbjCommented Aug 15, 2016 at 11:24
-
2That would be pretty trivial. Here's a tutorial for that: mikejolley.com/2012/12/21/…– cjbjCommented Aug 15, 2016 at 11:28
-
-
I tried the tutorial, but it doesn't work for me (obsolete?) becauses frames is not part of the js object– ThomasCommented Aug 16, 2016 at 7:08
I used this solution (without using the Media Library itself):
Using image-picker-lib inside a modal that set a hidden input's value, which is posted to the options. By getting all the media and echoing it as options I can let the user select an img.
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">
change
</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">Choose</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();
+ });
-
1I think a solution without additional libraries is better, solid; like the
wp.media
control.– bueltgeCommented Aug 17, 2016 at 12:26 -
@bueltge I agree, but nobody gave a straight answer and I was in need of time. So if someone gives a great answer, they get the bounty!– ThomasCommented Aug 17, 2016 at 12:40
-
I see your answer also as solution, but not the best way. Now it is a part of the question author, you ;) to make the decision.– bueltgeCommented Aug 17, 2016 at 12:42
-
This solution can quickly become a problem as the number of images increase. "nobody gave a straight answer" is not a excuse; your question is very poor, so you get poor answers. You don't show us any effort, research or code you has tried, just "I want to do this, give a ready-to-use solution", which is the same that "do the job for me". Search for wp.media as bueltge suggested; there are hundreds of examples here in WPSE. If you have problems using it, post a new question about it.– cybmetaCommented Aug 18, 2016 at 10:19
-
@cybmeta I did try and this is my best attemp, so don't be an ass about it. If you don't like it, propose a better solution.– ThomasCommented Aug 18, 2016 at 10:27
wp.media
to allow custom uploads, select of a media file for this requirement. WPSE have a lot of examples, but maybe this posts helps you jeroensormani.com/… Also you find on github examples, especially from ocean90 - github.com/ocean90/media-modal-demo