Hassle Free Responsive Images for WordPress

Published by Guest Author

Update: The plugin created in this article has moved here and now uses the more appropriate srcset attribute. It's the official WordPress plugin of the Responsive Images Community Group and is endorsed by the WordPress Core Team. It sounds likely that this will make it into WordPress core eventually. Pretty cool!

The following post is guest co-authored by Tim Evko (@tevko). WordPress has a built-in media uploading system. When you upload an image, it automatically creates and saves different versions of it. Tim will show us how we can customize and exploit that ability to help us with responsive images in content.

If you're like me, and you're tasked with building responsive website that's relatively easy to update, WordPress is most often the CMS you will be building that website on. If you're more like me, you probably skipped over a responsive image solution in favor of making things easier for whomever will be doing the updating. Fortunately, with a few lines of PHP and some JavaScript, you can now add automatic responsive image functionality to your WordPress site.

Here I'll show you how to add support for responsive images to your WordPress site in the form of a small WordPress plugin.

The Markup we ultimately want

We'll be using the Picturefill library here. For now, we'll use the markup that library suggests, which closely mimics what the <picture> element will soon be.

UPDATE: The <picture> element is landing in browsers, so the plugin/code in this article has been updated to work directly with that syntax.
<picture>
  <source srcset="examples/images/extralarge.jpg" media="(min-width: 1000px)">
  <source srcset="examples/images/large.jpg" media="(min-width: 800px)">
  <source srcset="examples/images/medium.jpg">
 
  <!-- fallback -->
  <img srcset="examples/images/medium.jpg" alt="alt text">
</picture>

That is the basic markup pattern, although it can get slightly more complex to accommodate some browser bugs.

What we're not going to do is use that markup directly in blog posts, we're going to get WordPress to help us with that.

The Theme

All you need to do in your theme is make sure this one-liner is present in its functions.php file:

add_theme_support('post-thumbnails');

This will ensure that your theme gives WordPress permission to resize the uploaded images. Without it, the plugin won't work.

The Plugin

This makes sense to do as a WordPress plugin, because we'll want to keep it active no matter what theme is active. We can make it a folder with a PHP file in there to be the plugin code itself, and a copy of the Picturefill library:

Adding the library

Queue it up responsibility:

function get_picturefill() {
  wp_enqueue_script('picturefill', plugins_url( '/js/picturefill.js', __FILE__ ));
}
add_action('init', 'get_picturefill');

That will ensure WordPress loads up this JavaScript library on the front end.

Define sizes

Tell WordPress what size images you want created upon uploading:

add_image_size('large-img', 1000, 702);
add_image_size('medium-img', 700, 372);
add_image_size('small-img', 300, 200);

You can set this up however you like. add_image_size has a variety of parameters you can adjust. In the case of a 1024x768 bunny rabbit JPG I uploaded, a bunch of versions get created:

The 936x702 one was created because we specified we wanted one with a max of 702 height. The 150x150 one was created because WordPress automatically makes a square thumb of that size.

Making a [shortcode]

Let's extend this plugin, giving it some real functionality, by making a responsive images shortcode. That way we can put this right in the post content:

[responsive imageid="12" size1="0" size2="500" size3="1000"]

and it will output the markup we need for Picturefill.

We'll split this up into three functions. One to define the shortcode and what HTML to output, one helper to return alt text, and one specifically to loop through and output the image sources.

function tevkori_get_img_alt( $image ) {
    $img_alt = trim( strip_tags( get_post_meta( $image, '_wp_attachment_image_alt', true ) ) );
    return $img_alt;
}

function tevkori_get_picture_srcs( $image, $mappings ) {
    $arr = array();
    foreach ( $mappings as $size => $type ) {
        $image_src = wp_get_attachment_image_src( $image, $type );
        $arr[] = '<source srcset="'. $image_src[0] . '" media="(min-width: '. $size .'px)">';
    }
    return implode( array_reverse ( $arr ) );
}

function tevkori_responsive_shortcode( $atts ) {
    extract( shortcode_atts( array(
        'imageid'    => 1,
        // You can add more sizes for your shortcodes here
        'size1' => 0,
        'size2' => 600,
        'size3' => 1000,
    ), $atts ) );

    $mappings = array(
        $size1 => 'small-img',
        $size2 => 'medium-img',
        $size3 => 'large-img'
    );

   return
        '<picture>
            <!--[if IE 9]><video style="display: none;"><![endif]-->'
            . tevkori_get_picture_srcs( $imageid, $mappings ) .
            '<!--[if IE 9]></video><![endif]-->
            <img srcset="' . wp_get_attachment_image_src( $imageid[0] ) . '" alt="' . tevkori_get_img_alt( $imageid ) . '">
            <noscript>' . wp_get_attachment_image( $imageid, $mappings[0] ) . ' </noscript>
        </picture>';
}

Then enabled the shortcode:

add_shortcode( 'responsive', 'tevkori_responsive_shortcode' );

Ideally you define your breakpoints in the plugin here and then don't pass them at all when using the shortcode, like:

[responsive imageid="12"]

Then only use the shortcode attributes in the rare cases you need to override the breakpoints.

Altering the Media Uploader output

This shortcode will be tremendously useful (remember we can even adjust the markup to be the correct <picture> in the future programmatically). But, how do we know the image ID to use? The Media Uploader UI doesn't make that information available. It knows that ID though, and with a simple filter we can adjust what gets sent to the editor:

function responsive_insert_image($html, $id, $caption, $title, $align, $url) {
  return "[responsive imageid='$id' size1='0' size2='600' size3='1000']";
}
add_filter('image_send_to_editor', 'responsive_insert_image', 10, 9);

Now selecting and inserting an image from the editor will work like this:

That'll do it! Here you can see it working:

More you can do

  • If you're looking for a wider range of support, consider installing Matchmedia.js as well. It will make @media queries start working in older browsers, which then automatically makes Picturefill work as well.
  • Rather than use shortcodes or adjust the media uploader output, you could make this work with a special image field via Advanced Custom Fields.
  • You could adjust the markup to allow for align-* as WordPress likes to do. Or with <figure> and <figcaption> elements. Also, alt tags.
  • You could have the settings for the breakpoints be settable via UI that the the plugin creates, rather than hard coded into the plugin.
  • Here's an alternate approach which uses Picturefill 2 and no shortcodes.

Here's the GitHub repo if you want to contribute.