Everything you ever wanted to know about wp.media and how to build image and file uploaders in WordPress

WP Media is a useful and sometimes mysterious part of WordPress core. It’s available as part of the “wp” Javascript namespace, you utilize it as wp.media(). When implemented correctly, it’s your ticket to integrating a file uploader and selector into your custom WP plugin or theme.

The good news is wp.media() is stable, it’s used of course by WP core in the WP Admin to provide media file management functions. It’s also been integrated into thousands of plugins and themes. The bad news is it can be a little bit complicated to implement if you’re new to it thanks to relatively slim documentation available and some of the potential pitfalls. Hopefully this guide helps you get up and running with wp.media without any fuss. Let’s jump into it!

There are 3 general steps in the process of wp.media integration:

  1. Enqueue the required scripts that provide wp.media. These are only loaded by default where the WP Admin uses them such as post editing. And don’t worry if your attempted loading of them causes duplication because the function we use has built-in duplication blocking as it checks for a contained hook having already run once.
  2. Build out your DOM elements. This could be in the form of a PHP/HTML mixed template, or it could in the form of JS/jQuery. Although technically you can just use any existing DOM element on a page and attach a click handler that opens the WP Media modal. That’s fine for an experiment, but that won’t create anything useful because you need DOM elements to store the value(s) of the selected file attachments, and you need to provide the user with options to remove a selected file or redo their selection.
  3. Initialize wp.media() and add event handlers. The key events are going to be the click handler that opens the WP Media modal, then the selection handler callback that “does stuff” after the user finishes making their selection(s) of files and/or uploading their files. For our purposes we actually don’t care (usually) if the user uploads or selects an existing file because WP Media takes care of that part, we only need to focus on handling the final selection when the user closes the modal. Aside from those core events (click, select) to make a full solution we typically want to provide a delete/remove option that let’s the user clear their selection and redo it.

Enqueue WP Media Script

The example below is the minimal way to go about calling wp_enqueue_media(). This will ensure the wp.media() function is available. Usually we want to attach this to the action hook “admin_enqueue_scripts” for admin use, or wp_enqueue_scripts” for front-end use. In other words it can be called along with any existing enqueues in your plugin or theme if you already have them. And if you’re just practicing with this, you can open up functions.php in the active theme of any test site and put it there.

add_action( 'admin_enqueue_scripts', function( $hook_suffix ) {

  wp_enqueue_media();

}

For further details on the enqueue or to see the code for this function on trac visit https://codex.wordpress.org/Javascript_Reference/wp.media

Add Minimal Markup

Our minimal markup just to get this working is going to a div with an ID that we can target:

<div id="media-selector">Select Media</div>

We will iterate over this multiple times adding more markup as it’s needed but this will be enough to verify your scripts are loaded and hopefully see the WP Media selector working.

Add a Click Event to Trigger Opening WP Media Selector

We’re going to use jQuery for this example, but you can also add a click event (listener) using JS.

jQuery( '#media-selector' ).on( 'click', function() {
  
  var mediaSelector = wp.media({
    title: 'Select or upload a product image.',
    button: {
      text: 'Finish Selection'
    }
  });

});

With this short snippet we’re attaching a click handler to our #media-selector element. We’re then calling wp.media() with a minimal configuration object. In that config object we have title and button properties set. The title will be shown in the modal window header, and the button text we added will customize the text in the selection button in the modal footer.

Store the Selected Media Value

With our minimal example working we can open the WP Media Selector, we can upload or select an example file and then the modal closes… and then nothing happens. Until we implement storage of the media attachment ID’s we’re just selecting… we’re not saving or handling. The next step then is implement storage of the ID’s which we’ll do using a hidden input element and a callback on the wp.media() save event that is fired after selection (by the user) ends.

Start by adding a hidden input element:

<input id="#media-selector-input" type="hidden" />

We’ll now work towards populating that input using the select callback. Remember that we saved our instance of wp.media() when we created it into a variable “mediaSelector”. We’ll now use mediaSelector.on( ‘select’ ). Just take note that this is effectively wp.media.on( ‘select’ ) that we’re using, but we cannot call this directly because we need to utilize our instance which is populated and mapped.

mediaSelector.on( 'select', function() {
  
  const attachment = mediaSelector.state().get('selection').first().toJSON();
  jQuery( '#media-selector-input' ).val( attachment.id );

});

You’ll notice in the code above the first line in the select callback is a lot to digest. We are accessing the state of the media selector in order to get the current selection. We’re then using first() to pick out the first item selected because all files selected are stored there as an array. Finally .toJson() is used to parse the selection. The result is we have a single attachment (file reference). We can then store it’s ID which we do on the next line. If you test this out using your browser inspector you should see the attachment ID being set in the hidden field.

Choose Multiple or Singular Settings

Right now with the code we have there is a problem, you might have already noticed it yourself. The user can choose multiple files, but we’re only storing one of those files in our hidden input reference. This is a mismatch in configuration. So we can either fix it by disabling multiple file selections in the WP Media Selector, which is what we should do when we want exactly 1 selection. Or we can support multiple file selections in which case we need to adapt our data storage (select event) so that instead of getting only the first of the selection array, instead we get the entire selection array. That will mean we need to choose how to store the data into the hidden input, and JSON seems like the best choice for that.

Which option did you choose? It doesn’t matter… because I’m making the choice for you… we’re going to cover multiple file selections in a later iteration over this but for now we’re just going to solve this with 1 line added to our wp.media() configuration object which is the property “multiple” and we’ll set that to “false”:

{
  multiple: false;
}

As a reminder you should now have the following in your click event handler and wp.media() setup:

jQuery( '#media-selector' ).on( 'click', function() {
  
  var mediaSelector = wp.media({
    title: 'Select or upload a product image.',
    button: {
      text: 'Finish Selection'
    },
    multiple: false
  });

});

Go ahead and test again and you should now find you can only select 1 file. Now our data storage of a single attachment ID is properly aligned with our selector.

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *