So how to add WordPress media uploader popup to our custom widget?
That’s not so hard, hovewer there are a few caveats.
Let’s start from our simple widget class, I’d recommend to get example from https://codex.wordpress.org/Widgets_API#Example. Then we will need to add our new option, it will be called “image”. Just copy and paste fields in the “form” function, to render widget form and “update” function, to save this option.
I would recommend to catch php output buffer, it may be helpful if you will want to cache widget output. So our “widget” function will look like this:
public function widget( $args, $instance ) { // Our variables from the widget settings $title = apply_filters( 'widget_title', empty( $instance['title'] ) ? __( 'Default title', 'text_domain' ) : $instance['title'] ); $image = ! empty( $instance['image'] ) ? $instance['image'] : ''; ob_start(); echo $args['before_widget']; if ( ! empty( $instance['title'] ) ) { echo $args['before_title'] . $title . $args['after_title']; } ?> <?php if($image): ?> <img src="<?php echo esc_url($image); ?>" alt=""> <?php endif; ?> <?php echo $args['after_widget']; ob_end_flush(); }
Our “form” function will be:
public function form( $instance ) { $title = ! empty( $instance['title'] ) ? $instance['title'] : __( 'New title', 'text_domain' ); $image = ! empty( $instance['image'] ) ? $instance['image'] : ''; ?> <p> <label for="<?php echo $this->get_field_id( 'title' ); ?>"><?php _e( 'Title:' ); ?></label> <input class="widefat" id="<?php echo $this->get_field_id( 'title' ); ?>" name="<?php echo $this->get_field_name( 'title' ); ?>" type="text" value="<?php echo esc_attr( $title ); ?>"> </p> <p> <label for="<?php echo $this->get_field_id( 'image' ); ?>"><?php _e( 'Image:' ); ?></label> <input class="widefat" id="<?php echo $this->get_field_id( 'image' ); ?>" name="<?php echo $this->get_field_name( 'image' ); ?>" type="text" value="<?php echo esc_url( $image ); ?>" /> <button class="upload_image_button button button-primary">Upload Image</button> </p> <?php }
And our update function:
public function update( $new_instance, $old_instance ) { $instance = array(); $instance['title'] = ( ! empty( $new_instance['title'] ) ) ? strip_tags( $new_instance['title'] ) : ''; $instance['image'] = ( ! empty( $new_instance['image'] ) ) ? $new_instance['image'] : ''; return $instance; }
As you can see, I’ve added a button underneath image input field with class “.upload_image_button”, but it will not work for now and to make it work we will need to add our custom admin javascript.
First what we need is to create our javascript file and put it into our theme, let’s create a file, called our_admin.js in assets/js under our theme folder.
Next we will need to register and enqueue our script to make it load in the admin panel, so lets add few lines to our widget class constructor function:
function __construct() { // Add Widget scripts add_action('admin_enqueue_scripts', array($this, 'scripts')); parent::__construct( 'our_widget', // Base ID __( 'Our Widget Title', 'text_domain' ), // Name array( 'description' => __( 'Our Widget with media files', 'text_domain' ), ) // Args ); }
And we will need then “scripts” function in our widget class:
public function scripts() { wp_enqueue_script( 'media-upload' ); wp_enqueue_media(); wp_enqueue_script('our_admin', get_template_directory_uri() . '/assets/js/our_admin.js', array('jquery')); }
As you can notice, we also added wp_enqueue_script( ‘media-upload’ ); and wp_enqueue_media(); to enqueue media library popup scripts.
And finally, here is our script, that will call WordPress media library popup and put selected image into the input field:
jQuery(document).ready(function ($) { $(document).on("click", ".upload_image_button", function (e) { e.preventDefault(); var $button = $(this); // Create the media frame. var file_frame = wp.media.frames.file_frame = wp.media({ title: 'Select or upload image', library: { // remove these to show all type: 'image' // specific mime }, button: { text: 'Select' }, 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 var attachment = file_frame.state().get('selection').first().toJSON(); $button.siblings('input').val(attachment.url); }); // Finally, open the modal file_frame.open(); }); });
So thats it, now, when you click on “Upload Image” button, WordPress media library popup will open and you will be able easily upload or select already uploaded image for widget options form.
Thanks for the example. Good job.. Got a working image selector now.
Finally working example! Thanks!
Works perfect. Thanks!
please can you set this all code in one file function.php
it is difficult for me..
Put above php codes in a class. You can put below codes in functions.php or create a new file and load it.
add_action('widgets_init', 'my_widget');
function my_widget() {
register_widget('my_new_widget ');
}
// widget class
class my_new_widget extends WP_Widget {
// copy above php codes here
}
hy,
thanks for the great resource!
one thing i found out while implementing this is that it is better to change the click-handler (line 3 in your js) to
$(document).live(“click”, “.upload_image_button”, function (e) {
then it will also work after saving the widget, because the button will be a new one added with ajax and therefore the “on” – handler will not work anymore, while “live” works also on dynamic elements.
matt
Hey!
Actually $.live is an alias for $.on and it was deprecated since jQuery 1.7, removed in jQuery 1.9 (http://api.jquery.com/live/)
Thanks for the great example you saved me some time 🙂
Many Thanks. Great Tutorial. Saved me after three days following a non working one!!! Deep Bow!
Thanks, it was really helpfull)
Worked out of the box, saved me some time – many thanks
Also wanted to say thanks!! 🙂
That worked pefectly, thanks so much for sharing!
Dude! You rock!!!!! Thanks so much for this, I must have looked at 34 other tutorials before landing on this one, and it’s just what I needed. The structure matches perfectly to my existing plugin, and it’s very clear and easy to follow. Awesome. My only suggestion would be to display a thumbnail of the image instead of just the filename. Thanks so much.
Any ideas why this doesn’t work for me ?
When I click upload image, the whole page reloads and nothing happens.
Please let me know what may cause the problem. I can send you my code if this won’t show.
See the Pen owNLwo by Karniej (@Karniej) on CodePen.
You need to debug your app, check if button with class .upload_image_button is actually rendered, check if JS code was added to ad page, you can add console.log(‘Code added’) on top of your code, check your console to see this message. Check if there any error in console.
Dude! You rock!!!!![2]
really cool example, very usefull code!! thanks mate.
Awesome tutorial. Saved me a ton of time as well!
I’m trying to add multiple files and have set multiple to true and that is working, but when I try and get the selected files’ names on select, I’m struggling to get anything but the first. I tried looping through each selection with .each but I’m not sure what to call.
// When an image is selected, run a callback.
file_frame.on(‘select’, function () {
var attachment = file_frame.state().get(‘selection’).each( function(){
console.log($(this).attachment.url);
//$(this).toJSON();
});
$button.siblings(‘input’).val(attachment.url);
});
This code logs an error “Cannot read property ‘url’ of undefined” – any ideas?
Thanks!!!
Hi, you probably need to specify variable in the each function:
var attachment = file_frame.state().get(‘selection’).each( function( attachment ) {
console.log( attachment.toJSON().url );
});
Otherwise try to cnonsole.log( file_frame.state().get(‘selection’) ); and see what kind of object is that, if it’s array you can use .forEach(function( attachment ) { … });
Hey, great tutorial. I just have a question:
when i’ve chosen a image and click on select, wordpress doesn’t notice that something changed in the URL textfield and the “Save” Button is still grey. I have to delete a letter or change something manually in on of the textfields to give wordpress the notification that i changed something.
Did i miss something?
Calling ‘change’ event after setting the value works for me
So the line 26 will look like:
$button.siblings(‘input’).val(attachment.url).change();
Thank Buddy
Thank Buddy But i want to diplay live image preview. how to do this?
Add `<img id="image_upload_preview" src="” alt=””>` above the image input field.
To make the image preview watch for changes, add this line
`$(‘#image_upload_preview’).attr(‘src’, attachment.url).change()`
on the js file, below `$button.siblings(‘input’).val(attachment.url).change();` (around line 28 or 29).
Hope it helps!
Thanks! That’s exactly that i was struggling into.
Thank dude, you saved my life <3
This worked wonders. Thanks!
Thanks a lot))) Have a nice day!
So bad that we should first search in SO, then here, then in official documentation. Thank you! 3 years later still extremely useful!
Clicking the button doesn’t do anything…
Check Sergei Varzin’s entry above. Adding .change() to line 26 of the .js, as suggested, worked for me.
If the Upload button doesn’t do anything, it’s probably from the copy/paste of code, which your browser console should display an syntax error….usually ” and ‘ need retyped.
Hello,
thanks for your nice article. It’s working fine, except one thing. When you press the button to upload an image, the media selector is opened twice. Maybe i embedded the jQuery Script at the wrong place. I placed it behind the last parahraph in function form. Somebody know, what I have done wrong?
Excellent!
Hy, thank’s for the idea
After uploaded image, the “save” button don’t work for me!
Thank’s for respond
Thank you, man 🙂
Thanks for the excellent tutorial. Your jquery helped out a lot.
Why ATTACHMENT DISPLAY SETTINGS (image size selection and alignments) is not supported on media editor box. How to make this happen ?
how can i make button remove image when clink on remove button
Thanks for Sharing this code. it’s really helpful for beginners.
I was more than happy to search out this
website.