Wordpress Responsive Images – Image Sizes in srcset

In a world of varying pixel densities, the 'srcset' and 'sizes' attributes are a lifesaver when rendering responsive image markup. WordPress automatically handles responsive images for site builders; however, it's going to make some assumptions that you may or may not agree with. Specifically, you don't get to decide which image sizes are used. wp_calculate_image_srcset() will look for image sizes with matching ratios (within 1px) and simply use them. What if this doesn't work for you?

Instead of simply forking wp_calculate_image_srcset() or wp_get_attachment_image_srcset(), I decided to write a custom function that does all of the heavy lifting of generating responsive image markup. Provide the following parameter - 1) the attachment ID, 2) an array of image sizes, 3) the default image size, 4) a 'sizes' attribute string, and 5) an optional array of attributes - and you get a rendered <img> element back:

<?php
/**
 * @param int $attachment_id
 *     ID of image.
 * @param array $image_sizes
 *     An array of strings of Wordpress image size names.
 * @param string $default_image_size
 *      The fallback image size to use for the "src" attribute.
 * @param string $sizes
 *      Value for 'sizes' attribute.
 * @param array $attributes
 *      An optional array of attributes.
 *         E.g. array('title' => 'Sample title', 'class' => 'header-image')
 *
 * @return string
 *     An <img> element.
 */
function custom_image_markup_generator($attachment_id, $image_sizes, $default_image_size, $sizes, $attributes = array() ) {
   
$src_array = wp_get_attachment_image_src($attachment_id, $default_image_size);

   
$attributes['width'] = $src_array[1];
   
$attributes['height'] = $src_array[2];

   
$meta = get_post_meta($attachment_id);
   
$attributes['alt'] = (!empty($meta['_wp_attachment_image_alt']) ? $meta['_wp_attachment_image_alt'][0] : "");
   
$attributes['src'] = $src_array[0];

   
// Loop through image sizes to generate srcset value.
   
$srcset_items = array();
    foreach (
$image_sizes as $image_size) {
       
// If image style is default, then srcset values are already known.
       
if ($image_size == $default_image_size) {
           
$srcset_url = $attributes['src'];
           
$srcset_width = $attributes['width'];
        }
       
// If image style is not default, then generate srcset values.
       
else {
           
$srcset_array = wp_get_attachment_image_src($attachment_id, $image_size);
           
$srcset_url = $srcset_array[0];
           
$srcset_width = $srcset_array[1];
        }

       
$srcset_items[] = $srcset_url . ' ' . $srcset_width . 'w';
    }
   
$attributes['srcset'] = implode(', ', $srcset_items);
   
$attributes['sizes'] = $sizes;

   
// Build attributes string for <img> element.
   
$attributes_string = '';
    foreach (
$attributes as $attr_name => $values) {
       
$attributes_string .= $attr_name . '="' . $values . '" ';
    }
   
// Insert attributes string into <img> element.
   
$output = '<img ' . trim($attributes_string) . '>';

    return
$output;
}
?>

Example Usage

To use in practice, we'll need to echo the return of the function - probably in a template file. E.g.:

<?php
 
echo custom_image_markup_generator(45, array('profile_1x', 'profile_2x'), 'profile_1x', '60px', array('class' => 'profile-img'));
?>

In this example, the image ID (a.k.a. attachment ID) is 45. Two image sizes are being used: 'profile_1x' and 'profile_2x'. The first is also the default image size. We're using '60px' as the sizes attribute, and we're adding a class attribute with 'profile-img' as the value. In practice, the image ID will probably be provided to us in the template. A common use case would be using Advanced Custom Fields to render the image as an integer representing the image ID. We can then feed that integer into custom_image_markup_generator() as the first parameter.

Comments

Thanks for this. I’m about to rework a homepage slideshow as WP is not implementing the built-in srcset functionality and thus serving 2000px wide heros to smartphones.

But I’m confused as to the code-end implementation. Assuming one adds this to functions.php, how does one invoke it on the front-end? Wondering if you could help in this regard. WordPress is catching up, but the responsive image game is tricky. Your plugin looks like it might do the trick but I’m unsure of deployment.

Chris Burge's picture

I updated the article to include an 'Example Usage' section. Take a look at that and see if that helps.

Add new comment