Claude Skill

wp-rocket-cache-invalidation

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,

LLM Mart · 0 points · 0 views 0 listing impressions 0 install-command copies
Virus-scanned Reviewed automatically before listing.

Full trust report

Download lonsdale201-wp-agent-skills-wp-rocket_wp-rocket-cache-invalidation-52f6020.zip · 6 KB
Part of lonsdale201/wp-agent-skills — 226 skills

Install

skills CLI npx skills add https://github.com/Lonsdale201/wp-agent-skills/tree/main/wp-rocket/wp-rocket-cache-invalidation
Claude Code claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install lonsdale201-wp-agent-skills@llmmart
Git git clone https://github.com/Lonsdale201/wp-agent-skills.git

The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole lonsdale201/wp-agent-skills collection as a plugin from our marketplace. Git is the plain clone.

Skill manifest

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 the before_/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() requires wp-admin/includes/plugin.php to be loaded — it's NOT available during early hooks like plugins_loaded. defined('WP_ROCKET_VERSION') and function_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 against wp-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') or defined('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') requires wp-admin/includes/plugin.php — not available during early hooks. Use defined / function_exists instead.
  • Pick the smallest granularity that covers the change. rocket_clean_post over rocket_clean_domain for 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 true from rocket_is_importing, insert posts, remove the filter, then call rocket_clean_domain once.
  • Don't call rocket_clean_domain from high-frequency events. Defeats WP Rocket's purpose.
  • Use $run_actions = false in rocket_clean_files when calling from inside another action handler to avoid recursion.
  • Multisite: switch_to_blog + restore_current_blog around 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_minify and rocket_clean_cache_busting are 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-filters when the answer isn't "clear cache after change" but "PREVENT this URL / path from being cached at all".
  • Run wp-rocket-mcp-and-abilities when the task is exposing WP Rocket settings to AI/MCP (the wp-rocket/get-options & wp-rocket/set-option abilities, the /oauth/* MCP OAuth server, or the rocket_mcp_* / rocket_enable_abilities filters) — new in 3.23.
  • Run wp-plugin-cron when invalidation is scheduled / batched (Action Scheduler, WP-Cron) — combine with rocket_clean_* calls in the cron handler.
  • Run wp-plugin-options-storage when 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.
  • .htaccess rewrite 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_buffer filter for HTML output manipulation. Niche + dangerous; covered in wp-rocket-cache-rejection-and-filters with strong warnings.
  • License / activation key handling. Premium-specific; not integrator-facing.

References

Files (wp-agent-skills)
  • SKILL.md 20.2 KB
    ---
    name: wp-rocket-cache-invalidation
    description: 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".
    metadata:
      wp-skills-author: "Soczó Kristóf"
      wp-skills-contact: "mailto:lonsdale201@hotmail.com"
      wp-skills-plugin: "wp-rocket"
      wp-skills-plugin-version-tested: "3.23"
      wp-skills-php-min: "7.4"
      wp-skills-last-updated: "2026-07-09"
    ---
    
    # 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](purge.php) and [inc/functions/files.php](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 the `before_/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()` requires `wp-admin/includes/plugin.php` to be loaded — it's NOT available during early hooks like `plugins_loaded`. `defined('WP_ROCKET_VERSION')` and `function_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 against `wp-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](files.php) except `rocket_clean_post` which is in [inc/common/purge.php](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
    
    ```php
    if ( ! function_exists( 'rocket_clean_post' ) ) {
        return;   // WP Rocket not active; skip silently
    }
    
    rocket_clean_post( $post_id );
    ```
    
    OR, with the constant guard:
    
    ```php
    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
    
    ```php
    // 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
    
    ```php
    // 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
    
    ```php
    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](files.php) and [inc/common/purge.php](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.
    
    ```php
    // 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:
    
    ```php
    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](files.php) — `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).
    
    ```php
    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')` or `defined('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')` requires `wp-admin/includes/plugin.php`** — not available during early hooks. Use `defined` / `function_exists` instead.
    - **Pick the smallest granularity that covers the change.** `rocket_clean_post` over `rocket_clean_domain` for 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 `true` from `rocket_is_importing`, insert posts, remove the filter, then call `rocket_clean_domain` once.
    - **Don't call `rocket_clean_domain` from high-frequency events.** Defeats WP Rocket's purpose.
    - **Use `$run_actions = false`** in `rocket_clean_files` when calling from inside another action handler to avoid recursion.
    - **Multisite: `switch_to_blog` + `restore_current_blog`** around 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_minify` and `rocket_clean_cache_busting`** are for CSS / JS asset pipeline changes, not for HTML cache.
    
    ## Common mistakes
    
    ```php
    // 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-filters`** when the answer isn't "clear cache after change" but "PREVENT this URL / path from being cached at all".
    - Run **`wp-rocket-mcp-and-abilities`** when the task is exposing WP Rocket settings to AI/MCP (the `wp-rocket/get-options` & `wp-rocket/set-option` abilities, the `/oauth/*` MCP OAuth server, or the `rocket_mcp_*` / `rocket_enable_abilities` filters) — new in 3.23.
    - Run **`wp-plugin-cron`** when invalidation is scheduled / batched (Action Scheduler, WP-Cron) — combine with `rocket_clean_*` calls in the cron handler.
    - Run **`wp-plugin-options-storage`** when 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.
    - **`.htaccess` rewrite 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_buffer` filter** for HTML output manipulation. Niche + dangerous; covered in `wp-rocket-cache-rejection-and-filters` with strong warnings.
    - **License / activation key handling.** Premium-specific; not integrator-facing.
    
    ## References
    
    - Plugin entry: [wp-content/plugins/wp-rocket/wp-rocket.php](wp-rocket.php) — version constants, header.
    - `rocket_clean_post`: [inc/common/purge.php:167](purge.php) — handles auto-draft / draft / nav_menu_item / attachment skips, fires `before_/after_rocket_clean_post`.
    - `rocket_clean_files`: [inc/functions/files.php:547](files.php) — `$run_actions` third arg controls whether `before_/after_rocket_clean_files` and per-URL `before_/after_rocket_clean_file` fire.
    - `rocket_clean_home`: [inc/functions/files.php:679](files.php).
    - `rocket_clean_domain`: [inc/functions/files.php:821](files.php).
    - `rocket_clean_term`: [inc/functions/files.php:924](files.php).
    - `rocket_clean_user`: [inc/functions/files.php:996](files.php).
    - `rocket_clean_cache_dir`: [inc/functions/files.php:1060](files.php).
    - `rocket_clean_minify`: [inc/functions/files.php:354](files.php).
    - WP Rocket plugin compatibility doc: [https://docs.wp-rocket.me/article/92-plugin-compatibility-with-wp-rocket](https://docs.wp-rocket.me/article/92-plugin-compatibility-with-wp-rocket).
    - Official documentation: <https://docs.wp-rocket.me/article/2-getting-started>
    

Comments (0)

Sign in to join the conversation.

No comments yet.

Reviews (0)

No reviews yet.

Related