Documentation for Cache Control plugin for WordPress

Introduction

The Cache-Control plugin for WordPress lets you set the cache freshness duration for dynamically generated pages on a WordPress website through the use of the Cache-Control HTTP response header. The plugin isn’t a cache plugin in itself, but can be used to control the behavior of standard HTTP caches such as browser caches, reverse proxies, content delivery networks (CDN), and web accelerators.

You set the cache freshness as the most number of seconds from the page was initially loaded that it’s acceptable for website visitors to be served a cached version of a page. The desired freshness duration will vary from page to page within a given website, but also from website to website. A longer freshness duration can save you bandwidth costs and money, and it can also help speed up your website. However, you must balance that between how frequently content is updated and how acceptable it is for visitors to see cached and potentially old pages.

Additionally, you can set error and cache-updating behavior in modern caches by configuring stale-cache handling.


Some familiarity with caching in HTTP will be required. Section 5.2 in or the whole of RFC 7234 can get you up to date. For stale cache handling specifically, you should alos refer to RFC 5861.

Configuration

The plugin can be configured for your WordPress administration area. Go to Settings: Cache-Control to see the options page.

All options within the plugin is set in seconds. Any option set to 0 seconds will omit the given omitted the given field from the Cache-Control header. Setting all options for a given type of pages to 0 seconds will make it uncacheable. Uncacheable pages

Each type of page must be configured separately. You can override the plugin and do entirely custom handling for specific request or type of pages using your own criteria using the cache_control_cachedirective filter hook. See the HACKING file in the plugin installation directory for details.

Configuration fields

The following fields can be configured within the plugin administration page. Each field matches the coresponding Cache-Control HTTP header as defined in RFC 7234 Section 5.2.

max-age (private cache)

Sets the number of seconds a page can be cached before it should be refreshed. This is the simplest field required for caching to work in most clients, and the only field which is set by default.

s-maxage (shared cache)

Sets the number of seconds a shared cache can store a page in its cache. A shared cache is a cache designed to be used by more than one device or visitor, such as a reverse proxies, content delivery network (CDN), or a web accelerator.

This option allow you to instruct intermediary caches to refresh cached resources more or less often than a private cache. In many situations, you may want a shared cache to update more often than a private cache.

If no shared cache duration is set, then the configured private cache duration is inherited for use by shared caches.

stale-if-error

Sets an additional number of seconds after a cached page has expired in the cache which stale copy of a page can be returned from the cache if your webserver returns an HTTP error. For many websites, it’s undesirable to return an error message when an older cached copy of a page can be served instead.

This can be set to hours or even days to help ensure your website remains available. This option is typically only desired when using a reverse proxy or a content distribution network.

You must also specify a private or shared cache duration to use this option.

stale-while-revalidate

Like the stale-if-error option, but doesn’t depend on the original webserver returning an HTTP error code. This option allows shared caches to keep serving cached copies to visitors for a number of seconds while updating the cached copy in the background. This can greatly improved page loading times for visitors won’t have to wait for pages to be updated.

This should be set to minutes, hours, or even days depending on how fresh you need your content to be. Note that you can likely benefit from decreasing the maxage option in favor of a longer stale-while-revalidate duration when using a reverse proxy or content distribution network. You should test and verify that stale-cache handling works on your infrastructure before deploying it.

You must also specify a private or shared cache duration to use this option. This option can be used in addition to stale-if-error.

Static resources

This plugin only works with dynamic pages generated by WordPress itself. You should also set Cache-Control headers manually in your webserver configuration for images, scripts, stylesheets, redirects, and other static resources. Please refer to the documentation for your webserver for details.

Extended feature set

In addition to controlling standard HTTP caching behavior, the Cache Control plugin for WordPress has a number of additional advanced features.

Scheduled posts

You can safely set long private and shared cache freshness durations as dynamic pages (indexes, feeds, taxonemies, searches, others) will dynamically reduce their max caching duration to a few seconds after a scheduled post is published. After a scheduled post has been published, affected pages return to normal caching duration. Every dynamic page will not expire at the exact same time by introducing some random number of seconds delay to mitigate “the thundering herd” problem.

Note that the stale-cache handling options are unaffected by scheduled posts. Intermediary caches will, however, be instructed to refresh their copies earlier than normal as pages will expire quicker.

Increasing pagination factor

When this option is set, older pages in to paged indexes will be cached for longer than newer pages (as determined by page number). The configured pagination factor is added to the main maxage and s-maxage options. This allows less popular archives to be served as stale for longer.

E.g. the 8th tag archive page with a pagination factor of 80 will have a max-age of max-age + ( 80 * 8).

Set this to 0 seconds to disables this feature. Index sorting order doesn’t affect this option.

Old age multiplier

When this option is set, the max-age and s-maxage values will be multiplied by the number of years since the last edit or comment (Last Modified time). The factor uses a monthly precision. This allows posts that were published a long time ago and that haven’t been changed for a long time to be cached longer than newer posts.

E.g. a post that hasn’t been modified or had a new comment in 3 months (¼ of a year) will be cached for max-age * 1.25.

This feature works better with the Mintor Edits plugin installed. This plugin prevents tiny and unimportant edits from changing the Last Modified time of a post.

Delta feed updates

You can improve reduce bandwidth usage of web syndication feeds (“RSS”) by offering feed delta updates. The Feed Delta Updates plugin for WordPress enables this feature on your website, and works great with the Cache-Control plugin for WordPress.

Supports WooCommerce

After you install the popular WooCommerce plugin for WordPress, additional options will appear in the administration interface for configuring WooCommerce specific page types.

Security considerations

By default, the plugin will mark any of the of the following pages uncacheable:

  • The WordPress login page (wp-login)
  • Any page from the WordPress administration area (wp-admin)
  • Pages loaded by a user who is logged in
  • Post previews
  • Unknown or custom page types (see the plugin administration page)

These defaults should prevent information leakage about about administrative or user accounts on a default WordPress installation that hasn’t been modified by plugins or the user. It’s your responsibility to verify that you’ve implemented caching correctly and that you don’t cache pages you don’t want to be saved.


By default, WordPress may modify and potentially leak information about people who leave comments on your WordPress website through its poorly conceived auto-fill feature. You can mitigate this by disabling the commenter cookie in WordPress. You can still keep this functionality without the cookie by moving the data storing from cookies and into localStorage in the visitors browser.