Wp rocket cache invalidation
Skill Lonsdale201/wp-agent-skills/wp-rocket/wp-rocket-cache-invalidation
A community-maintained collection of agent skills for WordPress plugin and theme development.
npx -y skills add Lonsdale201/wp-agent-skills --skill wp-rocket-cache-invalidationAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 21 stars21 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Programmatically clear WP Rocket cache from a third-party plugin / theme when data changes — the public rocket_clean_* function family (rocket_clean_post, rocket_clean_files, rocket_clean_term, rocket_clean_user, rocket_clean_home, rocket_clean_minify, rocket_clean_cache_busting, rocket_clean_domain, rocket_clean_cache_dir). Critical detection rule — WP Rocket is a PAID plugin not on Packagist; always feature-detect via function_exists('rocket_clean_post') OR defined('WP_ROCKET_VERSION') before calling, since not every site has it. Never raw-unlink the cache directory or call wp_cache_flush() expecting it to clear WP Rocket — wp_cache_flush is WP object cache, WP Rocket is FILE cache. The before_*_clean_* / after_*_clean_* action hooks fire around every clean — useful for audit logging and monitoring. Use when integrating cache invalidation from a companion or integration plugin. Triggers on rocket_clean_, before_rocket_clean, after_rocket_clean, "WP Rocket cache invalidate / purge / clear".
SKILL.md
20.3 KB, as published. Nobody here has run it
WP Rocket: cache invalidation from third-party code
For developers shipping a plugin or theme that mutates content WP Rocket has cached — saving a custom CPT, completing a WooCommerce order, importing data, processing a webhook, scheduling a bulk update. WP Rocket caches HTML to disk (NOT to the WP object cache); raw cache invalidation requires going through the plugin's public API, otherwise stale HTML stays served until the cache TTL or the next save.
WP Rocket is a paid plugin, not on Packagist, not in the WordPress.org plugin directory. Many sites have it; many don't. Every code path that touches
rocket_clean_*MUST be feature-detected first — otherwise your code fatals on installs without WP Rocket.
Misconception this skill corrects
"I'll call
wp_cache_flush()after my plugin saves data — that clears WP Rocket too."
It doesn't. wp_cache_flush() clears the WordPress object cache (transients, options, post meta caches in Redis / Memcached / WP_Cache_Object). WP Rocket is a page cache that writes static HTML files to disk under wp-content/cache/wp-rocket/.... The two are completely independent layers — you can flush the object cache 1000 times and the WP Rocket cached HTML stays untouched.
The right entry point: rocket_clean_post( $post_id ) if a specific post changed, or one of the more granular rocket_clean_* functions for other scenarios. Verified at wp-content/plugins/wp-rocket/inc/common/purge.php:167 and inc/functions/files.php.
Other AI-prone misconceptions:
- "I'll just
unlink()the WP Rocket cache files for this URL." Wrong direction — WP Rocket's filename layout is non-trivial: desktop / mobile / tablet variants, language variants (/cache/wp-rocket/example.com-en/...), query-string variants, gzipped variants, webp variants. Manual deletion misses some, leaves stale files, AND skips thebefore_/after_action hooks that other plugins (CDN purgers, Varnish, Cloudflare addons) listen for. - "
function_exists('rocket_clean_post')is paranoid; everyone has WP Rocket." No, WP Rocket is paid. ~30% of WP installs use SOME caching plugin; even of those, WP Rocket is one of many. Always feature-detect. - "
is_plugin_active('wp-rocket/wp-rocket.php')" is the right check." Half-true.is_plugin_active()requireswp-admin/includes/plugin.phpto be loaded — it's NOT available during early hooks likeplugins_loaded.defined('WP_ROCKET_VERSION')andfunction_exists('rocket_clean_post')work everywhere.
When to use this skill
Trigger when ANY of the following is true:
- The diff calls
rocket_clean_*,wp_cache_flush(),rocket_*cache operations, OR raw filesystem operations againstwp-content/cache/wp-rocket/. - A plugin saves data and the user expects the cached page to refresh.
- WooCommerce / membership / LMS plugin invalidation flows (e.g. user enrolls in a course → cached course page shows old "no access" state).
- Reviewing PR code that hooks
save_post/transition_post_status/woocommerce_*events and wants to invalidate cache. - Custom CPT integration where post-save → page invalidation is needed.
- Bulk import / migration scripts that should NOT churn the cache during the import (delay invalidation to the end).
Plugin identity (verified)
| Field | Value |
|---|---|
| Plugin | WP Rocket |
| Version | 3.23 (Code name "Iego") |
| Min WP | 5.8 |
| Min PHP | 7.4 |
| Tested up to | WP 6.3.1 |
| Distribution | Paid / premium — not on Packagist, not on WP.org repo |
| Constants | WP_ROCKET_VERSION, WP_ROCKET_SLUG = 'wp_rocket_settings', WP_ROCKET_PHP_VERSION, WP_ROCKET_WP_VERSION |
| Text domain | rocket |
| Cache type | File-based page cache (HTML written to disk) — NOT object cache |
Public cache-invalidation API (verified)
All functions live in wp-content/plugins/wp-rocket/inc/functions/files.php except rocket_clean_post which is in inc/common/purge.php.
| Function | Args | What it clears |
|---|---|---|
rocket_clean_post( $post_id, $post = null ) | int post ID, optional WP_Post | Cached HTML for this post + its archive(s) + home (per built-in logic) |
rocket_clean_files( $urls, $filesystem = null, $run_actions = true ) | string or array of URLs | Cached HTML for arbitrary URLs (e.g. category archives, custom permalinks) |
rocket_clean_term( $term_id, $taxonomy_slug ) | int + string | Taxonomy archive page |
rocket_clean_user( $user_id, $lang = '' ) | int + optional lang code | User-specific cache (logged-in user dynamic cookies) |
rocket_clean_home( $lang = '' ) | optional lang code | Homepage cache only |
rocket_clean_home_feeds() | none | Home feed cache |
rocket_clean_domain( $lang = '', $filesystem = null ) | optional lang + filesystem | Everything for the domain — the nuke option |
rocket_clean_cache_dir() | none | The entire cache directory (across domains on multisite) |
rocket_clean_minify( $extensions = ['js', 'css'] ) | array of extensions | Minified asset cache |
rocket_clean_cache_busting( $extensions = ['js', 'css'] ) | array of extensions | Cache-busting versioned static asset files |
Workflow
1. Always feature-detect first
if ( ! function_exists( 'rocket_clean_post' ) ) {
return; // WP Rocket not active; skip silently
}
rocket_clean_post( $post_id );
OR, with the constant guard:
if ( defined( 'WP_ROCKET_VERSION' ) ) {
rocket_clean_post( $post_id );
}
Both work; the function_exists form is more defensive (handles the rare case where WP Rocket is partially loaded). Pick one and stay consistent.
For namespaced PHP code, use a full backslash: if ( ! \function_exists( 'rocket_clean_post' ) ) return;.
2. Pick the right granularity
| Scenario | Right call |
|---|---|
| One specific post changed (CPT save, comment) | rocket_clean_post( $post_id ) |
| One specific URL changed (custom permalink, programmatic page) | rocket_clean_files( [ $url ] ) |
| Taxonomy archive needs refresh (term added / renamed) | rocket_clean_term( $term_id, $taxonomy ) |
| User profile changed | rocket_clean_user( $user_id ) |
| Homepage needs refresh (e.g. featured post change) | rocket_clean_home() |
| Site-wide change (theme switch, options change) | rocket_clean_domain() |
| Asset pipeline change (new minify rule, dev → prod) | rocket_clean_minify() + rocket_clean_cache_busting() |
Do not call rocket_clean_domain() from frequent events. It's the heaviest operation; over-using it defeats WP Rocket's whole purpose by constantly re-warming. Reserve it for actually-site-wide changes.
3. Hook into post-save events
// Most common pattern — clear when a CPT entry is saved.
add_action( 'save_post_my_cpt', function ( int $post_id, \WP_Post $post, bool $update ): void {
if ( wp_is_post_revision( $post_id ) || wp_is_post_autosave( $post_id ) ) {
return;
}
if ( ! \function_exists( 'rocket_clean_post' ) ) {
return;
}
rocket_clean_post( $post_id );
}, 10, 3 );
save_post_<cpt> is preferable to plain save_post (more specific). Skip revisions and autosaves — both fire save_post but neither matters for cache.
4. Hook into WooCommerce events
// Order completion → clear product page cache
add_action( 'woocommerce_order_status_completed', function ( int $order_id ): void {
if ( ! \function_exists( 'rocket_clean_post' ) ) {
return;
}
$order = wc_get_order( $order_id );
if ( ! $order ) {
return;
}
foreach ( $order->get_items() as $item ) {
$product_id = $item->get_product_id();
if ( $product_id ) {
rocket_clean_post( $product_id ); // each ordered product's page
}
}
}, 20, 1 );
Reason: stock count changes after a sale; cached product pages show stale stock. WP Rocket has its own WC integration but third-party plugins that touch stock or display cached prices need their own invalidation.
5. Bulk imports — defer invalidation
function my_import_posts( array $records ): void {
// Suppress WP Rocket's automatic purges during the import.
add_filter( 'rocket_is_importing', '__return_true' );
foreach ( $records as $record ) {
wp_insert_post( $record );
}
// Restore + nuke once.
remove_filter( 'rocket_is_importing', '__return_true' );
if ( \function_exists( 'rocket_clean_domain' ) ) {
rocket_clean_domain();
}
}
For a 10K-post import, calling rocket_clean_post() per-row generates 10K cache wipes + 10K filesystem operations. One rocket_clean_domain() at the end is orders of magnitude faster.
6. Lifecycle action hooks for monitoring
Verified in inc/functions/files.php and inc/common/purge.php — the public clean functions fire before_* and after_* actions:
| Function | Actions fired |
|---|---|
rocket_clean_post | before_rocket_clean_post, after_rocket_clean_post |
rocket_clean_files | before_rocket_clean_files, after_rocket_clean_files (per URL: before_rocket_clean_file, after_rocket_clean_file) |
rocket_clean_term | before_rocket_clean_term, after_rocket_clean_term |
rocket_clean_user | before_rocket_clean_user, after_rocket_clean_user |
rocket_clean_home | before_rocket_clean_home, after_rocket_clean_home |
rocket_clean_home_feeds | before_rocket_clean_home_feeds, after_rocket_clean_home_feeds |
rocket_clean_domain | per URL: before_rocket_clean_domain, after_rocket_clean_domain; after the full run: rocket_after_clean_domain |
rocket_clean_minify | before_rocket_clean_minify, after_rocket_clean_minify |
rocket_clean_cache_busting | before_rocket_clean_busting, after_rocket_clean_cache_busting |
rocket_clean_cache_dir | before_rocket_clean_cache_dir, after_rocket_clean_cache_dir |
Use these for:
- CDN purges triggered by cache wipes (
after_rocket_clean_post→ call your CDN API). - Audit logging — record cache-invalidation events with the post / URL info.
- Custom invalidation chains — when post X changes, also invalidate URL Y.
// Audit log — every invalidation
add_action( 'after_rocket_clean_domain', function ( string $root, string $lang, string $url ): void {
do_action( 'qm/info', "WP Rocket: domain cache cleared for {$url} (lang: {$lang})" );
}, 10, 3 );
// Trigger Cloudflare purge after WP Rocket clears a post
add_action( 'after_rocket_clean_post', function ( $post, array $purge_urls ): void {
foreach ( $purge_urls as $url ) {
my_cloudflare_purge( $url );
}
}, 10, 2 );
7. Multisite considerations
rocket_clean_domain( $lang ) clears the cache for the current site's domain. On multisite, switching context first:
foreach ( get_sites() as $site ) {
switch_to_blog( $site->blog_id );
if ( \function_exists( 'rocket_clean_domain' ) ) {
rocket_clean_domain();
}
restore_current_blog();
}
rocket_clean_cache_dir() clears the entire cache directory on disk — across all blogs at once. Use for "I'm activating WP Rocket-affecting changes globally" (theme switch, network-wide settings rollout).
8. The $run_actions flag in rocket_clean_files
Verified at inc/functions/files.php:547 — rocket_clean_files( $urls, $filesystem = null, $run_actions = true ). The third arg defaults to true — fires the before_/after_ hooks per file. Pass false for silent purge if you're calling it from inside another after_rocket_clean_* hook (avoids infinite recursion).
add_action( 'after_rocket_clean_post', function ( $post, array $purge_urls ) {
// Don't fire actions on these supplementary cleans (we're already inside an action)
rocket_clean_files( [ home_url( '/related-feed' ) ], null, $run_actions = false );
}, 10, 2 );
Critical rules
- Always feature-detect with
function_exists('rocket_clean_post')ordefined('WP_ROCKET_VERSION'). WP Rocket is paid; not every site has it. wp_cache_flush()does NOT clear WP Rocket cache. Two different layers — object cache vs file cache.is_plugin_active('wp-rocket/wp-rocket.php')requireswp-admin/includes/plugin.php— not available during early hooks. Usedefined/function_existsinstead.- Pick the smallest granularity that covers the change.
rocket_clean_postoverrocket_clean_domainfor a single-post change. - Skip revisions / autosaves when hooking
save_post— they fire but don't change visible content. - Defer invalidation during bulk imports — temporarily return
truefromrocket_is_importing, insert posts, remove the filter, then callrocket_clean_domainonce. - Don't call
rocket_clean_domainfrom high-frequency events. Defeats WP Rocket's purpose. - Use
$run_actions = falseinrocket_clean_fileswhen calling from inside another action handler to avoid recursion. - Multisite:
switch_to_blog+restore_current_blogaround the cache call when iterating sites. - Never raw-
unlink()the cache files. Filename layout is non-trivial (desktop / mobile / lang / query-string variants); manual deletion leaves stale variants. rocket_clean_minifyandrocket_clean_cache_bustingare for CSS / JS asset pipeline changes, not for HTML cache.
Common mistakes
// WRONG — wp_cache_flush expecting WP Rocket to clear
function my_save_handler( $post_id ): void {
update_post_meta( $post_id, 'foo', 'bar' );
wp_cache_flush(); // WRONG: only clears object cache, not WP Rocket file cache
}
// RIGHT
function my_save_handler( $post_id ): void {
update_post_meta( $post_id, 'foo', 'bar' );
if ( \function_exists( 'rocket_clean_post' ) ) {
rocket_clean_post( $post_id );
}
}
// WRONG — raw filesystem deletion
function my_clear() {
$cache_dir = WP_CONTENT_DIR . '/cache/wp-rocket/example.com';
array_map( 'unlink', glob( $cache_dir . '/*.html' ) ); // WRONG: misses mobile / lang / qs variants
}
// RIGHT
if ( \function_exists( 'rocket_clean_domain' ) ) {
rocket_clean_domain();
}
// WRONG — is_plugin_active during plugins_loaded
add_action( 'plugins_loaded', function () {
if ( is_plugin_active( 'wp-rocket/wp-rocket.php' ) ) { // WRONG: fatal — function not loaded
// ...
}
} );
// RIGHT
add_action( 'plugins_loaded', function () {
if ( ! defined( 'WP_ROCKET_VERSION' ) ) return;
// ...
}, 11 );
// WRONG — clean_domain on every post save
add_action( 'save_post', function ( $post_id ) {
if ( \function_exists( 'rocket_clean_domain' ) ) {
rocket_clean_domain(); // WRONG: nukes the entire site cache for one post change
}
} );
// RIGHT — granular
add_action( 'save_post', function ( $post_id ) {
if ( wp_is_post_revision( $post_id ) || wp_is_post_autosave( $post_id ) ) return;
if ( \function_exists( 'rocket_clean_post' ) ) {
rocket_clean_post( $post_id );
}
} );
// WRONG — no autosave / revision skip
add_action( 'save_post', function ( $post_id ) {
rocket_clean_post( $post_id ); // fires on every keystroke during autosave
} );
// RIGHT
if ( wp_is_post_revision( $post_id ) || wp_is_post_autosave( $post_id ) ) return;
rocket_clean_post( $post_id );
// WRONG — clean inside a clean (recursion)
add_action( 'after_rocket_clean_post', function ( $post ) {
rocket_clean_files( [ get_permalink( $post->ID ) ] ); // WRONG: fires after_rocket_clean_files which can re-trigger
} );
// RIGHT — pass $run_actions = false
add_action( 'after_rocket_clean_post', function ( $post ) {
rocket_clean_files( [ get_permalink( $post->ID ) ], null, false );
} );
// WRONG — bulk import without deferral
foreach ( $records as $record ) {
wp_insert_post( $record );
rocket_clean_post( /* ... */ ); // WRONG: N cache wipes for N records
}
// RIGHT — defer to one nuke
add_filter( 'rocket_is_importing', '__return_true' );
foreach ( $records as $record ) {
wp_insert_post( $record );
}
remove_filter( 'rocket_is_importing', '__return_true' );
if ( \function_exists( 'rocket_clean_domain' ) ) {
rocket_clean_domain();
}
// WRONG — assume one implicit home clean covers every language variant
rocket_clean_home(); // ambiguous on multilingual sites; depends on the active i18n integration/context
// RIGHT — iterate the active language codes from WPML / Polylang / TranslatePress
foreach ( [ 'en', 'de', 'fr' ] as $lang ) {
rocket_clean_home( $lang );
}
Cross-references
- Run
wp-rocket-cache-rejection-and-filterswhen the answer isn't "clear cache after change" but "PREVENT this URL / path from being cached at all". - Run
wp-rocket-mcp-and-abilitieswhen the task is exposing WP Rocket settings to AI/MCP (thewp-rocket/get-options&wp-rocket/set-optionabilities, the/oauth/*MCP OAuth server, or therocket_mcp_*/rocket_enable_abilitiesfilters) — new in 3.23. - Run
wp-plugin-cronwhen invalidation is scheduled / batched (Action Scheduler, WP-Cron) — combine withrocket_clean_*calls in the cron handler. - Run
wcs-renewal-schedulerif cache-invalidation triggers come from WC Subscription renewal events. - Run
wp-plugin-options-storagewhen deciding "should I cache this manually OR let WP Rocket handle it" — most often: let WP Rocket do it.
What this skill does NOT cover
- WP Rocket settings UI / admin pages. Out of scope; integrators don't touch UI.
- Internal
Engine/classes. Private; signatures change between versions. Use the public functions. - The WP Rocket REST API (admin-side, paid). Not designed for third-party invalidation.
.htaccessrewrite rules WP Rocket installs. Server-config concern; integrators don't modify these.- Cloudflare / Varnish / CDN-specific addons. Each has its own surface; this skill is core WP Rocket only.
rocket_bufferfilter for HTML output manipulation. Niche + dangerous; covered inwp-rocket-cache-rejection-and-filterswith strong warnings.- License / activation key handling. Premium-specific; not integrator-facing.
References
- Plugin entry: wp-content/plugins/wp-rocket/wp-rocket.php — version constants, header.
rocket_clean_post: inc/common/purge.php:167 — handles auto-draft / draft / nav_menu_item / attachment skips, firesbefore_/after_rocket_clean_post.rocket_clean_files: inc/functions/files.php:547 —$run_actionsthird arg controls whetherbefore_/after_rocket_clean_filesand per-URLbefore_/after_rocket_clean_filefire.rocket_clean_home: inc/functions/files.php:679.rocket_clean_domain: inc/functions/files.php:821.rocket_clean_term: inc/functions/files.php:924.rocket_clean_user: inc/functions/files.php:996.rocket_clean_cache_dir: inc/functions/files.php:1060.rocket_clean_minify: inc/functions/files.php:354.- WP Rocket plugin compatibility doc: https://docs.wp-rocket.me/article/92-plugin-compatibility-with-wp-rocket.
- Official documentation: https://docs.wp-rocket.me/article/2-getting-started