Controlling VIP Go Page Cache

VIP Go platform specific

This document is for sites running on VIP Go.

Learn more

Overview #

The VIP Go page cache is one of the caching layers of VIP Go. The page cache is served from our global network of edge locations (usually from memory).
By default, your VIP Go page cache behaves as follows:

  • Logged in users bypass the VIP Go page cache entirely
  • No-cache headers are respected, but should only be used after consulting VIP, use nocache_headers()
  • Responses with an HTTP Status Code of 200, including WordPress posts, pages, archives, the homepage, etc, are cached for 30 minutes; these responses are sent with a response header of cache-control: max-age=300, must-revalidate for browser cache control purposes
  • Enqueued JS and CSS is concatenated by VIP Go and cached for 15 days (this cache is busted when resources change). Note: The HTML is cached for 30 minutes, so the references to the new JS/CSS files could be up to 30 minutes out of date.
  • Other responses are cached for 1 minute or less
  • Redirects with a 302 HTTP Status are cached for 1 minute, redirects with a 301 HTTP Status are cached for 30 minutes.
  • All WordPress REST API responses are cached for 1 minutes (more about the WordPress REST API)

Using the developer tools in your browser you can likely see some detail about your cache behaviour in the following HTTP response headers:

  • x-cache shows you whether the response was from cache (hit), not from cache (miss), or grace (see below)
  • cache-control shows the max-age of the cache for this content
  • age shows the age of any response which hit the cache

The page cache considers the whole URL, including GET parameters; e.g. ?a=1&b=1 is different from ?b=1&a=1 and both are cached separately. When purging a URL, all variants of the GET parameters are purged at the same time. This means that a post with slug hello-world will have all variants ( eg.: /hello-world?a=1&b=1 as well as /hello-world?b=1&a=1 ) purged along with the main post.

When a page or a post of any kind (built-in post or custom post type) is published, the following caches are cleared by default:

  • The single post/page URL
  • The comments feed URL for that post/page
  • The term archive URL for all terms associated with the post
  • The term archive feed URL for all terms associated with the post
  • The homepage

When a term is created, updated, or deleted, the following caches are cleared by default:

  • The term archive URL for all terms associated with the post
  • The term archive feed URL for all terms associated with the post

Cache control can be written into your theme, plugin, or client MU plugin. We provide an API to filter the URLs being queued for clearance, to clear the cache for a specific URL, or for a post or term, see below.

You may also be interested in geo-targetting your site content.

↑ Top ↑

Grace Responses #

Grace responses ensure that intensely trafficked resources on your site continue to be served in a timely fashion.

The grace period for a given cache object (i.e. the cached response for a particular request) is the max-age for that object, plus one minute, e.g. for a max-age of five minutes the grace period will be six minutes.

If a request is received for a cache object within the grace period but outside of the max-age of the cache, the page cache can serve a “graced” object (i.e. the previously cached response for this request) immediately, and request a freshened resource from the origin servers. Once the cache is refreshed, subsequent requests are served the fresh response until the max age is reached and the cycle starts again.

Here’s an example timeline of requests for a particular URL:

  1. request at 00:00, no cache, request is served from the origin servers and cached for subsequent resources with a max-age of 5 minutes
  2. request at 00:04, the cache is valid so the response is served from cache
  3. request at 00:05, the cache has reached max-age but is within the grace period. The response is served with a “grace” copy of the current cache, while in the background the cached copy is refreshed from the origin servers.
  4. …etc

You can identify a graced response by the X-Cache: grace HTTP response header.

One practical implication of the grace period is that your site may serve cached objects which are up to one minute over the max-age of the cache.

↑ Top ↑

Cookies #

The VIP Go caching system does not vary for most cookies (the exceptions are listed below), this means that if you personalise content based on a cookie not in this list the response will be cached and served to the next user regardless of whether they have that cookie with the same value or not.

If a request has one of the following cookies, it will PASS cache, i.e. the request and response will be considered uncacheable:

  • A WordPress comment cookie
  • A WordPress test cookie
  • A WordPress post password cookie
  • A WordPress authentication cookie
  • A Woocommerce session cookie
  • The VIP Go cache bypass cookie vip-go-cb (must have a value of exactly 1)

If you set a cookie on the server as part of a response, other than from the list above, that resource (e.g. that URL) will be marked as uncacheable for 120 seconds; for this reason, setting cookies on busy pages or endpoints can affect the stability of your application.

In most cases, the most straightforward way to handle the limitations above is to move user-level interactions client-side using javascript.

↑ Top ↑

Cache API #

Using the cache clearance API you can:

  • Set the maximum age of the cache
  • Clear the cache for a specific URL, post, or term
  • Filter the URLs being queued for clearance in a variety of ways

Set the maximum cache age #

Some sample code to control cache age for feeds is below:

/**
* Hooks the wp action to insert some cache control
* max-age headers.
*
* @param Object wp The WP object, passed by reference
* @return void
*/
function wpcom_vip_cache_maxage( $wp ) {
    if ( is_feed() ) {
        // Set the max age for feeds to 5 minutes
        if ( ! is_user_logged_in() ) {
            header( 'Cache-Control: max-age=' . (5 * 60) );         
        }
    }
}
add_action( 'wp', 'wpcom_vip_cache_maxage' );

Please do not set cache age lower than 1 minute for heavily trafficked resource types. During code review we will check anywhere you are setting the maximum cache age and discuss the options with you.

Note the is_user_logged_in() check, which ensures the cache TTL headers are not set for logged in users, as this would trigger browser caching for them.

↑ Top ↑

Clearing caches for post, term, or a specific URL #

We have three functions you can call to clear particular caches:

wpcom_vip_purge_edge_cache_for_url( $url ) – purge the cache for one specific URL

wpcom_vip_purge_edge_cache_for_post( $post ) – purge the caches related to a post (see above, for which caches are associated with a post)

wpcom_vip_purge_edge_cache_for_term( $term ) – purge the caches related to a term (see above, for which caches are associated with a term)

↑ Top ↑

Setting individual users or requests to bypass cache #

This technique allows chosen users to bypass cache even if they are not logged in, meaning that their requests will always processed by the origin servers, you can personalise the response, and the response will never be cached and served to other users. This might fit the use case for a paywall, or as part of some A/B testing functionality.

Requests with the vip-go-cb cookie set with a value of 1 (it must be a value of 1) will always PASS the VIP Go cache, meaning that these requests will never be served a cached response and the response to these requests will never be cached to be served to others.

Logged in WordPress users accessing a VIP Go application will always PASS the cache, so setting this cookie for logged in WordPress users is not necessary. If you have users logging in via some other mechanism, you can set the vip-go-cb cookie in addition to any other cookies or local storage data for some third party login system and be sure that these users will not have responses cached or see cached responses.

↑ Top ↑

Filter the URLs cleared when a post is changed #

Whenever a post is published, a published post is changed, or a post is un-published, a set of URLs is assembled to be purged. By default we include most URLs you would want to clear, see the list above in “Overview”, and you can add to or remove from these URLs using the wpcom_vip_cache_purge_{$post->post_type}_post_urls filter.

Example code below:

/**
 * Hooks the wpcom_vip_cache_purge_post_post_urls filter to 
 * also clear a custom JSON endpoint for the post URL.
 * 
 * This targets posts of post type "post" only.
 *
 * @param array urls An array of URLs to be purged
 * @param int post_id The ID of the post for which we're purging URLs
 * @return array An array of URLs to be purged
 */
function my_cache_purge_post_urls( $urls, $post_id ) {
    $post = get_post( $post_id );
    if ( empty( $post ) ) {
        return $urls;
    }
    // Also purge the JSON format for the posts
    $urls[] = get_permalink( $post_id ) . '/json/';
    return $urls;
}
add_filter( 'wpcom_vip_cache_purge_post_post_urls', 'my_cache_purge_post_urls', 10, 2 );

↑ Top ↑

Filter the URLs cleared when a term is changed #

Whenever a term is created, changed, or deleted, a set of URLs is assembled to be purged. By default we include most URLs you would want to clear, see the list above in “Overview”, and you can add to or remove from these URLs using the wpcom_vip_cache_purge_{$taxonomy_name}_term_urls filter.

Example code below:

/**
 * Hooks the wpcom_vip_cache_purge_category_term_urls filter to 
 * also clear a custom JSON endpoint for the term archive
 *
 * @param array urls An array of URLs to be purged
 * @param int term_id The ID of the term for which we're purging URLs
 * @return array An array of URLs to be purged
 */
function my_cache_purge_term_urls( $urls, $term_id ) {
    $term = get_term( $term_id );
    if ( is_wp_error( $term ) || empty( $term ) ) {
        return false;
    }
    $term_link = get_term_link( $term, $taxonomy_name );
    if ( is_wp_error( $term_link ) ) {
        return false;
    }
    if ( $term_link && is_string( $term_link ) ) {
        $this->purge_urls[] = $term_link . '/json/';
    }
    return $urls;
}
add_filter( 'wpcom_vip_cache_purge_category_term_urls', 'my_cache_purge_term_urls', 10, 2 );

↑ Top ↑

Varying the cached content by User Agent class #

For anonymous requests you will see an X-Mobile-Class HTTP request header (accessible via $_SERVER['HTTP_X_MOBILE_CLASS']), our page cache provides buckets for the possible values here (desktop, smart, tablet, and dumb). You can conditionally alter your output for different classes of user agent by checking this header, and have the result cached correctly.

↑ Top ↑

Geo targeting on VIP Go #

VIP Go allows you to differentiate visitors from different countries, tailoring the content you serve to your visitors on a country by country basis, while still keeping the benefits of our fast page caching. Read our separate documentation on this geo targeting on VIP Go.

Ready to get started?

Drop us a note.

No matter where you are in the planning process, we’re happy to help, and we’re actual humans here on the other side of the form. 👋 We’re here to discuss your challenges and plans, evaluate your existing resources or a potential partner, or even make some initial recommendations. And, of course, we’re here to help any time you’re in the market for some robust WordPress awesomeness.