Silly Ideas: Cache WordPress Excerpts

I recently worked on profiling a customer site for performance problems, and one of the issues that I had seen was that calls to get_the_excerpt() were running HORRIBLY slow due to filters.

I ended up writing a really hacky workaround to cache excerpts to help reduce the burden they had on the page generation time, but we ended up not using this solution. Instead we found another filter in a plugin that removed the painfully slow stuff happening in the excerpt.

So below is one potential way to cache your excerpt, but be warned it’s only barely tested:

/**
 * Checks the excerpt cache for a post and returns the cached excerpt if available.
 * If the post is password protected, the original post excerpt is returned.
 *
 * @param string  $post_excerpt The original post excerpt.
 * @param WP_Post $post         The post object.
 *
 * @return string The post excerpt, either from the cache or the original.
 */
function blarg_check_excerpt_cache( string $post_excerpt, WP_Post $post ): string {
	// We do not want to cache password protected posts.
	if ( post_password_required( $post ) ) {
		return $post_excerpt;
	}

	$cache_key   = $post->ID;
	$cache_group = 'blarg_cached_post_excerpt';
	$cache_data  = wp_cache_get( $cache_key, $cache_group );

	if ( false !== $cache_data ) {
		remove_all_filters( 'get_the_excerpt' );
		add_filter( 'get_the_excerpt', 'blarg_check_excerpt_cache', PHP_INT_MIN, 2 );
		$post_excerpt = $cache_data;
	} else {
		add_filter( 'get_the_excerpt', 'blarg_cache_the_excerpt', PHP_INT_MAX, 2 );
	}

	// At this point, do not modify anything and return.
	return $post_excerpt;
}
add_filter( 'get_the_excerpt', 'blarg_check_excerpt_cache', PHP_INT_MIN, 2 );

/**
 * Caches the post excerpt in the WordPress object cache.
 *
 * @param string  $post_excerpt The post excerpt to cache.
 * @param WP_Post $post         The post object.
 *
 * @return string The cached post excerpt.
 */
function blarg_cache_the_excerpt( string $post_excerpt, WP_Post $post ): string {
	$cache_key   = $post->ID;
	$cache_group = 'blarg_cached_post_excerpt';
	wp_cache_set( $cache_key, $post_excerpt, $cache_group );

	return $post_excerpt;
}

/**
 * Deletes the cached excerpt for a given post.
 *
 * @param int|WP_Post $post The post ID or WP_Post object.
 *
 * @return void
 */
function blarg_delete_the_excerpt_cache( int|WP_Post $post ): void {
	if ( $post instanceof WP_Post ) {
		$post_id = $post->ID;
	} else {
		$post_id = $post;
	}

	$cache_key   = $post_id;
	$cache_group = 'blarg_cached_post_excerpt';
	wp_cache_delete( $cache_key, $cache_group );
}
add_action( 'clean_post_cache', 'blarg_delete_the_excerpt_cache', 10, 1 );
Code language: PHP (php)

This should automatically clear out the cache any time the post is updated, but if the excerpt gets updated in any other way you may need to purge the cache in other ways.

Good luck with this monstrosity!

Other Posts Not Worth Reading

Hey, You!

Like this kind of garbage? Subscribe for more! I post like once a month or so, unless I found something interesting to write about.


Comments

Leave a Reply