I recently teamed up with Mat Marquis of the Responsive Images Community Group to help integrate responsive images into the WordPress platform. We decided to refactor a plugin that I had built several months ago, hoping that it would lead to a more useable and performant solution.
After months of pull requests, conversations on Slack and help from WordPress’ core team, we’re finally ready to share what we’ve been working on. You can download and install RICG Responsive Images from WordPress’ plugin directory, while keeping track of our development progress on GitHub.
What Does The Plugin Do?
WordPress hasn’t changed the way it outputs the img
tag in quite some time. And although there are plenty of ways to hook into WordPress’ native functions and alter the img
snippet, doing so can be overwhelming for beginners and non-theme developers alike. Compound that with the complexity of Picturefill and of the srcset
specification, and WordPress users have had few options for implementing a clean and properly functioning responsive images solution.
Further Reading on SmashingMag:
- Responsive Images Now Landed In WordPress Core
- Automating Art Direction With The Responsive Image Breakpoints Generator
- Introducing The Responsive Image Breakpoints Generator
- Responsive Images Done Right: A Guide To
- Responsive Images In WordPress With Art Direction
To solve this problem, we set out to build a plugin that gives users responsive images as soon as the plugin is installed, with no extra effort needed. No admin setting, media uploading configuration or coding is required. The plugin comes with one dependency, a polyfill for browsers that don’t yet support native responsive images. Removing this file is completely optional and will not affect the functionality of the plugin, as long as the user has a modern browser.
As soon as an image is uploaded through the media interface, WordPress automatically creates three variations of the image at different sizes. When the plugin is activated, adding “Featured” and content images to a post will return WordPress’ standard image markup, with an added srcset
attribute. We’re using the srcset
attribute because it’s the easiest attribute for both developers and users to add. While the picture
element provides the user with a richer set of options, we felt that the srcset
attribute makes the most sense as an out-of-the-box solution. It’s also best to use when you’re focusing on resolution-switching more than art direction (more on that later in the article).
<a href="http://ricg.dev/wp-content/uploads/2015/01/image.jpg"><img class="alignnone size-full wp-image-6" src="http://ricg.dev/wp-content/uploads/2015/01/image.jpg" srcset="http://ricg.dev/wp-content/uploads/2015/01/image-150x150.jpg 150w, http://ricg.dev/wp-content/uploads/2015/01/image-300x300.jpg 300w, http://ricg.dev/wp-content/uploads/2015/01/image-1024x1024.jpg 1024w, http://ricg.dev/wp-content/uploads/2015/01/image.jpg 1800w" alt="a cool responsive image" width="1800" height="1800"></a>
The plugin is designed to be backwards-compatible, meaning that images added before the plugin was installed will be responsive when added to a post or “Featured Image” section. This is because it uses the image sizes previously defined by WordPress and the active theme’s functions.php
file. The image ratio will be maintained throughout the srcset
array, meaning that images differing from the aspect ratio of the initial uploaded image will be left out.
Theme developers can use the plugin to place responsive images wherever they’d like by using the tevkori_get_srcset_string()
function, which takes an image’s ID and size as parameters.
<img src="myimg.png" <?php echo tevkori_get_srcset_string( 11, 'medium' ); ?> />
There’s also a tevkori_get_srcset_array()
function that takes the same parameters and returns an array of srcset
values for the specified image.
How Does The Plugin Work?
Most of the functionality happens when an image is dropped into WordPress’ WYSIWYG editor. Because all of the resized images will have been created during the uploading process, the only thing left to do is create an array containing the URLs of the available images in various sizes, as well as their dimensions. This array is then filtered to remove the image sizes with aspect ratios that don’t match the ratio of the full-sized image.
The array is created by calling the wp_get_attachment_image_src()
function and storing the results. At the same time, we use wp_get_attachment_metadata()
to retrieve the same results but for every possible variation of the image. Next, the ratio is calculated by multiplying each image’s width by the result of the initial image’s height divided by the initial image’s width. If that result matches the initial image’s height, then the image will be pushed into the final array, to be returned by the tevkori_get_srcset_array()
function.
The tevkori_get_srcset_string()
function calls tevkori_get_srcset_array()
and places the result inside of the srcset
attribute. A filter is applied to the image_send_to_editor
function, where a regular expression is used to place the result of the tevkori_get_srcset_string()
function directly after the src
attribute in the image. The same process occurs for featured images, with a filter being applied to the post_thumbnail_html
function.
If the image size is changed in the post’s editor, then the plugin will detect the change and update the srcset
value accordingly. This ensures that the correct image ratio is always maintained. To enable this functionality, we’re using JavaScript to hook into the wp.media
object and recalculating the srcset
attribute by running the same image-ratio calculations defined in tevkori_get_srcset_array()
. Before starting on this project, I was unaware of the wp.media
object and its useful functionality. Because not much documentation for it exists, explaining in detail how we’re using it might be helpful. As it turns out, you can listen for an image-update
event in the post’s editor by adding an event listener to the wp.media
object.
wp.media.events.on( 'editor:image-update', function( args ) {
var image = args.image;
//more function logic
});
With this function, a theme developer can access every image as soon as it has been updated in the post’s editor. You can also take advantage of Underscore, which is used as a dependency by the media uploader to edit image data on the fly. In the case of our plugin, we’re using a helpful Underscore utility to get our image-size ratios once the editor:image-update
event has been fired.
// Grab all of the sizes that match our target ratio and add them to our srcset array.
_.each(sizes, function(size){
var softHeight = Math.round( size.width * metadata.height / metadata.width );
// If the height is within 1 integer of the expected height, let it pass.
if ( size.height >= softHeight - 1 && size.height <= softHeight + 1 ) {
srcsetGroup.push(size.url + ' ' + size.width + 'w');
}
});
To learn more about how we hook into the wp.media
object, be sure to look at the code in wp-tevko-responsive-images.js
.
The sizes Attribute
Currently, this plugin doesn’t add a sizes
attribute to complement the srcset
attribute. The reason is that we initially recognized that we could never predict what those sizes would need to be, because they depend on how the user’s theme is styled. While we are working on a solution to this issue, we’re encouraging all users to include a sizes
attribute on their own, either manually or via another WordPress plugin, such as wp-lazysizes. One thing to note is that the responsive images specification has recently changed, and use of the w
descriptor must now be followed by a sizes
attribute. Omitting the sizes
attribute will render the markup technically invalid, while still falling back to a default size of 100vh
.
What About Features X, Y And Z?
While much more can be done with responsive images, you’ve probably noticed a few use cases that this plugin doesn’t cover. The first thing that we’re usually asked about is a feature for art direction. Art direction refers to loading differently styled images at different breakpoints — whether that means entirely new images or the same image cropped or focused differently. This feature would require use of the picture
element, which in turn would mean a lot more markup to generate the final image.
Adding this feature to WordPress would be impossible without the addition of a fairly complicated interface in WordPress’ media uploader, because the user would need to be able to define all breakpoints and then select images to be loaded in when those breakpoints are reached. Our goal for this plugin is to allow for a basic implementation of responsive images, with absolutely no configuration needed by the user. So, we’ve decided to omit this feature. We will, however, do our best to allow art direction to work side by side with our plugin as we expand the API for theme developers.
Lazy-loading and image compression are two other features that we have no plans to implement, simply because they fall beyond the scope of a more or less “default” solution for responsive images. Again, we aim to make the addition of these features possible for theme developers who use our plugin via a feature-rich API.
What’s Next?
While the plugin is available for everyone to download and install, we’re actively working to make it better. So, users can expect frequent updates, resolved issues and an all-around better functioning plugin as time goes on. We’re planning to add more features, such as the sizes
attribute and hooks that allow theme developers to further customize the plugin.
Another feature we have yet to consider is ratio descriptors like 2x
and 3x
for “Retina” use cases. Better documentation and support are coming soon as well. Eventually, we’d like to see this plugin become a part of WordPress’ core, which means that it will stay minimalist, admin-less and easy to use.