Last updated:

How to achieve blazing fast images in WordPress themes

Our clients expect their websites to be fast.

Since Google introduced the Web Vitals, we now have a metric that measures performance—at least as far as Google’s search and ad services are concerned.

Block themes include performance optimizations out of the box, like optimized CSS delivery (you can watch this video to learn more).

However, there are still areas that need a knowledgeable developer to optimize. One of these is images.

Images that are larger than they need to be are also heavier than needed.

So in this article we’ll look at:

  1. What the default WordPress font sizes are.
  2. Why they are a bad fit for modern themes.
  3. What sizes to implement, and how.
  4. How to deal with existing content.

The default image sizes

By default, WordPress includes three image sizes:

  • Thumbnail: 150 x 150 pixels
  • Medium: 300 x 300 pixels
  • Large: 1024 x 1024 pixels

These sizes have been around for years. And they are not a great fit for most themes.

Users can customize these sizes through the Settings > Media screen.

The WordPress Media Settings screen allows to set the default image sizes for thumbnail, medium, and large.

But very few do, even more knowledgeable ones. So the default sizes often stay the default. And that’s a problem.

What’s the issue with these sizes?

Common widths for content areas are anywhere between 500 to 800 pixels, depending on the typeface and font size.

In practice this means that if users want to have an image that is as wide as their text content, they choose the large size.

And thereby they are inserting images that are 200 to 500 pixels to wide.

Now the width in and of itself is not an issue. Browsers handle the resizing, so that the image doesn’t overflow.

What’s an issue though is that every added pixel means a bigger image file. That not only means wasted band width. It also means worse performance in core metrics used by search engines.

The Twenty Twenty-Four theme demo site for example gets flagged for this by Google’s Page Speed Insights:

The Twenty Twenty-Four theme does not use well-sized images. This is flagged by the Google Page Speed insight tool.

Block themes have introduced another issue, and that is wide alignments. Wide sizes are often wider than the large size.

Applying a wide size to an image will stretch it to the requested size. So if you choose a smaller image, then it will look blurry.

So often users choose the original size instead. Which depending on the source image results in huge images being used.

How to solve these issues?

As you can guess by the problems outlined, the solution is to have two image sizes by default:

  1. One that is as wide as the content size in theme.json.
  2. One that is as wide as the wide size in theme.json.

That way users can choose the correct size for the width, and you get the best possible performance and display.

Of course it’s possible for a website to have several widths. It’s not uncommon for example for sales pages to have a wider content size than blog posts.

So here you can introduce a second set of image sizes that fit with these content and wide sizes.

What I like to do is re-use the medium and large sizes that are in WordPress:

  1. It results in a less clutter compared to adding more image sizes.
  2. It’s more portable than custom image sizes.

Now I could set these sizes in the interface. But I rather prefer to filter these options in code:

<?php
function tt4_child_set_medium_image_size() {
	return 620;
}
add_filter( 'pre_option_medium_size_h', 'tt4_child_set_medium_image_size' );
add_filter( 'pre_option_medium_size_w', 'tt4_child_set_medium_image_size' );

function tt4_child_set_large_image_size() {
	return 1280;
}
add_filter( 'pre_option_large_size_h', 'tt4_child_set_large_image_size' );
add_filter( 'pre_option_large_size_w', 'tt4_child_set_large_image_size' );Code language: PHP (php)

Rather than keeping the user facing names, I change these as well to align with the new sizing. I also do remove the thumbnail size for users, which is a lot cleaner:

Removing the thumbnail size makes the font size selector a lot cleaner.

Dealing with existing content

A recurring issue with WordPress is that it stores URLs inside of the database. And images are no exception to that.

This is the markup of an image block that’s stored in the database:

<!-- wp:image {"id":123,"sizeSlug":"large","linkDestination":"none"} -->
<figure class="wp-block-image size-large">
<img src="https://example.com/wp-content/uploads/image-1024x569.png" class="wp-image-6452"/>
</figure>
<!-- /wp:image -->Code language: HTML, XML (xml)

The image tag points to the image file at the moment of insertion.

In this case when the image was added to the editor, the large image size had a maximum width of 1024 pixels.

If you change the large image size, these changes are only reflected in images inserted after the change.

So what you need to do is:

  1. Find all images in the content using this size.
  2. Update the image source attribute with the new font size.

There are two possible solutions to this:

  1. Implement a filter on the content that changes the sizes on the fly (meaning during each render).
  2. Implement a WP CLI script that searches through all posts in the database, changes the image URLs, and saves the modified posts.

In my Block Theme Academy course, you can find all the code snippets to implement performant images as described above. Along with a code snippet to do on-the-fly image URL migrations.

The role of dynamic images

Enterprise hosts like Altis Cloud, WordPress VIP or Servebolt have supported dynamic images for quite a while.

By default WordPress creates an image file for each registered size. Meaning that if you have one image and six sizes, this means seven image files.

Dealing with these images, as well as resizing them when needed, can be cumbersome.

The solution is to use dynamic images that are generated when needed. This has three advantages:

  1. You don’t have to deal with tons of image files on your server.
  2. There’s no need to generate new sizes when registering new images.
  3. Images are loaded off a dedicated CDN.

As of the time of this writing, the Jetpack Boost Image CDN (previously known as Jetpack Photon) is still available for free.

Another option is Cloudinary. This is a paid service with a free tier that should be enough for small websites.

One lost word of caution: don’t use on the fly image generation on the server.

Such scripts like TimThumb used to be all the rage back in the day. Image generation is resource intensive, so it will put a burden on your web server.

Therefore if you want to use such a feature make sure to offload it to a dedicated service.

Diving deeper

The work we have done in this article is a solid foundation for performant images.

If you’re looking to optimize images further, I recommend learning more about responsive images in WordPress. With this knowledge, you can also optimize image delivery on mobile devices for best results.

Fränk Klein Avatar