Note: this post is old. Pre-Gutenberg. Please read it with that in mind. I am working on and plan to release (in 2020) a custom plugin for WordPress which will use the picture element. More on that when ready.

It’s taken me a long time to feel as though I understand WordPress’ core implementation of srcset. Maybe one could attribute the length of time necessary for comprehension to my lack of programmer brain skills. That could be. My only lingering concern resides in understanding how to completely unset WordPress’ standard image style queries. Perhaps we can not get that granular. For example, I wish there was a way to only load specific image styles per instance or components’ context. Perhaps what I truly want is a viable <picture> element and picture-mapping breakpoint plugin in WordPress.

This post touches on strategy advice for creating effective image styles based on width-based ratios and how those styles can be used with the Advanced Custom Fields plugin.

My setup: theme and plugins

Helpful resources and WordPress’ own documentation

Some articles about srcset really helped steer me in the right direction in terms of conceptually wrapping my head around how it’s used.


Methodology: image ratios versus image width

I’ve spent some time wrestling with WordPress srcset implementation–trying to extend the default thumbnail, small, medium and large image ratios further. This is one of those weird WordPressy things that gets tricky and kinda messy should you want to extend functions like these.

For my own use case, I figured that starting with a 16:9 ratio for all source images, followed by adding an array of specific sizes within the 16:9 ratio would work. It does work, but it’s too specific and I found that rather problematic in being a sustainable option. I went researching for image ratio methodology and advice.

There are so many articles about WordPress’ use of srcset but none effectively tackle or give advice on practical image ratios. My advice on this is to start with what you can realistically handle. Meaning, asking yourself how you prepare your images. If you use Photoshop to manually craft lead/featured images and custom image fields, then it might not make sense to make WordPress adhere to those specific dimensions. The crux of srcset is ratios. The browser will only receive the same srcset ratio of sized images that match the ratio of the originally uploaded image. What’s really neat is that you can also simply define an image width and those widths will all get added to the srcset array, which the browser then uses to choose the appropriately sized image to render, given the user’s device resolution. Granted, this is achieved with a bit of help. More on that below in a helper function.

A powerful obstacle: ACF plugin

What’s more than understanding WordPress’ implementation and image ratios, was understanding how to extend its power to the custom fields I’ve created using the Advanced Custom Fields Plugin for WordPress.

By default, ACF doesn’t support srcset properties for custom images. So there are several options ahead to overcome this obstacle. For a while I used WordPress’ get_thumbnail('size'); function for all featured images. Then I simply referenced the largest size I needed for ACF image fields, using the array return value. Then in some templates, I used a slight variation on returning the image values I wanted. The point here is that it all felt too inconsistent. There had to be a better and saner way! And there is!

After lots of trial-and-error, I have drawn the following conclusions and present each as advice for anyone struggling with srcset in WordPress.


Definition: making your own srcset image sizes

I finally landed on defining image sizes by width, only. I know that I can control the ratio in whatever computer application I’m using to generate the images. It’s redundant to impose the same ratio limitations within my CMS. This was the biggest revelation to me. I spent hours wrestling with different aspect ratios, defining them and regenerating all my website’s images.

By defining the widths only you have all the power and leverage all the reusable greatness.

Step one: unset WordPress’ sizes

This is optional, but I find it can be helpful to remove all unnecessary markup noise one can remove.

// unset WordPress core image sizes
function core_image_sizes($sizes) {
	unset($sizes['thumbnail']);
	unset($sizes['medium']);
	unset($sizes['medium_large']);
	unset($sizes['large']);
	return $sizes;
}
add_filter('intermediate_image_sizes_advanced', 'core_image_sizes');

My custom image sizes

Set your own image sizes.

// custom image sizes
if ( function_exists( 'add_theme_support' ) ) {
  add_theme_support( 'post-thumbnails' );
  set_post_thumbnail_size( 1800, 9999 );

  // additional image sizes

  add_image_size( 'teaser-square', 300, 300, true);
  //300 square pixels cropped
  
  add_image_size( 'teaser-square-medium', 600, 600, true); 
  //600 square pixels cropped
  
  add_image_size( 'teaser-square-x-large', 800, 800, true);
  //800 square pixels cropped

  // width-only images

  add_image_size( 'three-fourty', 340);
  add_image_size( 'four-twenty', 420);
  add_image_size( 'six-hundred', 600);
  add_image_size( 'seven-sixty', 760);
  add_image_size( 'eight-eighty', 880);
  add_image_size( 'ten-eighty', 1080);
  add_image_size( 'twelve-sixty', 1260);
  add_image_size( 'fourteen-hundred', 1400);
  add_image_size( 'eighteen-eighty', 1880);
}

With this setup, I have the freedom to easily reuse all these sizes instead of making them too specific to pieces of content. Having specific ratios may also impose more structure than necessary, too. Again, this is coming from someone who prepares their images prior to uploading them.

Methodology: custom responsive image helper function

//
// Responsive Image Helper Function for ACF
// 
// @param string $image_id the id of the image (from ACF)
// @param string $image_size the size of the thumbnail image or custom image size
// @param string $max_width the max width this image will be shown to build the sizes attribute
//
function grangler_responsive_image($image_id,$image_size,$max_width){
	// check the image ID is not blank
	if($image_id != '') {
	
        // set the default src image size
	$image_src = wp_get_attachment_image_url( $image_id, $image_size );
	// set the srcset with various image sizes
	$image_srcset = wp_get_attachment_image_srcset( $image_id, $image_size );
	// generate the markup for the responsive image
	echo 'src="'.$image_src.'" srcset="'.$image_srcset.'" sizes="(max-width: '.$max_width.') 100vw, '.$max_width.'"';
   }
}

Which I use in my templates in the following way.

Declare variables

<?php
/**
 * The template part for displaying content teaser
 *
 * @package WordPress
 * @subpackage Twenty_Sixteen
 * @since Twenty Sixteen 1.0
 */
 // get the featured image by defining some variables to print below.
   $featured_image = get_post_thumbnail_id();
   $featured_image_size = 'twelve-sixty'; // Set to custom size set in functions.php
   $featured_image_alt = get_post_meta($featured_image, '_wp_attachment_image_alt', true);
?>

I place my variables, when possible, at the top of each template file, that they’re used in. This brings me comfort in easily scanning the file and getting a quick overview of what I’m doing.

Call the function in your template, passing in the image variables

// print the featured_image variable if it isn't empty.
<?php if( !empty($featured_image) ): ?>
  <span class="post-thumbnail">
    <figure <?php post_class('featured-image');?>>
       <img <?php grangler_responsive_image($featured_image, $featured_image_size,'1260px'); ?><?php echo 'alt="' . $featured_image_alt . '"';?> />
    </figure>
  </span>
<?php endif; ?>

This helper function has served me well. Massive thank you to Aaron Rutley for sharing his helper function. Without it this would’ve taken me longer to figure out.


Conclusions

In conjunction with caching and decent lossless image optimization, srcset can help make your site more performant. I’m excited to push this further, as there may be room for less repetition. The line of how much is too much abstraction is another topic entirely.

I’d love to know if anyone has a better approach than where I’ve landed. Let me know if you’ve had your own srcset or image-related performant revelations.