Retina in RWP 1.7

Responsive images: plug and play.
That’s my newest slogan for Responsify WP which got updated to version 1.7 the other day. It’s a really good update which contains multiple great new features. The biggest and most requested one was the support for high resolution, or retina, images.

RWP_banner

In CSS, you can specify media queries for screens with higher pixel ratio. A common use case is that you replaces the regular sprite with one that is twice as large, thus making icons look crisp and sharp on devices like the iPhone or iPad.

@media (min-device-pixel-ratio: 2) {
    .icon {
        background: url('sprite@2x.png');
    }
}

This can now be achieved using regular HTML as well thanks to the srcset attribute.

<img src="photo.png" srcset="photo@2x.png 2x">  

<picture>
   <source media="(min-width: 800px)" srcset="head.jpg, head-2x.jpg 2x">
   <source media="(min-width: 450px)" srcset="head-small.jpg, head-small-2x.jpg 2x">
   <img src="head-fb.jpg" srcset="head-fb-2x.jpg 2x">
</picture>

(Thanks for the example, Google!)
RWP needed to have this feature to, but how could I approach the implementation of this in WordPress? Where would these 2x images come from?
I was sure of one thing, I didn’t want RWP to handle the creation of these retina images. It just didn’t feel like that was inside the scope of the responsibilities of RWP.

Depend on other plugins?

One possible approach to solve this was to depend on other plugins that could create retina images. I looked into a number of them and found WP Retina 2x to be the best one. Unfortunately, I realised that it wasn’t going to work out for a number of reasons.

WP Retina 2x generates new versions of an image that is twice the size of each specified image size. If the thumbnail is set to be 150x150px, a version called 150×150@2x will be generated which actually is 300x300px.
The problem for me was that these versions is not added to the database, so the only way to know if a retina version existed was to check the file system.
For maximal compatibility with RWP, the images needed to be generated by WordPress like the usual thumbnail, medium and large versions. Even though it’s not a plug and play solution, I decided that the best solution would be to ask the user to add custom image sizes.

<?php
add_image_size( 'medium@2x', 600, 600 );
add_image_size( 'large@2x', 2048, 2048 );
?>

RWP looks for image sizes with the @[value]x suffix in the name. The good thing with this approach is that the users has full control and can create images for whatever pixel density they want. This makes a very powerful solution for responsive retina images.

<?php
add_image_size( 'medium@1.5x', XXX, XXX );
add_image_size( 'medium@3x', XXX, XXX );
add_image_size( 'medium@5x', XXX, XXX );
?>

Featured images

Since the very first version of RWP, it has been applied to the the_content filter and done it’s magic on images. The purpose of the Picture::create() function has been to allow the user to create responsive images in other parts of the template.
For example, this code can be used to make featured images responsive:

<?php
$thumbnail_id = get_post_thumbnail_id();
echo Picture::create( 'element', $thumbnail_id );
?>

I have however received feature request about making RWP work on featured images out of the box. So as of version 1.7, RWP does that.

Filters

Another new feature in 1.7 is that the user can add even more filters that RWP should search for images to make responsive in. This can be done with the rwp_add_filters filter. (Yeah, it’s hard to talk about a filter that handles filters.)

<?php
function add_filters( $filters ) {
    $filters[] = 'my_custom_filter';
    return $filters; // Equals array( 'the_content', 'post_thumbnail_html', 'my_custom_filter' )
}
add_filter( 'rwp_add_filters', 'add_filters' ); 
?>

Attributes

The final new feature that I want to tell you about is the Picture::create( 'attributes' ) function. This returns an array of the generated attributes for a specified element.

<?php
$img_attributes = Picture::create( 'attributes', $attachment_id, array( 'element' => 'img' );
/* $img_attributes equals:
Array(
    'srcset' => 'thumbnail.jpg 150w, medium.jpg 300w, large.jpg 1024w'
    'sizes' => '(min-width: 300px) 1024px, (min-width: 150px) 300px, 150px'
)
*/
?>

This can be useful if the user wants to modify the attributes or insert the image with Javascript later.

<?php
echo '<img srcset="'.$img_attributes['srcset'].'" sizes="'.$img_attributes['sizes'].'">';
?>