Hi guys, this is the part 2 of our series for adding media uploader to a WordPress widget. Those who haven’t read the previous part, here is the link:

Part 1

In this part we will start with some javascript. First we have to go back to our my_script.js file that we added at the beginning of the part 1 of the tutorial. There we will add the following code snippet inside the document ready function like this:

jQuery(document).ready(function ($) {
   function renderMediaUploader(img, input) {
       // media uploader codes will be here.
   }
}

In this renderMediaUploader function we will render the WordPress media uploader and enable your user to select and upload images, videos and other media files in the widget.

Now let’s add following code snippet into the renderMediaUploader function.

var file_frame;

if ( undefined !== file_frame ) {
     file_frame.open();
     return;
}

Here the variable file_frame will be used to invoke the default media uploader of the wordpress. Now we will initialize the variable and add a listener to it.

        file_frame = wp.media.frames.file_frame = wp.media({
            frame:    'post',
            state:    'insert',
            multiple: false
        });

        file_frame.on('insert', function () {
            var selectedImage = file_frame.state().get( 'selection' ).first().toJSON();
            if(input){
                input.val(selectedImage.url);
            }
            if(img){
                img.attr('src', selectedImage.url);
            }
            else {
                input.before('<img class="my-image-preview" src="' + selectedImage.url + '" alt="Alternative Text">');
            }
        });

Here we are initializing the file_frame variable with WordPress Media Uploader instance. Then we are adding a callback for insert event.
And finally we will add another line of code to finish up the renderMediaUploader function.

file_frame.open();

Now the whole renderMediaUploader function will look like this:

function renderMediaUploader(img, input) {
    var file_frame;
    if ( undefined !== file_frame ) {
        file_frame.open();
        return;
    }

    file_frame = wp.media.frames.file_frame = wp.media({
        frame:    'post',
        state:    'insert',
        multiple: false
    });

    file_frame.on('insert', function () {
        var selectedImage = file_frame.state().get( 'selection' ).first().toJSON();
        if(input){
            input.val(selectedImage.url);
        }
        if(img){
            img.attr('src', selectedImage.url);
        }
        else {
            input.before('<img class="my-image-preview" src="' + selectedImage.url + '" alt="Alternative Text">');
        }
    });

    file_frame.open();
}

At this point we will see how to invoke the function based on user action and let the user to use the media uploader. In order to do this, we will need the piece of code from below:

$(document).on('click', 'a.my-image-selector-button', function (e) {
    e.preventDefault();
    renderMediaUploader($(this).next('img'), $(this).parent().find('input.my-image-input'));
})

This code snippet will invoke the renderMediaUploader function every time we click on the Choose Image button in the widget.

Now we will dive into the depth of this code. When someone clicks on the Choose Image Button in the widget, this jQuery code snippet will call renderMediaUploader function. There is a little thing left to explain here. As you might have noticed, we have added the click listener to document and asked it to track the button as a child element. The reason for this is that, every time you click save button in the widget, the widget refreshes itself and generates the elements within itself. For this reason, any listener bound to the button will get refreshed after each save. This will create some issues with the listener. To prevent this, we have added the listener with root document instead of the button.