Learn it fast with expert-taught software and skills training at lynda.com. See what you can learn

By Morten Rand-Hendriksen | Thursday, July 24, 2014

Create Responsive Featured Images in WordPress

Create Responsive Featured Images in WordPress

Responsive layouts have become commonplace in today’s web experiences, but the current HTML <img> element still has a fundamental flaw when used with responsive designs: It assumes uniformity in the screens it’s displayed upon, a uniformity that doesn’t exist in today’s mobile-saturated world.

Consider an image on a web page from the viewer’s perspective. Although it appears to be part of the page, it’s actually a replaced element: The code of the page cuts a hole in the page big enough to contain the image, and then retrieves it from its remote location to fill that hole. In some cases the hole has a specified width and height; in others the hole is built to be flexible and scale to a percentage, or proportion, of the screen size.

In responsive web designs, the width of the hole containing an image is defined dynamically by the size of the viewer’s window or screen and limited only by the widest possible size of that screen. The height is set to automatically retain the image proportions relative to its width. On wide screens the viewer sees the image in its native size; on smaller screens the image is squeezed to fit within the smaller hole.

When images were first introduced as HTML elements, the screens upon which they were displayed had uniform sizes and pixel densities. Those days are gone–and today the web lives on devices large and small, with pixel densities ranging from the traditional to resolutions so high they surpass the capacity of the human eye. In today’s fluid environment, the classic HTML image is a poor solution, presenting developers with a tricky dilemma. Should you provide an image big enough to appear crisp on the largest high-res screen, but still force mobile users to download all those pixels? Or instead should you provide an image optimized for mobile browsers that looks comparatively small and uninteresting on big screens?

It’s time we made some progress on responsive images—and now we can.

Responsive Images, the short version

The web community’s been working on a standard for responsive images for some time, and now has a proposal we can start using.

The premise is simple: For in-page images, provide the browser with enough information to display the image that best matches the viewer’s screen width and resolution. For example,

  • On a small screen with low resolution, provide a small image with low resolution.
  • On a large screen with high resolution, provide a large image with high resolution.
  • On a small screen with high resolution, provide a small image with high resolution.
  • On a small screen with high resolution but low bandwidth, provide the best possible image with the smallest file size.

So rather than providing one image to fit all scenarios, we provide the browser with options and let it pick the best image for each viewer’s device.

This new style of responsive images can be implemented in several ways. We can use the traditional <img> element’s new srcset and sizes attributes, which allow us to serve different images depending on screen sizes and resolutions. Or we can use the new <picture> element, which lets us add CSS media queries to the srcset and sizes attributes and provide more detailed instructions for the browser to follow. Either way, image markup is no longer a one-line, one-URL affair—which makes automation an attractive option.

Picturefill.js and stop-gap measures

As with most new standards, responsive images face one major obstacle before becoming broadly accepted: browser support, which is currently non-existent. Fortunately we won’t have to wait for the browsers to catch up, as the team creating the responsive images specification has created a JavaScript that acts as a stop-gap or “polyfill” to let us use these new methods today. The script is called Picturefill, it’s open source, and you can download it and use it in your own projects.

Responsive Featured Images in WordPress

Let’s walk through the process of adding a responsive featured image to a WordPress theme. WordPress is an ideal platform for responsive images because it already creates multiple versions of uploaded images at different sizes, which can be specified by the theme developer. Featured images in WordPress make an ideal target for responsive images as they’re placed into the theme by the developer, while images in WordPress posts are placed by the user. Enabling responsive featured images in WordPress is a great introduction not only to responsive images but also to advanced WordPress theme development.

Step 1: Defining Image Sizes

Adding responsive images to a WordPress theme requires planning. You need to consider which image sizes should be presented, and in which user scenarios. Here two key factors are considered: The screen width and the screen resolution: Screen width will be defined as a min-width value, resolution as an Xx value. The traditional screen resolution of 96ppi is considered 1x; iOS Retina displays, roughly twice the traditional screen resolution, are considered 2x; and many Android devices now ship with up to 3x resolution.

Taking a mobile-first approach, where the largest available image width is 1060px, you could end up with a table like this:

Minimum screen width 1x resolution 2x resolution
0 (smallest screen) 400px x 225px 800px x 490px
400px 800px x 490px 1060px x 650px
800px 1060px x 650px Original size

Note that for each min-width size, the 1x resolution is higher. This is to account for screens that are larger than the defined min-width; an image of 400px wide displayed on a screen that is 401px wide looks awful.

Step 2: Adding new image sizes to the theme

Now that image sizes are defined, we’ll add the image sizes to the theme. Do this in your theme’s functions.php file using the add_image_size() function:

<?php
add_image_size('large-thumb', 1060, 650, true);
add_image_size('medium-thumb', 800, 490);
add_image_size('small-thumb', 400, 245);
?>

We could now retrieve any of these image sizes with the internal the_post_thumbnail( $size, $attr ); function, but this would produce only one image size. For example, this PHP block:

<?php the_post_thumbnail(‘large-thumb’); ?>

outputs the following HTML code:

<img width="1060" height="650" src="http://(...)/wp-content/uploads/2011/07/dcp_20821-1060x650.jpg" class="attachment-post-thumbnail wp-post-image" alt="Boardwalk">

Obviously the resulting img element isn’t particularly flexible with a single, fixed height and width. What we really want is a picture element with all the necessary fallback images like so:

<picture>
  <source srcset="http://mor10.com/wp-content/uploads/2014/05/tools-1060x650.jpg, http://mor10.com/wp-content/uploads/2014/05/tools.jpg 2x" media="(min-width: 800px)">
  <source srcset="http://mor10.com/wp-content/uploads/2014/05/tools-800x425.jpg, http://mor10.com/wp-content/uploads/2014/05/tools-1060x650.jpg 2x" media="(min-width: 400px)">
  <source srcset="http://mor10.com/wp-content/uploads/2014/05/tools-400x212.jpg, http://mor10.com/wp-content/uploads/2014/05/tools-800x425.jpg 2x">
  <img alt="Pencil drawing of a parrot wrench" src="http://mor10.com/wp-content/uploads/2014/05/tools-1060x650.jpg">
</picture>

If this is your first peek at the <picture> element, it can be jarring.

To explain what’s going on in the code, the picture element contains a series of <source> elements. Each of these elements defines a <srcset> containing the URIs to the images’ different resolutions (1x, 2x, 3x, and so on) followed by a CSS media query defining at which sizes the particular image srcset will be triggered. The <source> elements are stacked from the widest screens (top) to narrowest screens (bottom). The last definition is an <img> tag, which contains the default image to be used, along with the <alt> and other attributes.

When this code is loaded into a browser, the “hole” for it is cut out using the <img> tag, and the srcset value from the correct <source> tag is used based on the viewer’s screen width and resolution.

Step 3: Getting the various image sizes from WordPress

To get WordPress to output the correct code, we need to retrieve the various image sizes individually. Our available WordPress functions were never intended to do this, so we’ll have to get crafty.

Assuming we have the post ID, we first need to retrieve the ID for the current featured image, get the alt attribute for that image (or set it to something like the post title if no attribute exists), and then retrieve the data for each of the image sizes as so:

$attachment_id = get_post_thumbnail_id($post_id);
$alt_text = get_post_meta($attachment_id, '_wp_attachment_image_alt', true);
if ( !$alt_text ) { $alt_text = esc_html( get_the_title($post_id) ); }

$thumb_original = wp_get_attachment_image_src($attachment_id, 'full');
$thumb_large    = wp_get_attachment_image_src($attachment_id, 'large-thumb');
$thumb_medium   = wp_get_attachment_image_src($attachment_id, 'medium-thumb');
$thumb_small    = wp_get_attachment_image_src($attachment_id, 'small-thumb');

The wp_get_attachment_image_src(); function returns an array of the image URL, width, and height, along with a value that tells us if it’s been resized. In this case we need just the URL along with the alt text, so for simplicity we can combine them into a new array:

$thumb_data = array(
  'thumb_original' => $thumb_original[0],
  'thumb_large'    => $thumb_large[0],
  'thumb_medium'   => $thumb_medium[0],
  'thumb_small'    => $thumb_small[0],
  'thumb_alt'      => $alt_text
);

Step 4: Building a function to output the <picture> element

For all of this to work, we also need to wrap the code in a function that can be called from a template. The resulting code looks like this:

<?php
/**
* Create function my_responsive_thumbnail() to output responsive featured image
* Function can be called from within the loop of any template file using
* my_responsive_thumbnail(get_the_ID());
*/

function my_responsive_thumbnail($post_id){
// Get the featured image ID
$attachment_id = get_post_thumbnail_id($post_id);
// Get alt text or set the $alt_text variable to the post title if no alt text exists
$alt_text = get_post_meta($attachment_id, '_wp_attachment_image_alt', true);
if ( !$alt_text ) { $alt_text = esc_html( get_the_title($post_id) ); }

// Get the info for each image size including the original (full)
$thumb_original = wp_get_attachment_image_src($attachment_id, 'full');
$thumb_large    = wp_get_attachment_image_src($attachment_id, 'large-thumb');
$thumb_medium   = wp_get_attachment_image_src($attachment_id, 'medium-thumb');
$thumb_small    = wp_get_attachment_image_src($attachment_id, 'small-thumb');

// Create array containing each image size + the alt tag
$thumb_data = array(
'thumb_original' => $thumb_original[0],
'thumb_large'    => $thumb_large[0],
'thumb_medium'   => $thumb_medium[0],
'thumb_small'    => $thumb_small[0],
'thumb_alt'      => $alt_text
);

// Echo out <picture> element based on code from above
echo '<picture>';
echo '<!--[if IE 9]><video style="display: none;"><![endif]-->'; // Fallback for IE9
echo '<source srcset="' . $thumb_data['thumb_large'] . ', ' . $thumb_data['thumb_original'] . ' 2x" media="(min-width: 800px)">';
echo '<source srcset="' . $thumb_data['thumb_medium'] . ', ' . $thumb_data['thumb_large'] . ' 2x" media="(min-width: 400px)">';
echo '<source srcset="' . $thumb_data['thumb_small'] . ', ' . $thumb_data['thumb_medium'] . ' 2x">';
echo '<!--[if IE 9]></video><![endif]-->'; // Fallback for IE9
echo '<img srcset="' . $thumb_data['thumb_small'] . ', ' . $thumb_data['thumb_medium'] . ' 2x" alt="' . $thumb_data['thumb_alt'] . '">';
echo '</picture>';
}?>

The function receives the post ID, and echoes out the full <picture> element. It can then be added within the loop of any template file using the following function call:

<?php my_responsive_thumbnail(get_the_ID()); ?>

Step 5: Adding Picturefill.js to add browser support

At this point, the function outputs the correct code but no responsive images will yet appear. Instead, you get the smallest, default image size—as currently no browsers support the <picture> element. To make everything work, we need to add Picturefill.js into our theme.

First, download picturefill.min.js from the Picturefill website and add the file to your theme /js/ folder. Next, enqueue picturefill.min.js from the functions.php file and ensure it loads into the head of the page:

function my_scripts(){
  wp_enqueue_script( 'my-picturefill', get_stylesheet_directory_uri() . '/js/picturefill.min.js', '20140528', false);
}
add_action('wp_enqueue_scripts', 'my_scripts');

Picturefill’s creators recommend adding the script asynchronously, but this isn’t an option in WordPress yet, so inserting the code directly is our only current option.

Once Picturefill is included you should now see responsive images in your browser. As you change the size of the browser window, the different image files we specified earlier will display; smaller screens will only get the small image sizes, while larger screen widths get the larger images.

Now that we’ve got things working, take a moment to read Picturefill’s Browser Support page to learn which browsers are supported by the script, and what happens when things don’t work as expected.

Step 6: Solving an obvious problem with Transients

The above solution works, but it has an obvious problem: When we add a regular featured image to a post in WordPress, we are making a single query to the database for that featured image. In this new my_responsive_thumbnail() function we are making no less than six queries every time an image is loaded. This is neither lean nor wise from a server load perspective.

Fortunately, WordPress has a built-in caching system called “transients” that can help us out. In WordPress, a transient is a piece of cached data we can set up, retrieve, and delete any time we like. So rather than querying the database six times every time we want to display a responsive featured image, we can cache the featured image data when the featured image is created and just call the cached transient with a single query when we want to display it. This requires a substantial rework of our code, but the key components remain the same as before:

/**
* Function for responsive featured images.
* Creates a  element and populates it with appropriate image sizes for different screen widths.
* Works in place of the_post_thumbnail();
*/

function simone_the_responsive_thumbnail($post_id) {
// Check to see if there is a transient available. If there is, use it.
if ( false === ( $thumb_data = get_transient( 'featured_image_' . $post_id ) ) ) {
  simone_set_image_transient($post_id);
  $thumb_data = get_transient( 'featured_image_' . $post_id );
}

echo '<picture>';
 echo '<!--[if IE 9]><video style="display: none;"><![endif]-->';
 echo '<source srcset="' . $thumb_data['thumb_large'] . ', ' . $thumb_data['thumb_original'] . ' 2x" media="(min-width: 800px)">';
 echo '<source srcset="' . $thumb_data['thumb_medium'] . ', ' . $thumb_data['thumb_large'] . ' 2x" media="(min-width: 400px)">';
 echo '<source srcset="' . $thumb_data['thumb_small'] . ', ' . $thumb_data['thumb_medium'] . ' 2x">';
 echo '<!--[if IE 9]></video><![endif]-->';
 echo '<img srcset="' . $thumb_data['thumb_small'] . ', ' . $thumb_data['thumb_medium'] . ' 2x" alt="' . $thumb_data['thumb_alt'] . '">';
 echo '</picture>';
}

/**
* Create image transient to avoid looping through multiple image queries every time a post loads.
* Called any time a post is saved or updated right after existing transient is flushed.
* Called by simone_the_responsive_thumbnail when no transient is set.
*
* - Get the featured image ID
* - Get the alt text (if no alt text is defined, set the alt text to the post title)
* - Build an array with each of the available image sizes + the alt text
* - Set a transient with the label "featured_image_[post_id] that expires in 12 months
*/

function simone_set_image_transient($post_id) {
  $attachment_id = get_post_thumbnail_id($post_id);
  $alt_text = get_post_meta($attachment_id, '_wp_attachment_image_alt', true);
  if ( !$alt_text ) { $alt_text = esc_html( get_the_title($post_id) ); }
    $thumb_original = wp_get_attachment_image_src($attachment_id, 'full');
    $thumb_large   = wp_get_attachment_image_src($attachment_id, 'large-thumb');
    $thumb_medium   = wp_get_attachment_image_src($attachment_id, 'medium-thumb'); 
    $thumb_small   = wp_get_attachment_image_src($attachment_id, 'small-thumb');
    $thumb_data = array(
      'thumb_original' => $thumb_original[0],
      'thumb_large'    => $thumb_large[0], 
      'thumb_medium'   => $thumb_medium[0],
      'thumb_small'    => $thumb_small[0],
      'thumb_alt'      => $alt_text
);

set_transient( 'featured_image_' . $post_id, $thumb_data, 52 * WEEK_IN_SECONDS );
}

/**
* Reset featured image transient when the post is updated
*/

add_action('save_post', 'simone_reset_thumb_data_transient');

function simone_reset_thumb_data_transient( $post_id ) {
  delete_transient( 'featured_image_' . $post_id );
  if ( has_post_thumbnail($post_id) ) {
    simone_set_image_transient($post_id);
  }
}

Worth noting here is the transient function, which sets up a transient that lasts for one year and provides a fallback if the transient somehow gets flushed. The last function clears the transient and creates a new one any time a post or page is updated.

Real-life usage

Now that you’ve seen the code, you are probably wondering if this really works. The answer is yes! A slight variation of the last function, complete with transients, is what is displaying featured images on http://mor10.com. The function also ships with the most recent version of the Simone theme currently available from GitHub. As I said, these are early days and this is an early-stage example of how responsive featured images can be incorporated into WordPress. The example was built to show the decision, coding, and caching processes necessary to build this new type of functionality into a WordPress theme or child theme. Now that you know how, it’s your turn to take this code, improve upon it for your own projects, and contribute your improvements back to the community.

Responsive images are powered by the community of web developers who use them. So use them!

Learn it from the experts.

With online video courses at lynda.com, you can reach your goals faster. Learn software, improve your skills, and get an inside look at how the professionals work.

See what you can learn


Share this article:

Tags: , , , , , , ,

Get the latest news

  •   New course releases
  •   Pro tips and tricks
  •   News and updates
  
New releases submit clicked

You can change your email preferences at any time. We will never sell your email. More info

Featured articles

A lynda.com membership includes:

Unlimited access to thousands of courses in our library
Certificates of completion
New courses added every week (almost every day!)
Course history to track your progress
Downloadable practice files
Playlists and bookmarks to organize your learning
Become a member

Thanks for signing up.

We’ll send you a confirmation email shortly.


Sign up and receive emails about lynda.com and our online training library:

Here’s our privacy policy with more details about how we handle your information.

Keep up with news, tips, and latest courses with emails from lynda.com.

Sign up and receive emails about lynda.com and our online training library:

Here’s our privacy policy with more details about how we handle your information.

   
submit Lightbox submit clicked
Terms and conditions of use

We've updated our terms and conditions (now called terms of service).Go
Review and accept our updated terms of service.