One of the recent changes to my Ryuzine Press plugin is that it now requires WordPress 3.5 or higher, so there really was no excuse to be using that ugly, tired old “thickbox” media uploader modal dialog anymore.  Time to update to the snazzy new one!

The first site I found with something useful on how to make this changeover was this one: How to use WordPress 3.5 Media Uploader In Theme Options. Now, an important point is that I needed this for a plugin’s options, not a theme.  But it got me started.  First and foremost, anywhere other than the standard Edit Post page you need to make sure you have the new media script loading on your custom options/setting pages.  So this goes into your admin functions.php file:

1
2
3
4
function use_new_media_box() {
wp_enqueue_media();
}
add_action( 'admin_enqueue_scripts', 'use_new_media_box' );

It isn’t clear in some tutorials that you can’t just put the wp_enqueue_media() function there by itself, you have to put it inside an admin_enqueue_scripts action or it won’t work.

Changing out the “Media Library” buttons in my Options page wasn’t too difficult either.  I changed it from this:

1
2
3
4
<label for="upload_image">
<input id="masthead_image" type="text" name="myplugin_opt_covers[mastheadimg]" size="36" value="&lt;?php echo $options['mastheadimg']; ?&gt;" />
<input class="image_uploader_button" id="masthead_image_button" type="button" value="Media Library" />
</label>

To this:

1
2
3
<label class="uploader" for="upload_image">
<input id="masthead_image" type="text" name="myplugin_opt_covers[mastheadimg]" size="36" value="&lt;?php echo $options['mastheadimg']; ?&gt;" />
<input class="button" id="masthead_image_button" type="image_uploader_button button" value="Media Library" />

Ah, but if you haven’t removed the old “thickbox” code yet, this will not open the new Media Uploader.  You need a little bit of jQuery to help!  This was the first place that the aforementioned link didn’t help, but some of the code in the comments got me on the right track.  It’s kind of a different animal when all I want is to grab the image URL and stick it in a text box (instead of attaching it to a post).  Ultimately this is the code I ended up using:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
jQuery(document).ready(function($){
var _custom_media = false,
_orig_send_attachment = wp.media.editor.send.attachment;
id = ''; // need to grab this

wp.media.editor.send.attachment = function(props, attachment){
$("#"+id).val(attachment.url); // port into textbox
}
$('.uploader .button').click(function(e) {
var send_attachment_bkp = wp.media.editor.send.attachment;
var button = $(this);
id = button.attr('id').replace('_button', '');
wp.media.editor.open(button);
return false;
});
$('.add_media').on('click', function(){
_custom_media = false;
})
});

What’s important here is the “id=”; on line 4, so that it can be referenced inside the other functions. Line 12 sets “id” to the ID of the button, minus the “_button” suffix, so it then refers to the text input field. The wp.media.editor.send.attachment function then pulls that id on Line 7 along with the URL of the image (attachment.url), setting the value of the textbox to that URL. Ok, so now that you dropped that into the head of your Options page (or enqueued it properly), you click the “Media Library” button and up pops the new Media Uploader modal dialog! Yay! Select and image, hit “Insert into post” and…

Crap, the old “thickbox” one is underneath it! That’s because the old method scripts are still being loaded on the functions.php page. Ok, this is the point where you’ll have to decide if you want to support WordPress 3.5+ exclusively, or if you want people running older versions to still be able to use your plugin. I opted for setting 3.5 as my minimum required version, but if you do want to support older versions it would be something like this in your functions.php file:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
$wp_version = get_bloginfo('version');
if ($wp_version < 3.5) {
    // Pre WP 3.5 uploaders
    function my_admin_scripts() {
    wp_enqueue_script('media-upload');
    wp_enqueue_script('thickbox');
    wp_register_script('my-upload', WP_PLUGIN_URL.'/my-plugin/js/uploader.js', array('jquery','media-upload','thickbox'));
    wp_enqueue_script('my-upload');
    }

    function my_admin_styles() {
    wp_enqueue_style('thickbox');
    }
    // I have a 'settings' and a 'tools' page that each need the media uploader //
    if ( isset($_GET['page']) && ($_GET['page'] == 'my-settings' || $_GET['page'] == 'my-tools') ) {
    add_action('admin_print_scripts', 'my_admin_scripts');
    add_action('admin_print_styles', 'my_admin_styles');
    }
} else {
// Media Uploader for WP 3.5+ //
    function my_new_media_box() {
        wp_enqueue_media();
    }
    add_action( 'admin_enqueue_scripts', 'my_new_media_box' );

    function my_new_admin_scripts() {
        wp_register_script('my-upload', WP_PLUGIN_URL.'/my-plugin/js/media_uploader.js', array('jquery'));
    wp_enqueue_script('my-upload');
    }
    function my_new_admin_styles() {
        wp_register_style('my-media', WP_PLUGIN_URL.'/my-plugin/css/media.css');
        wp_enqueue_style('my-media');
    }
    // My plugin has both a 'settings' and 'tools' page, each needs media uploader //
    if ( isset($_GET['page']) && ($_GET['page'] == 'my-settings' || $_GET['page'] == 'my-tools') ) {
    add_action('admin_print_scripts','my_new_admin_scripts');
    add_action('admin_print_styles' ,'my_new_admin_styles');
}

Ok, so it’s now working. The “Media Library” buttons pop up the new Media Uploader modal dialog. But it has that sidebar with gallery stuff, it says “Insert Media” and the button at the bottom says “Insert into post” – which is confusing because we aren’t actually inserting media and we aren’t on a “post” page.

Modifying the Media Uploader Window

This post talks about using the built-in method leveraging the “custom-header” script already in WordPress.

1
2
3
4
5
<input id="choose-from-library-link" name="masthead_image_button" type="button" class="button"
    data-update-link="<?php echo esc_attr( $modal_update_href ); ?>"
    data-choose="<?php esc_attr_e( 'Choose a Default Image' ); ?>"
    data-update="<?php esc_attr_e( 'Set as default image' ); ?>"
    value="Media Library />

Notice that I had to change the button ID. This is where my problems with this started. The “custom-header” script will ONLY look for that id. Which means, unless you do something funky, you can only have ONE of these buttons on a page – which isn’t going to work for a options/settings page that has several on it. Even so, I wanted to see if it would work for one button and, if it did, worry about making it work for multiple buttons later. Notice that I set the “name” of the input element, and then changed my jQuery to grab the button name instead of id – which at least got me pointing to the correct text field.

Click the button and up comes the new Media Upload dialog with the title “Choose a Default Image” and a button in the corner that says “Set as default image” and no sidebar. So far so good, but it doesn’t actually DO anything with the selected image yet.

The other component of this is to define the action in the head of the page (note: I didn’t include the nonce security check):

1
2
3
4
5
6
if (isset($_REQUEST['file'])) {
    // Process and save the image id
    $options = get_option('my_plugin_opt_covers', TRUE);
    $options['masthead_img'] = absint($_REQUEST['file']);
    update_option('my_plugin_opt_covers', $options);
}

What that gives you, though, is NOT the URL of the image. It gives you the ID number of the image “post” and then takes you to the front-end where it tells you it can’t find that page. Ok, so clearly this was barking up the wrong tree. So forget everything in this section, it won’t work for you on an Options/Settings page and definitely not for putting the URL in a text input box.

Take Two

This was the next post I found about actually creating your own Media Uploader dialog to replace the default one.

I have to admit it looked like a lot of extra work just to get RID of a column and change the labels on a couple of things. I don’t want to end up maintaining a custom media uploader with my plugin. So ultimately I decided to focus on just accomplishing the small things I wanted to do.

The Final Hack

As I said above, what I wanted was to get rid of the sidebar on the Media Uploader, since creating a Gallery is irrelevant and don’t really want to encourage inserting from a remote URL. What I ended up doing was arguably a bit of a hack but it works. First I took a look t the classes applied to the Media Uploader window elements and modified it with a bit of CSS:

1
2
3
.media-frame-menu { display: none; }
.media-frame-title, .media-frame-router,
.media-frame-content { left: 0; }

Line 1 hides the left-hand column, the next moves the rest over to the left margin. I just stuck this into an admin stylesheet that ONLY loads on my Options and Tools pages, so this doesn’t affect the Media Uploader windows on the Edit Post pages. Next I wanted to make the window title and the button label more relevant to the current context. Thanks to a comment on this post it turns out that’s actually pretty easy since WordPress 3.5 localizes all the string at the bottom of the page:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/* <![CDATA[ */
var _wpMediaViewsL10n = {
    "url":"URL",
    "addMedia":"Add Media",
    "search":"Search",
    "select":"Select",
    "cancel":"Cancel",
    "selected":"%d selected",
    "dragInfo":"Drag and drop to reorder images.",
    "uploadFilesTitle":"Upload Files",
    "uploadImagesTitle":"Upload Images",
    "mediaLibraryTitle":"Media Library",
    "insertMediaTitle":"Insert Media",
    "createNewGallery":"Create a new gallery",
    "returnToLibrary":"\u2190 Return to library",
    "allMediaItems":"All media items",
    "noItemsFound":"No items found.",
    "insertIntoPost":"Insert into post",
    "uploadedToThisPost":"Uploaded to this post",
    // ET CETERA
    };
/* ]]> */

So, since we’re already using some jQuery to process the URLs from the Media Uploader I just added a couple of string overrides to the end of that same script:

1
2
3
    // Modify Media Uploader labels
    _wpMediaViewsL10n.insertMediaTitle  = 'Select Image';
    _wpMediaViewsL10n.insertIntoPost    = 'Insert URL';

The only thing now that doesn’t make sense is that you can still select multiple images, but the script will only accept the last image selected – which hopefully people will figure out on their own. Plus it does say “Select Image” not “Images.” Hey, c’mon, I told you this was a hack!

Now, if you wanted to do this from PHP instead of relying on jQuery to do the dirty work, this post supplied a list of all the $strings used in the Media Uploader:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
$strings = array(
        // Generic
        'url'         => __( 'URL' ),
        'addMedia'    => __( 'Add Media' ),
        'search'      => __( 'Search' ),
        'select'      => __( 'Select' ),
        'cancel'      => __( 'Cancel' ),
        /* translators: This is a would-be plural string used in the media manager.
           If there is not a word you can use in your language to avoid issues with the
           lack of plural support here, turn it into "selected: %d" then translate it.
         */

        'selected'    => __( '%d selected' ),
        'dragInfo'    => __( 'Drag and drop to reorder images.' ),

        // Upload
        'uploadFilesTitle'  => __( 'Upload Files' ),
        'uploadImagesTitle' => __( 'Upload Images' ),

        // Library
        'mediaLibraryTitle'  => __( 'Media Library' ),
        'insertMediaTitle'   => __( 'Insert Media' ),
        'createNewGallery'   => __( 'Create a new gallery' ),
        'returnToLibrary'    => __( '← Return to library' ),
        'allMediaItems'      => __( 'All media items' ),
        'noItemsFound'       => __( 'No items found.' ),
        'insertIntoPost'     => $hier ? __( 'Insert into page' ) : __( 'Insert into post' ),
        'uploadedToThisPost' => $hier ? __( 'Uploaded to this page' ) : __( 'Uploaded to this post' ),
        'warnDelete' =>      __( "You are about to permanently delete this item.\n  'Cancel' to stop, 'OK' to delete." ),

        // From URL
        'insertFromUrlTitle' => __( 'Insert from URL' ),

So, if you wanted to remove the Media Tab from the top you’d do it like this:

1
2
3
4
5
function remove_media_tab($strings) {
    unset($strings["insertFromUrlTitle"]);
    return $strings;
}
add_filter('media_view_strings','remove_media_tab');

You’d want to make sure that filter was only applied on your options or settings pages, otherwise you’d end up removing it from every Media Uploader, which is probably not what you wanted.

So, hopefully that will help out anyone else scouring the interwebs looking for info on how to grab URLs from the Media Uploader. Cheers!