40,000+
August 16, 2026
July 15, 2011
This plugin does not install nor configure a cache proxy. It acts as an interface with such services.
One common method of caching content for websites is via the use of reverse proxy caching. Common examples of this are Varnish and NGINX. These systems allow a website to update content and have the visitor’s experience cached without the need for complex plugins storing the files locally and using up a user’s disk space.
A reverse proxy cache is installed in front of a server and reviews requests. If the page being requested is already cached, it delivers the cached content. Otherwise it generates the page and the cache on demand.
The Proxy Cache Purge plugin sends a request to delete (aka flush) the cached data of a page or post every time it’s modified.
When content on a site is updated by WordPress, the plugin reaches out to the proxy cache service with the URL of the page, requesting the cache be deleted.
Not all pages are deleted from the cache on every change. For example, when a post, page, or custom post type is edited, or a new comment is added, only the following pages will purge:
In addition, your entire cache will be deleted on the following actions:
Plugins can hook into the purge actions as well, to filter their own events to trigger a purge.
On a multisite network using subfolders, only network admins can purge the main site.
Purging is only half the story. Once Proxy Cache Purge empties a page, the cache for that URL is gone, so the next visitor triggers a full uncached render and waits for it. On busy sites this “cache stampede” shows up as slow pages right after every update.
Cacheability Pro is a companion plugin that closes that gap: it automatically re-warms purged URLs in the background so visitors keep hitting fast, cached responses, and it tunes your cache headers so more of your pages stay cacheable in the first place. Proxy Cache Purge handles invalidation; Cacheability Pro handles everything around it.
Proxy Cache Purge keeps your cache fresh, but how often is it actually being hit? If you run your own Varnish or NGINX server, GetPageSpeed Amplify shows your cache hit rate, request volume, and backend health over time, with a free tier. Proxy Cache Purge handles invalidation; Amplify shows you whether the cache is doing its job.
If you’re working on a site and need to turn off caching in one of two ways:
define( 'VHP_DEVMODE', true ); to your wp-config.php fileThat will break cache on page loads. It is not recommended for production!
As of version 5.4.0, Proxy Cache Purge includes an optional Cache Tags / Surrogate Keys purge mode. This feature is marked as BETA and is disabled by default.
When enabled, the plugin:
Requirements:
Surrogate-Capability headers (for example, Surrogate-Capability: vhp="Surrogate/1.0 tags/1").How to enable:
Alternatively, you can force-enable or force-disable detection via wp-config.php:
define( ‘VHP_VARNISH_TAGS’, true ); // Force treat cache as tag-capable
define( ‘VHP_VARNISH_TAGS’, false ); // Force treat cache as not tag-capable
Because this feature depends on your cache configuration, it is recommended that you test it carefully in staging before enabling it on production.
On busy sites, sending many PURGE requests directly from admin requests can slow things down. When you define DISABLE_WP_CRON as true in wp-config.php (because you are running a real system cron that calls wp-cron.php), Proxy Cache Purge automatically switches to an asynchronous mode:
Object-cache purges (the “Purge Database Cache” option) remain synchronous and are not affected by this behaviour. The Proxy Cache settings page and Site Health integration expose basic queue status so you can verify that background purging is healthy; if the queue appears large or very old, check that your system cron is correctly invoking WordPress cron.
Important: Cron Frequency and Cache Freshness
When using background purging, the frequency of your system cron determines how quickly cache invalidations are processed. The longer the interval between cron runs, the longer visitors may see stale content after updates.
For minimal stale content, run your system cron every minute:
* * * * * /usr/bin/php /var/www/html/wp-cron.php
If you can tolerate slightly longer delays, every 2-5 minutes is also acceptable. However, running cron less frequently (e.g., every 15 minutes) means cache purges may be delayed by that amount after content changes.
Note: Scheduled posts are handled specially. When a scheduled post is published via WP-Cron, the cache is purged synchronously within the same cron run, ensuring immediate cache invalidation without waiting for the next cron execution.
For detailed instructions on setting up a proper Linux-based WordPress cron, see: WordPress Cron Optimization.
Disabling Background Purging
If you have DISABLE_WP_CRON defined but do not want background purging (for example, on low-traffic sites where immediate purges are preferred), you can force-disable cron-based purging by adding this to your wp-config.php:
define( 'VHP_DISABLE_CRON_PURGING', true );
With this constant set, all cache purges will execute immediately during the request, regardless of the DISABLE_WP_CRON setting.
Purge
Purge commands let you empty the cache.
wp varnish purge – Flush the entire site cache (equivalent to clicking “Empty Cache” in admin)wp varnish purge --all – Explicitly flush the entire site cachewp varnish purge <url> – Flush cache for a specific URL and all content below it (wildcard)wp varnish purge <url> --url-only – Flush cache for only the exact URL specified (no wildcard)wp varnish purge --tag=<tag> – Flush cache by tag (requires Cache Tags mode to be enabled)Examples:
wp varnish purge – Purge entire sitewp varnish purge --all – Same as above, more explicitwp varnish purge https://example.com/hello-world/ – Purge this URL and everything below itwp varnish purge https://example.com/hello-world/ --url-only – Purge only this exact URLwp varnish purge https://example.com/wp-content/themes/ --wildcard – Purge all theme fileswp varnish purge --tag=p-123 – Purge all pages tagged with post ID 123wp varnish purge --tag=pt-post – Purge all cached pages of post type “post”Debug
Debugging can help you figure out why your cache isn’t working as well as it could. The default is for your home page, but you can pass any URL on your domain.
wp varnish debug [<url>]Available parameters:
[--include-headers] — Include headers in debug check output[--include-grep] — Grep active theme and plugin directories for common issuesDevMode
Development mode allows you to disable the cache, temporarily.
wp varnish devmode [<activate|deactivate|toggle>] – Change development mode stateAsync purge queue (cron-mode)
When you define DISABLE_WP_CRON as true and run a real system cron for WordPress, Proxy Cache Purge can move heavy purge work into a small background queue that is processed by WP‑Cron.
You can inspect and manage that queue via WP‑CLI:
wp varnish queue status – show whether cron-mode is active, if a full purge is queued, counts of queued URLs/tags, and the last queue run time.wp varnish queue process – process any items currently in the queue (useful to run after deploys or cache‑sensitive operations).wp varnish queue clear – clear the queue without sending any PURGE requests.These commands do not replace your normal WordPress cron (you still need a cron entry that calls wp cron event run --due-now or hits wp-cron.php), but they give you a simple operational handle when using cron‑mode.
There are different types of cache purges, and they behave differently:
Manual Purges (Admin Bar)
Manual purges are always immediate, even when background cron-mode is enabled. This is intentional: when you click a button, you expect immediate results.
Automatic Purges (Post Save/Update)
When you save or update a post, the plugin automatically purges:
This can be 20-50+ URLs depending on your site structure. When cron-mode is enabled, these automatic purges are queued and processed in the background to avoid slowing down the post editor.
Key Difference
Action
URLs Purged
Uses Cron Queue?
“Purge Cache (All Pages)”
1 (regex)
No – always immediate
“Purge Cache (this page)”
1
No – always immediate
Post save/update
20-50+
Yes (if cron-mode enabled)
If you need to immediately purge all URLs related to a specific post (not just the post URL), save the post – the automatic purge will handle all related URLs.
No special instructions apply.
If you have a 3rd party proxy service (such as Sucuri or Cloudflare) you will need to add an IP address on the Proxy Cache -> Settings page. Alternatively you can add a define to your wp-config.php file: define('VHP_VARNISH_IP','123.45.67.89');
When using NGINX based proxies, your IP will likely be localhost.
Please report all issues in the support forums
If you have code patches, pull requests are welcome.
This plugin was originally adopted and updated for DreamHost’s DreamPress server, however it is not (and never has been) for DreamHost only.
I worked at DreamHost from 2012 to 2022, and have maintained the plugin since around 2014 or so.
As of October 2023, this plugin is NO LONGER installed by default on DreamPress.
Today, the plugin is maintained by GetPageSpeed, with a focus on advanced NGINX and proxy caching deployments and strong compatibility with the NGINX cache-purge module from the NGINX Extras collection.
No. This plugin tells your cache system when content is updated, and to delete the cached data at that time.
Speed and stability. Emptying too much of a cache on every change can slow a server down. This plugin does its best to determine what needs to be deleted and when, while providing hooks for developers to use as necessary.
It depends on the post, but in general the tool will delete cached content for:
Not really, but in order to prevent your site from crashing by running the same checks over and over, if you try to purge more than 50 URLs at once, the plugin will do a full purge. Normally this never happens, but there are some plugins that hook into the options to add more pages to purge on an update.
You can change this value in your settings, or via the define VHP_VARNISH_MAXPOSTS in your wp-config.php file.
Keep in mind, the count of 50 does not include category/tags, API, or RSS pages. It’s just the sheer number of individual posts/pages you’re trying to purge at once.
Yes. If your environment doesn’t cache logged-in users and you want to avoid purge noise from autosaves/drafts, you can exclude specific statuses network‑wide via wp-config.php (multisite‑friendly).
Add a define to exclude drafts:
define( 'VHP_EXCLUDED_POST_STATUSES', 'draft' );
Exclude multiple statuses (comma‑separated):
define( 'VHP_EXCLUDED_POST_STATUSES', 'draft,pending' );
Or pass an array:
define( 'VHP_EXCLUDED_POST_STATUSES', array( 'draft', 'pending' ) );
Developers can also use a filter to adjust the valid statuses programmatically:
add_filter( 'varnish_http_purge_valid_post_statuses', function( $statuses, $post_id ) {
return array_diff( $statuses, array( 'draft' ) );
}, 10, 2 );
By default, the plugin considers these statuses for purge URL generation: publish, private, trash, pending, draft.
Yes. Click the ‘Empty Cache’ button on the “Right Now” Dashboard (see the screenshot if you can’t find it). There’s also an “Empty Cache” button on the admin toolbar.
If you don’t see a button, then your account doesn’t have the appropriate permissions. Only administrators can empty the entire cache. In the case of a subfolder multisite network, only the network admins can empty the cache for the primary site.
No. WordPress can’t detect those file changes so it can’t tell your cache what to do. You will need to use the Empty Cache buttons when you’re done editing your code.
No. Some of them have behaviours that cause them not to cache, either by accident or design. It’s incredibly hard to debug those, since many of the related issues are contextual (like if you save a page with a special setting). I’ve done my best to flag everything as possible issues with the debugger.
Yes. Full documentation can be found on Custom Filters in the wiki.
Not permanently, and remember that this plugin is not actually caching your content.
You can use development mode to have WordPress attempt to tell your proxy service not to serve cached content, but the content will still be cached by the service.
There are three ways to do this:
define( 'VHP_DEVMODE', true ); to your wp-config.php file.The first two options will enable development mode for 24 hours. If you’re working on long term development, you should use the define.
It is not recommended you use development mode on production sites for extended periods of time, as it will slow your site down and lose all the benefits of caching in the first place.
If you’ve disabled caching via the define, then you cannot restart cache via the plugin. You would need to change define( 'VHP_DEVMODE', true ); to define( 'VHP_DEVMODE', false ); in your wp-config.php file.
Due to the damage this can cause a site, access is limited to admins only. In the case of a multisite network, only Network Admins can disable caching and they must do so via wp-config.php for security.
While development mode is on, your server will continue to cache content but the plugin will tell WordPress not to use the cached content. That means files that exist outside of WordPress (like CSS or images) may serve cached content.
The plugin does its best to add a No Cache parameter to javascript and CSS, however if a theme or plugin doesn’t use proper WordPress enqueues, then their cached content will be shown.
Because the server is still caching content.
The plugin provides a way to flush the cache for those pages, as well as anything not included in WordPress, for your convenience.
From your WordPress Dashboard, go to Proxy Cache > Check Caching. There, a page will auto-scan your front page and report back any issues found. This includes any known problematic plugins. You can use it to scan any URL on your domain.
PageSpeed likes to put in Caching headers to say not to cache. To fix this, you need to put this in your .htaccess section for PageSpeed: ModPagespeedModifyCachingHeaders off
If you’re using nginx, it’s pagespeed ModifyCachingHeaders off;
When you use CloudFlare or any other similar service, you’ve put a proxy in front of the server’s proxy. In general this isn’t a bad thing, though it can introduce some network latency (that means your site may run slower because it has to go through multiple layers to get to the content). The problem arises when WordPress tries to send the purge request to your domain name and, with a proxy, that means the proxy service and not your website.
On single-site, you can edit this via the Proxy Cache > Check Caching page. On Multisite, you’ll need to add the following to your wp-config.php file: define('VHP_VARNISH_IP','123.45.67.89');
Replace 123.45.67.89 with the IP of your Proxy Cache Server (not CloudFlare). DO NOT put http in this define. If you’re on nginx, you’ll want to use localhost instead of an IP address.
If you want to use WP-CLI, you can set an option in the database. This will not take precedence over the define, and exists for people who want to use automation tools: wp option update vhp_varnish_ip 123.45.67.89
This is usually related to CloudFlare’s APO setup.
I have an open ticket with CloudFlare trying to debug this, but basically whatever they’re doing with APO doesn’t ‘like’ the flush command and times out (or crashes).
Your IP address is incorrect. Check the IP of your server and then the setting for your proxy cache IP. If they’re not the same, that’s likely why.
Your proxy IP must be one of the IPs that the service is listening on. If you use multiple IPs, or if you’ve customized your ACLs, you’ll need to pick one that doesn’t conflict with your other settings.
For example, if you have a Varnish based cache and it’s listening on a public and private IP, you’ll want to pick the private. On the other hand, if you told Varnish to listen on 0.0.0.0 (i.e. “listen on every interface you can”) you would need to check what IP you set your purge ACL to allow (commonly 127.0.0.1 aka localhost), and use that (i.e. 127.0.0.1).
If your web host set up your service, check their documentation.
You may enter them, separated by a comma, on the settings page.
So far this plugin has been reported to successfully function on Varnish v2 through v6.5.
Yes. Set the cache backend to NGINX via the settings page (Proxy Cache > Settings > Cache Backend) or add this to your wp-config.php:
define( 'VHP_PURGE_BACKEND', 'nginx' );
When set to NGINX, the plugin uses a literal * wildcard instead of Varnish’s .* regex pattern, which is what the NGINX cache-purge module expects. You should also set your Proxy Cache IP to localhost.
This is a question beyond the support of this plugin. I do not have the resources available to offer any configuration help. Here are some basic gotchas to be aware of:
/.* and sets the X-Purge-Method header to regex/* instead (literal wildcard)Some providers require a control key, token, or Authorization header to accept PURGE requests. You can set a header name and value via the settings page or via the following constant:
define( 'VHP_VARNISH_EXTRA_PURGE_HEADER', 'X-Control-Key: YOUR_CONTROL_KEY_HERE' );
Alternatively, you can inject any required header via a filter.
Set where PURGE requests should be sent (host:port, no scheme):
define( ‘VHP_VARNISH_IP’, ‘varnish.example.com:6081’ );
Add your control key/auth header via a small MU plugin so it loads on every request. Create wp-content/mu-plugins/varnish-purge-auth.php with:
<?php
add_filter( ‘varnish_http_purge_headers’, function( $headers ) {
// Example: provider expects a custom key header
$headers[‘X-Control-Key’] = ‘YOUR_CONTROL_KEY_HERE’;
// Or use Authorization headers:
// $headers['Authorization'] = 'Basic ' . base64_encode( 'username:password' );
// $headers['Authorization'] = 'Bearer ' . 'YOUR_TOKEN_HERE';
return $headers;
} );
If your provider requires HTTPS for the purge endpoint, force the schema:
add_filter( 'varnish_http_purge_schema', function() { return 'https://'; } );
Important: This plugin sends HTTP PURGE requests to your cache service. It does not use the Varnish management interface (varnishadm/secret on port 6082).
Yes IF the service has an interface. Sadly NGINX does not. Detailed directions can be found on the debugging section on GitHub. Bear in mind, these interfaces tend to be command-line only.
It means that somewhere your server’s headers aren’t returning the data the plugin needs to see, in order to determine if the cache is working. The most common cause is that your server isn’t returning the X-Varnish header or the Age header.
You can use varnish_http_purge_x_varnish_header_name filter to customize this header name, like below to resolve this:
function change_varnish_header( $default_header ) {
return 'My-Custom-Header'; // Replace with the desired header
}
add_filter( 'varnish_http_purge_x_varnish_header_name', 'change_varnish_header' );
vhp_flush_do) now only purges URLs on this site’s own host, and requires a capability (filter: vhp_manual_purge_capability, default edit_published_posts) in addition to the nonce. Previously a low-privileged user could reuse the purge nonce to point the server’s outbound PURGE request at an arbitrary host – a blind SSRF reachability oracle. Reported privately by Austin Ginder.vhp_process_purge_queue was silently never re-scheduled. Watchdog re-arms a ghost event when the queue is non-empty and vhp_varnish_last_queue_run is older than 5 minutes.enqueue_urls() now ensures the cron event is scheduled even when a full purge is already queued.DISABLE_WP_CRON no longer auto-enables async purging — opt in via VHP_ENABLE_CRON_PURGING, the vhp_varnish_cron_purging site option, or the vhp_purge_use_cron filter.VHP_ENABLE_CRON_PURGING constant and vhp_purge_queue_watchdog_seconds filter.Requires PHP bumped from 5.6 to 7.4 to match WordPress 7.0’s PHP floor. Sites on PHP < 7.4 will not see this update.VHP_DISABLE_CRON_PURGING constant to force-disable background purging even when DISABLE_WP_CRON is enabled. Useful for low-traffic sites that use external cron but prefer immediate cache purges.--all flag for explicit full site cache purge.--url-only flag to purge exact URL without wildcard matching.--tag=<tag> option for tag-based cache purging (requires Cache Tags mode).wp varnish purge correctly documented as full site purge.transition_post_status hook to handle future publish transitions synchronously, ensuring immediate cache invalidation for scheduled posts.?p=XXX) are now purged when scheduled posts publish, clearing any cached 404 responses.VHP_VARNISH_TAGS wp-config define.VHP_EXCLUDED_POST_STATUSES define to exclude statuses (e.g. drafts) from purge triggers.varnish_http_purge_valid_post_statuses filter to customize statuses programmatically.rest_base and use term IDs.wp_remote_get args and header checks (Via header scalar/array).| Version | Download | Type |
|---|---|---|
| 5.12.3 | Download | Stable |
| 5.12.2 | Download | Stable |
| 5.12.1 | Download | Stable |
| 5.12.0 | Download | Stable |
| 5.11.1 | Download | Stable |
| 5.11.0 | Download | Stable |
| 5.10.0 | Download | Stable |
| 5.9.2 | Download | Stable |
| 5.9.0 | Download | Stable |
| 5.8.3 | Download | Stable |
| 5.8.2 | Download | Stable |
| 5.8.1 | Download | Stable |
| 5.8.0 | Download | Stable |
| 5.7.0 | Download | Stable |
| 5.6.5 | Download | Stable |
| 5.6.4 | Download | Stable |
| 5.6.3 | Download | Stable |
| 5.6.2 | Download | Stable |
| 5.6.0 | Download | Stable |
| 5.5.3 | Download | Stable |
| 5.5.2 | Download | Stable |
| 5.5.1 | Download | Stable |
| 5.5.0 | Download | Stable |
| 5.4.0 | Download | Stable |
| 5.3.0 | Download | Stable |
| 5.2.2 | Download | Stable |
| 5.2.1 | Download | Stable |
| 5.2.0 | Download | Stable |
| 5.1.3 | Download | Stable |
| 5.1.2 | Download | Stable |
| 5.1.1 | Download | Stable |
| 5.1.0 | Download | Stable |
| 5.0.3 | Download | Stable |
| 5.0.2 | Download | Stable |
| 5.0.1 | Download | Stable |
| 5.0 | Download | Stable |
| 4.8.1 | Download | Stable |
| 4.7.3 | Download | Stable |
| 4.6.6 | Download | Stable |
| 4.5.0 | Download | Stable |
| 4.4.0 | Download | Stable |
| Development | Download | Trunk |