Hijack the WordPress Media Gallery

I have a friend that wants to update a banner on his WordPress blog homepage without changing the template files. I tell him I’d be glad to help him out and start working on a plugin that provides a custom administration page to allow for this. As I am a firm believer in the power of a lazy coder to get things done faster and better, my first thought was: “Why don’t I just see if I can hijack the ‘Select Image From Gallery’ page to do this?” that process for my own ends shouldn’t take me but a few minutes…and a lot less time than trying to build my own media selector. Like nearly all the content on my site, if you are reading this, I wasn’t able to find my answer elsewhere.

First, we will examine how the media library iframe is launched from the post editor and how we can duplicate that in our plugin. So lets crack open the page source and see what we can find:

<a href="media-upload.php?post_id=-1249588072&type=image&TB_iframe=true" id="add_image" class="thickbox" title='Add an Image' onclick="return false;"><img src='images/media-button-image.gif' alt='Add an Image' /></a>

Looks like a standard hyperlink, with some extra information in the tag. What first jumps out at me is the onclick=”return false;”. By having an onclick return false in a hyperlink, you ensure that a browser with javascript will never open the link when it is clicked. Sounds pretty silly until you remember that WordPress is a big user of JQuery. From there, we know to look at the class of the hyperlink, class=”thickbox”. This is a reference to the Thickbox 3.1 library found at /wp-includes/js/thickbox/thickbox.js. This is a library to load an iframe inside an overlay with the background greyed out. Further, it uses the href of the anchor tag to know where to pull the iframe content from.

A quick check of the source on our custom page shows that Thickbox is being loaded in the footer, so we do not have to call it directly from our custom wp-admin page. I can just call up the media library with some html code:

<a href="media-upload.php?type=image&TB_iframe=true" class="thickbox" title="Select A Banner Image From Gallery" onclick="return false;" class="thickbox">
<img id="banner_image" src="<?php echo(htmlentities($banner_image)); ?>" width="450" height="25" />
</a>
<input type="hidden" id="banner_image_input" name="banner_image" value="<?php echo(htmlentities($banner_image)); ?>" />

The snippet displays an image with the source of $banner_image that can be clicked on to open the Media Gallery iframe. I have also added a hidden form input to store the resulting information passed back from the media library. Once done, I now have an image on my admin page that I can click on to call up the media library.

We’re half-way there now! All we have to do next is figure out how the media library sends an image to the post editor. This part isn’t as easy. Thanks to thickbox, the media library opens up in an inline-iframe. This means that we can’t just view the page source and find our answer. Instead, the only clue we have to hunt for is the “Insert into Post” button. A quick file search turns that up in /wp-admin/includes/media.php. From there, we discover the onclick of the button, onclick=”addExtImage.insert();”, which is thankfully also in the media.php file. At the end of the function, we see exactly what we are looking for:

var win = window.dialogArguments || opener || parent || top;
win.send_to_editor(html);

The media library calls the function send_to_editor in the scope of the window that opened the media library–our admin page! We can add our own function into the admin page and collect the html that the media library sends us:

function send_to_editor(html) {
    alert(html);
    tb_remove();
}

Once done, we can open the media library from our admin page and select an image. When we hit the “Insert into Post” button, we get an alert with the following content:

<img src="http://127.0.0.1/devel/wp-content/uploads/2009/09/banner.jpg" alt="banner" title="banner" class="alignnone size-full wp-image-494" />

All we have to do now, is strip out everything but the image source and updates the form. First, the function eliminates all of the text returned except the image source. It then updates the banner image and the hidden input value that I am using in my form:

function send_to_editor(html) {
    var source = html.match(/src=\".*\" alt/);
    source = source[0].replace(/^src=\"/, "").replace(/" alt$/, "");
    $("#banner_image").attr('src', source);
    $('#banner_image_input").attr('value', source);
    tb_remove();
}

I fire up the admin page a final time, and everything works! I now have a custom admin page that allows my friend to update a banner on his wordpress site using the media gallery.