Query Caching (and a little extra)

By default, WordPress does not cache WP_Query queries.  Doing so can greatly improve performance.  The way I do this is via the Advanced Post Cache plugin:

By running this plugin (hopefully as an mu-plugin) with a persistent object cache, WP_Query calls, along with get_post() calls (only if suppress_filters is false) will be cached.

Bonus!

Now that we’re caching queries, here’s how I do a little extra caching to squeeze out a tiny bit more performance:

<?php
// By default Jetpack does not cache responses from Instagram oembeds.
add_filter( 'instagram_cache_oembed_api_response_body', '__return_true' );

// Cache WP Dashboard Recent Posts Query
add_filter( 'dashboard_recent_posts_query_args', 'cache_dashboard_recent_posts_query_args', 10, 1 );
function cache_dashboard_recent_posts_query_args( $query_args ) {
	$query_args['cache_results'] = true;
	$query_args['suppress_filters'] = false;
	return $query_args;
}

// Cache WP Dashboard Recent Drafts Query
add_filter( 'dashboard_recent_drafts_query_args', 'cache_dashboard_recent_drafts_query_args', 10, 1 );
function cache_dashboard_recent_drafts_query_args( $query_args ) {
	$query_args['suppress_filters'] = false;
	return $query_args;
}

// Cache comment counts, https://github.com/Automattic/vip-code-performance/blob/master/core-fix-comment-counts-caching.php
add_filter( 'wp_count_comments', 'wpcom_vip_cache_full_comment_counts', 10, 2 );
function wpcom_vip_cache_full_comment_counts( $counts = false , $post_id = 0 ){
	//We are only caching the global comment counts for now since those are often in the millions while the per page one is usually more reasonable.
	if ( 0 !== $post_id ) {
		return $counts;
	}

	$cache_key = "vip-comments-{$post_id}";
	$stats_object = wp_cache_get( $cache_key );

	//retrieve comments in the same way wp_count_comments() does
	if ( false === $stats_object ) {
		$stats = get_comment_count( $post_id );
		$stats['moderated'] = $stats['awaiting_moderation'];
		unset( $stats['awaiting_moderation'] );
		$stats_object = (object) $stats;

		wp_cache_set( $cache_key, $stats_object, 'default', 30 * MINUTE_IN_SECONDS );
	}

	return $stats_object;
}

// Cache monthly media array.
add_filter( 'media_library_months_with_files', 'wpcom_vip_media_library_months_with_files' );
function wpcom_vip_media_library_months_with_files() {
	$months = wp_cache_get( 'media_library_months_with_files', 'extra-caching' );

	if ( false === $months ) {
		global $wpdb;
		$months = $wpdb->get_results( $wpdb->prepare( "
			SELECT DISTINCT YEAR( post_date ) AS year, MONTH( post_date ) AS month
			FROM $wpdb->posts
			WHERE post_type = %s
			ORDER BY post_date DESC
			", 'attachment' )
		);
		wp_cache_set( 'media_library_months_with_files', $months, 'extra-caching' );
	}

	return $months;
}

add_action( 'add_attachment', 'media_library_months_with_files_bust_cache' );
function media_library_months_with_files_bust_cache( $post_id ) {
	if ( defined( 'WP_IMPORTING' ) && WP_IMPORTING ) {
		return;
	}

	// What month/year is the most recent attachment?
	global $wpdb;
	$months = $wpdb->get_results( $wpdb->prepare( "
			SELECT DISTINCT YEAR( post_date ) AS year, MONTH( post_date ) AS month
			FROM $wpdb->posts
			WHERE post_type = %s
			ORDER BY post_date DESC
			LIMIT 1
		", 'attachment' )
	);

	// Simplify by assigning the object to $months
	$months = array_shift( array_values( $months ) );

	// Compare the dates of the new, and most recent, attachment
	if (
		! $months->year == get_the_time( 'Y', $post_id ) &&
		! $months->month == get_the_time( 'm', $post_id )
	) {
		// the new attachment is not in the same month/year as the
		// most recent attachment, so we need to refresh the transient
		wp_cache_delete( 'media_library_months_with_files', 'extra-caching' );
	}
}

Leave a Reply