Caching API on a CDN i.e CloudFlare
-
This plugin is great, we use it to power a headless NextJS WordPress site and it helped drastically reduce build times by caching repeated requests.
However, i wish there was a way to go a step further with the caching.
We have Cloudflare in-front of our WordPress site, when we cache the requests using their edge network we can get requests down from ~300ms cached to 30ms. Which in turn both helps reduce build times further and load on our origin.
The problem is cache busting here, ideally we’d have a way to hook into the
cleanup_deleted_caches
function to get all the URLs that were busted to send in a batch to Cloudflare to also bust.I’ve been playing around with a fork of the plugin to with a
wp_rest_cache/deleted_caches
action that’s fired when the cron job is run, to provide this./** * Function called by a cron job to delete flushed or deleted caches from the transients API. * * @return void */ public function cleanup_deleted_caches() { global $wpdb; /** * How many caches should be cleanup in each run? * * Allows to change the number of cleaned up caches per cron run. * * @since 2020.2.0 * * @param int $limit The maximum number of cleaned up caches per cron run. */ $limit = (int) apply_filters( 'wp_rest_cache/max_cleanup_caches', 1000 ); // EDIT: select URI & headers $sql = "SELECT <code>request_uri</code>, <code>request_headers</code>, <code>cache_key</code>, <code>deleted</code> FROM {$this->db_table_caches} WHERE <code>expiration</code> = %s AND <code>cleaned</code> = %d LIMIT %d"; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $caches = $wpdb->get_results( $wpdb->prepare( $sql, date_i18n( 'Y-m-d H:i:s', 1 ), 0, $limit ) ); // EDIT: add a hook that can be triggered when caches are cleared. do_action( 'wp_rest_cache/deleted_caches', $caches ); if ( $caches ) { foreach ( $caches as $cache ) { $this->delete_cache( $cache->cache_key, $cache->deleted ); } } $sql = "SELECT COUNT( <code>cache_id</code> ) AS <code>number_of_caches</code> FROM {$this->db_table_caches} WHERE <code>expiration</code> = %s AND <code>cleaned</code> = %d"; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $count = $wpdb->get_var( $wpdb->prepare( $sql, date_i18n( 'Y-m-d H:i:s', 1 ), 0 ) ); if ( $count > 0 ) { $this->schedule_cleanup(); } }
Using this hook, i then hit the Cloudflare API telling it to purge the URLs that were busted.
I also modified the
schedule_cleanup
function to not run on a cron job. This is primarily as i wanted the cache busting to be instant rather than after 5 minutes.I know this is there for performance, but needed a way to trigger this on all the cases that a cache entry could get deleted as outlined here https://www.ads-software.com/support/topic/hook-for-when-cache-is-cleared/
private function schedule_cleanup() { $this->cleanup_deleted_caches(); }
Would be potentially nice to have the option to trigger this instantly vs using a cron job.
Finally on top of this i needed to add some headers to tell Cloudflare to cache the resource, i could do this using the hook below.
add_filter( 'wp_rest_cache/cache_headers', function ( $headers ) { // Add cache-headers so that Cloudflare can cache the response. $headers['Cache-Control'] = 'public, max-age=300, s-maxage=300'; return $headers; }, 10000 );
However, ideally this would be added to the initial request too, the header is only returned in the second request if the request wasn’t already cached. So it requires 2 requests before Cloudflare caches it.
Not sure if you know of a better way to hook this up to a CDN infront? Thanks!
- The topic ‘Caching API on a CDN i.e CloudFlare’ is closed to new replies.