Note: this post is old. Pre-Gutenberg. Please read it with that in mind. I am working on and plan to release (in 2021 or 2022) a custom plugin for WordPress which will use the picture element. More on that when ready. This post only got me so far in terms of the control I was looking for, but it served its purpose when I needed it.

This post touches on strategic advice for creating effective image styles based on width-based ratios and how those styles can be used with the Advanced Custom Fields plugin. What I was really looking to accomplish, for my purposes and as the catalyst for this post, was to define and serve purposeful somewhat art-directed image sizes. Rather, I wanted a bit more control over what image sizes are being chosen by the browser.

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

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 serve an image in a size which matches the ratio of the uploaded image. So what we’re really aiming for here is defining image widths.

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. This way you don’t have to worry about WordPress’ image size definitions being served by the browser instead of your more purposeful image size.

// 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.