DIY Truly Responsive Images on Your WordPress Website

Responsive Web Design is all the craze at the moment. Watching websites cascade into different layouts as you resize the browser can even be mesmerising.

But there’s one facet of RWD that still remains a (properly) unsolved problem. Responsive Images.

Download the source files (twentytwelve child theme).

If you simply use CSS’s max-width: 100%; attribute, mobile sites will still be downloading full size images. That’s an issue, because if your desktop site has images 920px wide, the mobile version will still be downloading this massive image, making loading time slow.

Enter Picturefill

Picturefill is a javascript library that loads the smallest possible image first, and then updates that image on-the-fly depending on the screen resolution it’s being served on.

This works well because for mobile devices, essentially nothing changes. The smallest possible image is loaded quickly.

For Tablets and Desktops, a different source image is specified, and as soon as Javascript kicks in, it will halt the download of the smaller image and swap it out for a more appropriately sized one.

The Syntax

Unfortunately, the syntax for this is rather verbose:

<div data-picture data-alt="Image alt text">
  <div data-src="mobile.png"></div>
  <div data-src="tablet.jpg"        data-media="(min-width: 768px)"></div>
  <div data-src="desktop.jpg"       data-media="(min-width: 920px)"></div>
  <div data-src="large-desktop.jpg" data-media="(min-width: 1140px)"></div>

  <!-- Fallback content for non-JS browsers. -->
  <noscript>
    <img src="mobile.png" alt="Image alt text">
  </noscript>
</div>

That’s a lot of code for just one image! Fortunately, we can create a shortcode for this, so you only have to write it once.

Let’s say we’re replacing the featured image of every post on your blog with this responsive shortcode. Even if you’ve been uploading images for a long time at a certain width, that’s fine. We can use Regenerate Thumbnails to make them the correct sizes. But I’ll get to that later.

Setup

No matter your blog, you can do this on any existing website. I’ll be making a child theme of TwentyTwelve on a fresh installation with several images uploaded at 920px for demonstration purposes. The theory, however, is entirely the same on any website and the code will work on yours too.

Here you can see two cute cats just chillin’. Unfortunately, the size of the image is way larger than necessary. This is going to slow down the page. Maybe not by much, but it’s still unnecessarily large!

Only visible at 1/3 of its actual size, we’re wasting resources!

The solution to that is as I’ve said, Picturefill. But we want to create something reusable, where you don’t have to manually enter each image size every single time you need a responsive image.

So we turn to shortocdes. Ideally, you’d structure a shortcode as so:

[rimg src="http://link-to-the-image.png" caption="This is the caption"]

Simple enough. The only downside is using the “insert into post” feature becomes semi-useless. There is absolutely a hack around it, but I won’t be getting into that today.

Our Image Sizes and Breakpoints

For my TwentyTwelve site, there are several breakpoints, but I’ll be focussing on only 3 image sizes:

  • 740px – The largest a desktop image can be
  • 540px – The largest an image can be after hitting a ‘tablet’ breakpoint
  • 340px – The largest an image can be when at mobile size

We start by adding new image sizes, so that new cropped thumbnails are created every time a new image is uploaded.

Open up the functions.php file of your theme, or create it in your new theme and add the following lines:

<?php

/*
 *  Custom image sizes for responsivity.
 */

add_image_size('resp-large', 720, 9999);
add_image_size('resp-medium', 520, 9999);
add_image_size('resp-small', 320, 9999);

Now, every time a new image is uploaded, a version at each size specified will be created. The 9999 parameter is the height, and setting it to this allows for unlimited height.

But what about all my old images?

No problem. Like you, I’ve uploaded images for this tutorial that do not yet have thumbnails at these sizes.

Regenerate Thumbnails hides in the Tools Menu.

Enter Regenerate Thumbnails. It’s a handy plugin that goes through every single image you’ve ever uploaded, and regenerates thumbnails based on images sizes currently set for your site.

Go to the page, and hit “Regenerate All Thumbnails.” You’ll be presented with a progress bar as your thumbnails get regenerated to all the correct sizes. If you’re doing this live and have a lot of images, this could take some time.

Regenerate Thumbnails has a surprisingly nice UI!

Now we’ve got images at the correct sizes, it’s time to put them to use.

Installing Picturefill

Just like any Javascript library you install to your theme, we have to add the Picturefill script to the wp_enqueue_scripts() hook. Go ahead and download Picturefill (right click, save target as), and place it in your theme folder.

If you’re familiar with enqueuing scripts, you should know how this goes. If not, copy the code below into your functions.php file just below the add_image_size() functions.

/*
 *  Enqueue Picturefill to the front-end
 */

function add_picturefill(){
  wp_enqueue_script(
    'picturefill',
    get_bloginfo('stylesheet_directory').'/picturefill.js' );
}

add_action('wp_enqueue_scripts', 'add_picturefill');

Our custom function add_picturefill() enqueue’s the script. To enable it, however, we need to hook into “wp_enqueue_scripts” using add_action().

If you save and refresh, and view the source of your page, you should be able to find the picturefill script nicely included in the <head>

Now that’s there, we have to build something reusable that will automatically generate responsive images without having to write out the overly verbose code for each image.

Responsive Image Shortcode

Shortcodes come to the rescue! Shortcodes are cool. They are basically a way to build custom ‘elements’. Read up a little bit about them if you’re unaware of them.

Our shortcode is going to look like this:

[rimg src="http://link-to-full.size/image.png caption="This will be the alt and caption"]

Easy enough, right? Considering it will spit out a completely responsive image, I think shortcodes are a godsend.

Our shortcode function will do a number of things, in order.

  1. Check if an image source URL is present
  2. Retrieve ID of image from source URL
  3. Retrieve different image sizes URLs from ID
  4. Return the correct HTML structure for Picturefill with image URLs
  5. Check if caption is present, and if so spit out the caption

The Code

Now this presents one big problem- how do we get all the other image sizes just from a URL? Ideally we want an ID, but it makes more sense to input a URL, right?

That’s cool. I’ve researched a nifty little function that will return the ID of an image when you provide the original image url. If you try to pass a thumbnail image, it won’t work. Regardless, here’s the snippet that you should drop into your functions.php.

/*
 *  Get image ID from URL
 */

function get_attachment_id_from_src($url) {
  global $wpdb;
  $prefix = $wpdb->prefix;
  $attachment = $wpdb->get_col($wpdb->prepare("SELECT ID FROM " . $prefix . "posts" . " WHERE guid='%s';", $url ));
    return $attachment[0];
}

I wish WordPress had a built in function for this kind of stuff. It’s pretty nasty (looking) code, but it’s essentially a database query that looks in the posts table (where image attachments are stored) for the ID, and returns the first result.

Back to the shortcode. To prove this function works, we’ll build the start of our shortcode, and then use it in a post. Drop the following into your functions.php file after the get_attachment_id_from_src() function.

/*
 *  Responsive shortcode
 */

function responsive_image($atts){
  extract( shortcode_atts( array(
    'src' => '',
    'caption' => '',
  ), $atts ) );

  return get_attachment_id_from_src($src);
}

add_shortcode('rimg', 'responsive_image');

If you’re not familiar with the Shortcode API, this is the code for creating a self-contained shortcode. The add_shortcode() function looks very similar to the add_hook() function, which makes understanding it very easy.

The tricky bit is to wrap your head around is lines 2-5 of the function. The extract() function basically presents us with our defaults if nothing is supplied. Which hopefully it never is. But we can use this empty string to test whether to output the image code later.

Finally, the return line uses our helper function to output the ID of an image URL.

In practice

I’ve gone ahead and used a shortcode that we’ve just created.

And if we look on the front-end of that post, instead of seeing a shortcode, we see an ID! Great!

Getting the Different Sized URLs

Now that we’ve got a function that returns an image ID from URL, we can start building the Picturefill HTML code around it. Update your responsive_image() function to look like this:

function responsive_image($atts){
  extract( shortcode_atts( array(
    'src' => '',
    'caption' => '',
  ), $atts ) );
  if($src != '')
  {
    $img_ID = get_attachment_id_from_src($src);
    $large = wp_get_attachment_image_src( $img_ID, 'resp-large' );
    $medium = wp_get_attachment_image_src( $img_ID, 'resp-medium' );
    $small = wp_get_attachment_image_src( $img_ID, 'resp-small' );

    $output = $src;
  }

  return $output;

}

Here, all we’re doing is getting different sized image URLs. We’ve now got the following variables available to us:

  • $image_ID
  • $caption
  • $src
  • $large
  • $medium
  • $small

And the shortcode will now output the URL we specified when writing it.

The Picturefill Code

At long last, we’re ready to output some HTML that will end up as our responsive image. Since it’s a shortcode, we need to return everything, instead of echo it.

Here’s a handy tip. When you want to return large variables, you can add a period into the mix to add to an array.

Have a look at this:

$output = "Hello ";
$output.= "World!";

echo $output;

//echos "Hello World!"

Cool huh? So we can use this in our shortcode function to output clean HTML. Here’s the updated function, it’s big but it’s really just adding the HTML.

function responsive_image($atts){
  extract( shortcode_atts( array(
    'src' => '',
    'caption' => '',
  ), $atts ) );
  if($src != '')
  {
    $img_ID = get_attachment_id_from_src($src);
    $large = wp_get_attachment_image_src( $img_ID, 'resp-large' );
    $medium = wp_get_attachment_image_src( $img_ID, 'resp-medium' );
    $small = wp_get_attachment_image_src( $img_ID, 'resp-small' );

    $output = '<div class="responsive-image">';
    $output = '  <div data-picture data-alt="' . $caption . '">';
    $output.= '    <div data-src="' . $small[0] . '"></div>';
    $output.= '    <div data-src="' . $medium[0] . '" data-media="(min-width: 786px)"></div>';
    $output.= '    <div data-src="' . $large[0] . '" data-media="(min-width: 920px)"></div>';
    $output.= '    <div data-src="' . $src . '" data-media="(min-width: 1140px)"></div>';
    $output.= '    <noscript>';
    $output.= '      <img src="' . $small[0] . '" alt="' . $caption . '">';
    $output.= '    </noscript>';
    $output.= '  </div>';
    if($caption != '') $output.= '  <p class="caption">' . $caption . '</p>';
    $output.= '</div>';
  }

  return $output;

}

That’s a whole lot of code, but all we’ve really added is the $output variable.

If you refer from the top of this post, it echoes the syntax Picturefill requires to work. The only difference is we’re replacing the image URLs with out dynamically retrieved thumbnails. At the end, there is a conditional statement that prints a caption if it’s necessary.

Right now, you have a perfectly working responsive shortcode to use!

“This little critter is only 320px wide.”

If you drag your window wider and wider, and inspect the <img> element that is displayed, the src changes as you hit break points!

The next breakpoint is hit, a new image loaded

Sweet! Truly responsive images, that will take up the least amount of bandwidth possible.

What About My Featured Images?

No stress. You’re going to have to dig around your theme files a bit, to look for the_post_thumbnail(), or whatever code spits out your post thumbnail. In the case of TwentyTwelve, it’s in the content.php file (which I’ve overridden with a child theme).

Replace

<?php the_post_thumbnail(); ?>

with

<?php
  $thumb = wp_get_attachment_image_src( get_post_thumbnail_id($post->ID), 'original' );
  $url = $thumb['0'];
  echo do_shortcode( '[rimg src="' . $url . '"]' );
?>

And you’ll instantly have responsive featured images too!

If this doesn’t work and your images are blown out, remember to use Regenerate Thumbnails to regenerate your images at the right sizes.

And that’s it! If you wish to download the source code, I’ve zipped up the TwentyTwelve Child Theme I created during this tutorial.

Responsive Images are a great way to save bandwidth, stay up with the curve and keep your readers happy with short loading times. Hopefully, the proposed < picture> element will make the final spec, so minimal changes will be need to made to this code in order for it to stay up to standards.

If you have any questions, feel free to ask below!

Comments (14)

  1. The only downside is using the “insert into post” feature becomes semi-useless. There is absolutely a hack around it, but I won’t be getting into that today.

    Could you point us in the right direction?

      • Follow up to my last reply: the script/PHP solution from the 24Ways article does indeed work, although I’m limited in my ability to test it since I don’t have access to a smartphone or a tablet.

        Since my installation is multisite, I installed the files (.htaccess, adaptive-images.php, and a writable cache directory) in /wp-content/blogs.dir/#, where # is the site I want to apply this to. Changed the paths in the 2 files to match the new location, excluded some directories, and changed the default settings in adaptive-images.php. I can see the smaller files being created when I visit the site, so I know it works.

  2. Hi Harley, Interesting and informative post. You made it look so easy. I got to check out your 2012 child theme. You said

    “And that’s it! If you wish to download the source code, I’ve zipped up the TwentyTwelve Child Theme I created during this tutorial.”

    I could not find a link to the zip file on this post. Could you provide me with the zip or provide the link?

  3. Has anyone tested this on Android 2.3? There is a current unresolved issue regarding this on Picturefill github, so I presume you’ll have the same issues. And with a significant percentage of Android users still on 2.3 it is a showstopper in my opinion.

  4. Pretty neat, works like a charm on my featured images. Just one question: is it possible to make sure every image someone adds in the content is replaced by the shortcode? Cause the editors using my website won’t be able to (remember how to) use shortcodes, as you might understand.

  5. Hi, it only works amazingly well after I realised that if you get the newer version of picturefill, it uses spans instead of divs.

    “NOTE: if you need/prefer to use divs in your picturefill markup, you may want to grab v1.0.0: https://github.com/scottjehl/picturefill/tree/v1.0.0 . The current version here made the switch to span to better mimic an img element’s inline nature, as well as fix a bug or two for WordPress users.”

    Maybe the tutorial could be updated for future generations.

Participate