Image optimisation for WordPress: WebP, AVIF and lazy loading, a practical guide
What core already does for you, what it does not, and the few lines of code that close the gap
On most small business WordPress sites we look at, images are the heaviest thing on the page by a wide margin. A homepage hero exported straight from a phone or a stock library can easily outweigh every script and stylesheet combined. The good news is that modern WordPress handles a lot of image work for you, and the remaining gaps can be closed with a little configuration rather than another plugin.
This guide covers what core already does, how to get WebP or AVIF versions of your uploads, how lazy loading really behaves, and how to treat the one image that matters most: the hero.
What WordPress core already does
It is worth knowing the defaults before adding anything:
- Responsive sizes. Every upload is resized into several sub sizes, and content images get
srcsetandsizesattributes so the browser can pick a sensible file for the screen. - A ceiling on huge uploads. Since version 5.3, uploads wider or taller than 2560 pixels are scaled down, with the original kept on disk.
- Width and height attributes. Content images are output with dimensions, which lets the browser reserve space and avoids layout shift.
- Native lazy loading. Since 5.5, images get
loading="lazy". Later releases stopped applying it to the first images on the page, and since 6.3 WordPress addsfetchpriority="high"to the image it judges most likely to be the largest contentful paint. - Modern formats. WebP uploads are supported from 5.8 and AVIF from 6.5, provided the server's image library can handle them.
That last condition catches people out. Check Tools > Site Health > Info > Media Handling to see whether your server's Imagick or GD build lists WebP and AVIF. If AVIF is missing there, no amount of plugin configuration will produce AVIF files on that server.
Generating WebP or AVIF from JPEG uploads
Clients and editors will keep uploading JPEGs, and that is fine. Since 5.8 there is a filter that tells WordPress which format to use when it creates the sub sizes. Put this in a small must use plugin (for example wp-content/mu-plugins/image-formats.php) so a theme change does not lose it:
<?php
/**
* Output WebP sub sizes for JPEG uploads, or AVIF where the server supports it.
*/
add_filter( 'image_editor_output_format', function ( $formats ) {
$target = wp_image_editor_supports( array( 'mime_type' => 'image/avif' ) )
? 'image/avif'
: 'image/webp';
$formats['image/jpeg'] = $target;
return $formats;
} );
New uploads will now produce modern sub sizes while the original JPEG stays untouched. To convert the existing library, WP-CLI can regenerate the missing files:
wp media regenerate --only-missing --yes
Run it on a staging copy first and take a backup. On a large library it is worth running out of hours, because it is heavy on the server.
A word on quality: both formats can look poor if compressed too hard. WebP around 75 to 82 and AVIF around 50 to 60 is a reasonable starting point for photographs, but check real images on a real phone. Logos and screenshots with flat colour often look better as PNG or SVG.
Lazy loading: the mistake that slows the page down
Lazy loading is excellent for images further down the page and harmful for the one image visitors see first. If the hero is lazy loaded, the browser waits until layout is worked out before even requesting it, which delays the largest contentful paint.
WordPress core now avoids this for content images, but heroes are often printed by a theme template, a page builder or a slider, and those can bypass core's logic. View the page source and look at your hero. If it has loading="lazy", remove it there. Also avoid JavaScript lazy loading libraries that swap data-src into src; native lazy loading does the same job without the extra script.
Treat the hero as a special case
For a full width hero in a custom template, a picture element gives you AVIF, a WebP fallback and a JPEG for anything older, with explicit dimensions and a high fetch priority:
<picture>
<source type="image/avif"
srcset="/img/hero-800.avif 800w, /img/hero-1600.avif 1600w"
sizes="100vw">
<source type="image/webp"
srcset="/img/hero-800.webp 800w, /img/hero-1600.webp 1600w"
sizes="100vw">
<img src="/img/hero-1600.jpg" width="1600" height="900"
alt="Kitchen fitter measuring a new worktop"
fetchpriority="high" decoding="async">
</picture>
If you are creating these files by hand, the command line tools are quick:
cwebp -q 80 hero-1600.jpg -o hero-1600.webp
avifenc -q 55 hero-1600.jpg hero-1600.avif
Keep the hero to the size it is actually displayed at. A 4000 pixel image squeezed into a 1600 pixel slot is wasted bandwidth however good the format.
Make sure the server serves them properly
Older Apache setups do not always know the AVIF type, and images should be cached by browsers for a long time. In .htaccess:
<IfModule mod_mime.c>
AddType image/avif .avif
AddType image/webp .webp
</IfModule>
<IfModule mod_expires.c>
ExpiresActive On
ExpiresByType image/avif "access plus 1 year"
ExpiresByType image/webp "access plus 1 year"
ExpiresByType image/jpeg "access plus 1 year"
</IfModule>
If you replace an image but keep the same file name, those long cache times mean returning visitors may see the old one, so upload under a new name instead.
A quick checklist
- Confirm WebP and AVIF support in Site Health.
- Add the output format filter and regenerate missing sizes on staging.
- Check the hero is not lazy loaded and has
fetchpriority="high". - Make sure every image has width and height attributes.
- Resize oversized originals before upload, not after.
- Run Lighthouse on mobile before and after, and compare the largest contentful paint.
None of this is glamorous, but on a typical brochure site it is often the single biggest speed win available. If you would like a second pair of eyes on a slow site, this is part of the WordPress development and performance work we do in Birmingham.
Rocky V, Head of Operations at DigitalCave
About the author
- DigitalCave is a web design and digital marketing agency in the Jewellery Quarter, Birmingham, working with businesses across the West Midlands and the UK since 2013. We build WordPress and Shopify sites and run SEO, local SEO, Google Ads and Meta ads. This blog shares practical technical notes from client work. Website: https://digitalcave.uk
Comments
Join the discussionNo comments yet. Be the first to comment.
