Updated date:

Native Lazy Loading for Wordpress Images

Author:

What is Native Lazy-Loading?

When a browser opens a webpage, it normally loads every image on it—even ones far below the visible area, or viewport. Some visitors might not ever scroll further down the page, which means the bandwidth spent loading those unseen images is wasted.

In an ongoing quest for faster internet, developers came up with clever ways to defer the loading of images outside the viewport until the user scrolls near them. All of these solutions required JavaScript, though, which adds its own overhead and breaks images altogether for those who browse with JavaScript disabled.

The situation changed with the arrival of Chrome 76. From that version onward, Chrome and Chromium-derived browsers support native lazy-loading. All you have to do is add a single attribute to your image tags:

<img src="cutecat.jpg" loading="lazy" />

It's that simple. And if a different browser doesn't support the new attribute yet, the images will load normally, no harm done.

Now I'll tell you how to add these attributes to your images in Wordpress automatically (for the most part).

March 2020 Update (Read First!)

There have been exciting developments since this article was written. Native image lazy-loading has become a part of the official HTML spec. Browser support has improved. And perhaps most importantly, native lazy-loading is to be merged into WordPress core as of version 5.5.

In practical terms, this means that no extra effort your part will be necessary after WP version 5.5 arrives in August 2020. Until then, you can test native lazy-loading by using the modifications described below. Just keep in mind that hey will become irrelevant in several months (and hooray for that).

Native Lazyload Plugin

chromes-native-lazy-loading-for-wordpress-images

First off, Google's own Native Lazyload plugin can do all the work for you. At the time of writing, it's rife with one-star reviews claiming it broke their site, but I'm sure it will get fixed eventually. Even then, I won't use it because I'm a curmudgeon and avoid installing plugins as much as possible, but if you're looking for the fastest and easiest solution, this is it.

1. Add Lazy Loading Attribute to Featured Images and Attachments

Adding the loading="lazy" attribute to featured images (previously called post thumbnails), galleries, and images on attachment pages is easy by using the wp_get_attachment_image_attributes hook. Simply copy and paste the code below into your theme's functions.php file:

add_filter( 'wp_get_attachment_image_attributes', 'add_lazy_load', 10, 3 );
function add_lazy_load( $attr, $attachment, $size ) {
    if ( ! array_key_exists( 'loading', $attr ) ) {
        $attr['loading'] = 'lazy';
    }
    return $attr;
}

Kudos to akkis on Wordpress Code Reference for this snippet.

You can verify that this works by inspecting the source code of a featured image or an attachment page on your site:

chromes-native-lazy-loading-for-wordpress-images

2. Add Lazy Loading Attribute to New Images Inside Posts

The code above doesn't affect single images added via post editor. For that I've used the image_send_to_editor hook as shown below. Add it to functions.php like before.

add_filter( 'image_send_to_editor', 'lazyloading', 10, 8 );
function lazyloading( $html ) {
    $html = str_replace( ' />', ' loading="lazy" />', $html );
    return $html;
}

What this does is simply tack on the loading="lazy" attribute whenever inserting an image into a post via "Add media". When you switch to "Text" in Classic Editor or click the three dots and then "Edit as HTML" in Gutenberg, you'll see something along these lines:

chromes-native-lazy-loading-for-wordpress-images

As you might've guessed, this only affects newly inserted images. Galleries and post thumbnails aside, existing images in older posts won't receive the lazy loading treatment. There's a good reason for this: Images inserted into posts are essentially a part of the post text and can't be filtered directly.

You can, of course, use a function that searches the contents of an entire post and tacks on the lazy loading attribute to each <img> tag it finds, but that strikes me as inefficient. The process would have to be repeated each time a visitor views a post, putting undue load on your server and slowing your site, which is the opposite of what we're trying to do. This approach is much easier, however, so I've added such a function further below in case you'd like to use it.

3. Lazy Loading for Existing Images in Posts

To deal with existing images in older Wordpress posts, I can't really think of anything smarter than doing a simple search & replace. (If you have a better idea, please share it in the comments!) This might not seem very elegant, and it hardcodes the loading="lazy" attribute into posts, but it only has to be done once.

To this end, I've used a plugin called Better Search Replace on my wp_posts table as follows:

Do be careful and make a database backup beforehand, because it can easily break things.

Do be careful and make a database backup beforehand, because it can easily break things.

If you're going to do this at all, it's best to do it before you modify the editor as described in Step 2, or you'll get image tags with duplicating attributes. Again, only do this once.

And if this attribute never gains mainstream support, you can always remove it from your posts by performing the search & replace in reverse.

Easier Alternative for All Images in Posts

But let's say you use a good caching plugin so the cost of searching through the post text with each page load doesn't apply. In that case you can use the_content filter to search every post for image tags and tack on the lazy loading attribute on the fly. Simply add the following function to your functions.php file:

add_filter('the_content', 'lazy_load_images');
function lazy_load_images($content) {
	if ( is_single() && in_the_loop() && is_main_query() ) {
		$content = str_replace('/>', 'loading="lazy" />', $content);
	}
	return $content;
}

If you use this approach, you can skip steps 2 & 3 because this function will automatically add the loading="lazy" attribute to every image on every post.

4. Lazy Loading for Commenter Avatars

Comments are usually located at the bottom of the page, so user avatars are a good target for lazy loading. You could use this filter in your functions.php:

add_filter( 'get_avatar' , 'lazyavatar' , 1 , 1 );
function lazyavatar( $avatar ) {
	$avatar = str_replace('<img','<img loading="lazy"',$avatar);
    return $avatar;
}

Or, if your theme uses a custom comment callback, you might find the get_avatar() function and add loading="lazy" to it through the extra_attr parameter.

If you're using a more modern comment system like Disqus, this isn't necessary.

5. Lazy Loading Youtube Videos

One thing I haven't mentioned so far is that lazy loading can also be applied to iframes. When you paste a link to a video on Youtube (or other supported site), Wordpress automatically turns it into an iframe to embed it on your post. To make it load lazily, we can use the embed_oembed_html filter as follows:

function lazyoutube($html) {
	$html = str_replace( '<iframe', '<iframe loading="lazy"', $html );
    $html = '<div class="video-container">'.$html.'</div>';
    return $html;
}
add_filter( 'embed_oembed_html', 'lazyoutube', 10, 1 );

Verifying the Improvement

There are several ways to test if lazy loading works. The easiest is to open your website in the latest version of Chrome, fire up the Developer tools (Ctrl + Shift + I), and switch to the Network tab. Navigate to a long page with a lot of images and scroll down. You should see that the images at the far bottom won't load until you scroll lower.

Don't be alarmed if the images load immediately! The threshold at which Chrome will load an image depends on multiple factors, including connection speed. Anecdotally, the distance also appears significantly higher than JavaScript-based solutions, so you might want to find a really long page for testing.

An alternative way is to launch an Audit via the same developer tools, or use the web-based PageSpeed Insights test. Look for the "Defer offscreen images" message, which will show up in the "Opportunities" section if not yet implemented, and in the "Passed audits" section if lazy loading is working.

A green "Defer offscreen images" result in Google's PageSpeed Insights is what you want to see.

A green "Defer offscreen images" result in Google's PageSpeed Insights is what you want to see.