Speed Up Your Genesis Theme by Reducing Database Queries

WordPress ships with a bunch of nifty methods to improve performance and knowing when to use one of them could cut the number of database queries on your site by over 60%.

Post Thumbnail Caching

It has to do with the way post thumbnails are displayed in a loop.

By default, whenever get_the_post_thumbnail() is called in the main loop for the first time, WordPress looks up data for all thumbnails that are likely to appear and caches them. Otherwise, the thumbnail data for each post needs to be fetched on each iteration of the loop at a cost of two additional queries per thumbnail: One for the attachment and one for the attachment’s meta data.

So what exactly is the method? It’s a simple function, aptly named update_post_thumbnail_cache().

How It Works

When a new WP_Query is run, all of the selected posts and their metadata are pulled from the database and cached so that any time one of the posts or its metadata is referenced during the same request, it can be read from memory rather than hitting the database again.

Instead of fetching thumbnail info from the database each time it’s needed, WordPress can fetch data for all thumbnails at once and cache them the same way posts are cached, which is what happens when update_post_thumbnail_cache() is called.

It accepts a single, optional argument, which is the WP_Query object for the loop that should be cached. Since main loops are already cached, you would typically only need to use it with custom loops:

$custom_loop = new WP_Query( array(
    'post_type' => 'post',
) );

update_post_thumbnail_cache( $custom_loop );

What’s the Deal with Genesis?

Genesis has its own API method called genesis_get_image() to display post thumbnails and it doesn’t reference get_the_post_thumbnail(), so it doesn’t take advantage of WordPress’ default caching. The Genesis method does have other useful features, like providing a couple of fallback alternatives if a featured image hasn’t been set, but that’s really more of an edge case and there’s no reason it shouldn’t take advantage of the performance benefits provided by update_post_thumbnail_cache().

To do so, here’s a filter that will enable the caching, as well as add a slight enhancement to WP_Query. Activate the code below as a plugin or prefix it and include it directly in your theme:

<?php
/**
* Plugin Name: Cache Post Thumbnails
* Description: Prime the post thumbnails cache for individual loops.
* Version: 1.0.0
* Author: Brady Vercher
* Author URI: http://www.blazersix.com/
* License: GPL-2.0+
* License URI: http://www.gnu.org/licenses/gpl-2.0.html
*/
/**
* Prime post thumbnail cache.
*
* Automatically primes the cache for the main loop on the front page and
* archives. The cache can be activated for additional queries using the
* 'blazersix_cache_post_thumbnails' filter.
*
* Custom queries can also pass a 'blazersix_cache_post_thumbnails' flag via the
* query args to prime the cache.
*
* @since 1.0.0
*
* @param array $posts List of posts in the query.
* @param WP_Query $wp_query WP Query object.
* @return array
*/
function blazersix_prime_post_thumbnails_cache( $posts, $wp_query ) {
// Prime the cache for the main front page and archive loops by default.
$is_main_archive_loop = $wp_query->is_main_query() && ! is_singular();
$do_prime_cache = apply_filters( 'blazersix_cache_post_thumbnails', $is_main_archive_loop );
if ( ! $do_prime_cache && ! $wp_query->get( 'blazersix_cache_post_thumbnails' ) ) {
return $posts;
}
update_post_thumbnail_cache( $wp_query );
return $posts;
}
add_action( 'the_posts', 'blazersix_prime_post_thumbnails_cache', 10, 2 );

That snippet will automatically cache post thumbnails in main loops that aren’t for singular posts. It also allows you to cache custom loops by passing an additional argument to WP_Query:

$custom_loop = new WP_Query( array(
    'post_type' => 'post',
    'blazersix_update_post_thumbnail_cache' => true,
) );

Checking Your Site

If you want to see how many queries each request on your site is generating, go download the excellent Query Monitor plugin by John Blackbourn.

  1. Nitin

    Hi Brady,

    In Genesis theme – Modern Portfolio that uses featured widget amplified plugin on homepage, there isn’t any significant drop in the number of queries. I can tell that this plugin is the culprit, but could you suggest a workaround

    The site in question is blog.ficci.com

    • Brady Vercher
      https://www.blazersix.com

      From a glance, it doesn’t look like your site can take advantage of this approach since it isn’t using a standard loop. There are other ways to improve performance that will have a bigger impact, so don’t spend too much time focused on something like this.

  2. Tom
    GenesisThemes.ca

    Thanks, Brady. Your pointer to the Query Monitor plugin highlights some bottlenecks for my image-heavy archive pages. I’m using Genesis with a custom post type. Any pointers?

    • Brady Vercher
      https://www.blazersix.com

      It really depends on how your site is built. A static page cache is probably going to provide the most benefit if you’re tuning performance. The method here is really more of a micro-tweak in the grand scheme of things.

  3. kg69design

    Thanks!!! That was really helpful! I was worried about the number of database queries in custom loop with get_the_post_thumbnail() and it seems that here it is a solution.

  4. Damian
    https://timersys.com

    Nice nice nice! I was struggling on how to optimize a page with 120 thumbnails on a custom query and I was about to manually write the query instead of using Wp_Query but with this function I got reduced 200 db queries :)