WP Rocket is the most popular WordPress caching plugin for a reason – it works well out of the box. But if you manage client sites, run CI/CD deployments, or need conditional caching logic, the plugin’s UI only gets you so far.
This post is the code-first companion to my WP Rocket settings guide. It covers the filters, WP-CLI commands, deployment scripts, and debugging techniques that I use on production sites. If you’re comfortable with PHP and a terminal, this is for you.
Jump to the Filters & Hooks reference
Where to Put Your Code
Before adding any WP Rocket snippet, decide where it lives. The wrong choice can cost you hours after a theme update or migration.
Option 1: Child Theme functions.php
Quick for testing. Drop a snippet into your child theme’s functions.php and it runs immediately. The downside: switching themes kills every customization.
Option 2: MU-Plugin (Recommended)
Create a file in wp-content/mu-plugins/ and it loads automatically on every request. No activation needed, survives theme switches, and loads before regular plugins.
<?php
/**
* Plugin Name: WP Rocket Custom Filters
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
// Always check that WP Rocket functions exist
if ( function_exists( 'get_rocket_option' ) ) {
// Your filters go here
}MU-plugins load in alphabetical order, so prefix the filename if load order matters (e.g., 00-wp-rocket-custom.php).
Option 3: Code Snippets Plugin
If you prefer a GUI, the free Code Snippets plugin lets you add PHP snippets from the dashboard. Each snippet can be toggled on and off without touching files.
Always wrap WP Rocket function calls in function_exists() checks. If the plugin is deactivated or removed, your site won’t crash with a fatal error.
The pre_get_rocket_option Filter Family
WP Rocket stores its settings in a single options array. The pre_get_rocket_option_{option_name} filter lets you override any setting in PHP before WP Rocket reads it. This is the most flexible tool in the developer toolkit.
Return a truthy value to enable a feature, or 0 to disable it:
// Force-enable Delay JS on every page
add_filter( 'pre_get_rocket_option_delay_js', '__return_true' );
// Force-disable minify CSS
add_filter( 'pre_get_rocket_option_minify_css', '__return_zero' );You can also use conditional logic. Here’s a real-world example that disables Remove Unused CSS on WooCommerce pages, where dynamic styles often get stripped incorrectly:
add_filter( 'pre_get_rocket_option_remove_unused_css', function( $value ) {
if ( function_exists( 'is_woocommerce' ) && is_woocommerce() ) {
return 0;
}
return $value;
} );Environment-Aware Settings
This is a game changer for agencies. Use wp_get_environment_type() (available since WordPress 5.5) to apply different WP Rocket settings on staging vs. production:
add_filter( 'pre_get_rocket_option_minify_css', function( $value ) {
// Disable CSS minification on staging for easier debugging
if ( wp_get_environment_type() === 'staging' ) {
return 0;
}
return $value;
} );
add_filter( 'pre_get_rocket_option_minify_js', function( $value ) {
if ( wp_get_environment_type() === 'staging' ) {
return 0;
}
return $value;
} );Set the environment type in wp-config.php:
define( 'WP_ENVIRONMENT_TYPE', 'staging' ); // 'production', 'staging', 'development', 'local'Key Filters & Hooks Reference
These are the filters I reach for most often. Each one includes a practical code example you can drop into your mu-plugin.
rocket_delay_js_exclusions
Exclude specific scripts from the Delay JavaScript Execution feature. This is the filter you’ll use when a slider, form, or above-the-fold script breaks because it was delayed.
add_filter( 'rocket_delay_js_exclusions', function( $exclusions ) {
// Exclude Swiper slider - it must run immediately for above-the-fold carousels
$exclusions[] = 'swiper-bundle(.*).js';
// Exclude Google Tag Manager
$exclusions[] = 'googletagmanager.com/gtm.js';
// Exclude a custom inline script by its content
$exclusions[] = 'initHeroAnimation';
return $exclusions;
} );I wrote a dedicated post about this filter with more examples: Exclude Scripts from WP Rocket’s Load JS Deferred.
rocket_exclude_js
Exclude JavaScript files from minification and combining. Use this for vendor scripts that are already minified or scripts that break when their load order changes.
add_filter( 'rocket_exclude_js', function( $excluded_js ) {
// Exclude an already-minified vendor bundle
$excluded_js[] = '/wp-content/themes/your-theme/js/vendor.min.js';
// Exclude a payment gateway script that breaks when combined
$excluded_js[] = '/wp-content/plugins/payment-plugin/assets/checkout.js';
return $excluded_js;
} );rocket_exclude_css
Same concept, but for CSS files. Useful for dynamically generated stylesheets or critical CSS that must load in a specific order.
add_filter( 'rocket_exclude_css', function( $excluded_css ) {
// Exclude a dynamically generated stylesheet (e.g., from a page builder)
$excluded_css[] = '/wp-content/plugins/elementor/assets/css/custom-frontend.css';
// Exclude a stylesheet loaded via a CDN with a dynamic version parameter
$excluded_css[] = 'fonts.googleapis.com/css';
return $excluded_css;
} );rocket_rucss_skip_styles_with_attr
Skip specific <style> blocks from the Remove Unused CSS engine based on their HTML attributes. Useful when a plugin injects inline styles that RUCSS incorrectly strips.
add_filter( 'rocket_rucss_skip_styles_with_attr', function( $attributes ) {
// Skip any style tag with data-no-optimize attribute
$attributes[] = 'data-no-optimize';
// Skip styles injected by a specific plugin
$attributes[] = 'id="my-plugin-inline-css"';
return $attributes;
} );rocket_preload_exclude_urls
Prevent specific URLs from being preloaded. WP Rocket’s preload crawler visits every URL from your sitemap – this filter lets you trim URLs that don’t need caching.
add_filter( 'rocket_preload_exclude_urls', function( $excluded_urls ) {
// Exclude paginated archive pages beyond page 5
$excluded_urls[] = '/page/[5-9][0-9]*/';
$excluded_urls[] = '/page/[0-9]{3,}/';
// Exclude filtered product pages
$excluded_urls[] = '/shop/?filter(.*)';
return $excluded_urls;
} );rocket_override_donotcachepage
Force WP Rocket to cache a page even when another plugin has set the DONOTCACHEPAGE constant. Membership and access-control plugins often set this constant on pages that are actually public.
// Force caching on all pages, ignoring DONOTCACHEPAGE from other plugins
add_filter( 'rocket_override_donotcachepage', '__return_true', PHP_INT_MAX );Use this filter carefully. If a page serves personalized content per user, forcing the cache will show the wrong content to visitors.
rocket_htaccess_mod_rewrite
Modify the rewrite rules that WP Rocket adds to your .htaccess file. This is advanced – use it to add custom rules for WebP serving or specific caching headers.
add_filter( 'rocket_htaccess_mod_rewrite', function( $rules ) {
// Add a custom header for cached WebP images
$custom_rule = '# Serve WebP with correct content type' . PHP_EOL;
$custom_rule .= '<IfModule mod_mime.c>' . PHP_EOL;
$custom_rule .= ' AddType image/webp .webp' . PHP_EOL;
$custom_rule .= '</IfModule>' . PHP_EOL;
return $custom_rule . $rules;
} );rocket_cache_query_strings
By default, WP Rocket ignores query strings and serves the same cached page regardless of URL parameters. This filter tells WP Rocket to create separate cache files for specific query strings.
add_filter( 'rocket_cache_query_strings', function( $query_strings ) {
// Cache product filter pages separately
$query_strings[] = 'color';
$query_strings[] = 'size';
$query_strings[] = 'sort_by';
return $query_strings;
} );Each unique combination of these query string values gets its own cached file. Don’t add high-cardinality parameters (like user IDs or timestamps) or you’ll fill your cache directory fast.
rocket_head_items
Add custom elements to the <head> section with explicit priority control. Introduced in WP Rocket 3.17, this filter gives you fine-grained control over element ordering.
add_filter( 'rocket_head_items', function( $items ) {
// Add a preconnect hint for a third-party font CDN (priority 10 = early)
$items[] = [
'content' => '<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>',
'priority' => 10,
];
// Add a DNS prefetch for an analytics domain (priority 15)
$items[] = [
'content' => '<link rel="dns-prefetch" href="https://www.google-analytics.com">',
'priority' => 15,
];
return $items;
} );Priority values follow a convention: preconnect at 10, preload at 30, styles and scripts at 50.
Programmatic Configuration with update_rocket_option()
The update_rocket_option() function writes directly to WP Rocket’s settings in the database. Where pre_get_rocket_option overrides settings at runtime, update_rocket_option() changes them permanently.
This is useful for agency onboarding scripts that configure WP Rocket identically across multiple client sites:
// Run once via WP-CLI: wp eval-file setup-rocket.php
if ( ! function_exists( 'update_rocket_option' ) ) {
echo 'WP Rocket is not active.';
exit;
}
// Standard agency baseline
update_rocket_option( 'minify_css', 1 );
update_rocket_option( 'minify_js', 1 );
update_rocket_option( 'delay_js', 1 );
update_rocket_option( 'lazyload', 1 );
update_rocket_option( 'remove_unused_css', 1 );
update_rocket_option( 'preload', 1 );
update_rocket_option( 'cache_mobile', 1 );
update_rocket_option( 'do_caching_mobile_files', 1 );
// Clear cache after changing settings
if ( function_exists( 'rocket_clean_domain' ) ) {
rocket_clean_domain();
}
echo 'WP Rocket configured successfully.';Run it on each site:
wp eval-file setup-rocket.phpAlways call rocket_clean_domain() after programmatic changes. Otherwise the old cached files will still be served with the previous settings.
WP Rocket WP-CLI Commands
WP Rocket ships with a WP-CLI package that makes cache management scriptable. These are the commands I use in deployment scripts and cron jobs.
| Command | What It Does |
|---|---|
wp rocket clean --confirm | Purge the entire cache without a confirmation prompt |
wp rocket activate-cache | Enable page caching and set WP_CACHE to true in wp-config.php |
wp rocket deactivate-cache | Disable page caching and set WP_CACHE to false |
wp rocket regenerate --file=advanced-cache.php | Regenerate the advanced-cache.php drop-in |
wp rocket regenerate --file=config | Regenerate the config file in wp-rocket-config/ |
wp rocket preload | Trigger the cache preload crawler |
Quick Cache Clear After Content Updates
If you have a custom plugin that publishes content via code, clear the cache for that specific post:
// After programmatically updating a post
wp_update_post( $post_data );
// Clear only that post's cache
if ( function_exists( 'rocket_clean_post' ) ) {
rocket_clean_post( $post_id );
}CI/CD & Deployment Pitfalls
This is where most developers hit problems with WP Rocket. The plugin relies on two generated files that live outside the plugins directory. If your deployment pipeline doesn’t account for them, caching silently stops working.
The Two Critical Files
wp-content/advanced-cache.php– The drop-in that WordPress loads before any plugin. If this file is missing or stale, page caching is completely disabled.wp-content/wp-rocket-config/{domain}.php– The config file that contains your site’s caching rules. Without it, WP Rocket can’t generate cached files.
The Problem
In a typical Git-based deployment (Capistrano, Deployer, GitHub Actions), the wp-content directory is replaced or symlinked fresh on each deploy. This wipes advanced-cache.php and the wp-rocket-config/ folder. WP Rocket notices the missing files and disables itself.
The Fix: Post-Deploy Script
Add these WP-CLI commands to your deployment script, after the code is in place:
#!/bin/bash
# post-deploy.sh - Run after code deployment
# Regenerate the advanced-cache.php drop-in
wp rocket regenerate --file=advanced-cache.php
# Regenerate the site config
wp rocket regenerate --file=config
# Re-enable caching (sets WP_CACHE constant)
wp rocket activate-cache
# Clear stale cache from the previous deployment
wp rocket clean --confirm
# Preload the cache so the first visitor hits a warm cache
wp rocket preloadBedrock / Composer Setups
If you use Bedrock, the advanced-cache.php path differs because wp-content is mapped to app/. WP Rocket handles this automatically during activation, but after a deployment you need to regenerate:
wp rocket regenerate --file=advanced-cache.php --path=/srv/www/your-site/current/web/wpStaging vs. Production Config
Combine the pre_get_rocket_option filters from the previous section with environment detection. This way, a single codebase works correctly on both staging and production:
// In your mu-plugin
add_filter( 'pre_get_rocket_option_minify_css', 'savvy_staging_disable_optimization' );
add_filter( 'pre_get_rocket_option_minify_js', 'savvy_staging_disable_optimization' );
add_filter( 'pre_get_rocket_option_remove_unused_css', 'savvy_staging_disable_optimization' );
add_filter( 'pre_get_rocket_option_delay_js', 'savvy_staging_disable_optimization' );
function savvy_staging_disable_optimization( $value ) {
if ( wp_get_environment_type() !== 'production' ) {
return 0;
}
return $value;
}This keeps all optimizations off on staging and development, making debugging much easier while keeping production fully optimized.
Debugging WP Rocket
When pages aren’t being cached or optimizations aren’t applying, here’s how to figure out what’s happening.
1. Check the HTML Source
View the page source (Ctrl+U / Cmd+U) and scroll to the very bottom. WP Rocket adds an HTML comment when a page is served from cache:
<!-- This website is like a rocket, isn't it? Performance optimized by WP Rocket. -->
<!-- Last modified: 2026-03-19 12:34:56 -->If this comment is missing, the page is not cached. If the timestamp doesn’t change between refreshes, the cache is working.
2. Enable WP_ROCKET_DEBUG
Add this to your wp-config.php to enable WP Rocket’s debug logging:
define( 'WP_ROCKET_DEBUG', true );This activates the internal logger. Logs go to wp-content/wp-rocket-config/. Remember to disable it on production – the logger classes add overhead when enabled.
3. The DONOTCACHEPAGE Detective Work
The most common reason a page isn’t cached: another plugin or theme is setting DONOTCACHEPAGE. To find the culprit, add this temporary snippet:
add_action( 'template_redirect', function() {
if ( defined( 'DONOTCACHEPAGE' ) && DONOTCACHEPAGE ) {
error_log( 'DONOTCACHEPAGE is set. Backtrace: ' . wp_debug_backtrace_summary() );
}
}, PHP_INT_MAX );Check your debug log (wp-content/debug.log) and the backtrace will show you exactly which plugin or function set the constant.
4. “Why Isn’t My Page Cached?” Checklist
Run through this list when troubleshooting:
- Is the user logged in? Logged-in users get uncached pages by default.
- Is
DONOTCACHEPAGEbeing set? Use the snippet above. - Does
advanced-cache.phpexist and contain WP Rocket code? Check withhead -5 wp-content/advanced-cache.php. - Is
WP_CACHEset totrueinwp-config.php? - Does the URL match a pattern in Advanced Rules > Never Cache URLs?
- Is a cookie-based exclusion active? Check the Never Cache Cookies setting.
- Does the cache directory have correct write permissions? WP Rocket needs to write to
wp-content/cache/.
Dynamic Content & WooCommerce Gotchas
Full-page caching and dynamic content are natural enemies. When WP Rocket caches a page, every visitor sees the same HTML. If your page shows user-specific data through PHP, those visitors will see stale or wrong content.
The Rule: PHP for Structure, AJAX for Personalization
Any content that changes per user (cart count, wishlist, recently viewed products, logged-in greetings) must load via JavaScript/AJAX after the cached page loads. If it’s rendered in PHP, WP Rocket will cache the first visitor’s version and serve it to everyone.
WooCommerce: get_refreshed_fragments
WooCommerce uses an AJAX endpoint called wc-ajax=get_refreshed_fragments to update the mini cart after the page loads. WP Rocket optimizes this by caching the fragments response when the cart is empty.
If your mini cart shows incorrect counts or doesn’t update, disable the optimization:
add_filter( 'pre_get_rocket_option_cache_wc_ajax', '__return_zero' );Cache Purging on Checkout
When a WooCommerce order completes, WP Rocket clears the cache for every product in the order and its associated categories. On stores with products in many categories, this can slow down the checkout process itself.
If you notice slow checkouts, disable the automatic purge and handle it manually via a scheduled event:
// Disable automatic cache clearing on WooCommerce status changes
add_filter( 'rocket_post_invalidation_wc_product', '__return_false' );
// Schedule a single bulk cache clear instead
add_action( 'woocommerce_order_status_completed', function( $order_id ) {
if ( ! wp_next_scheduled( 'savvy_delayed_cache_clear' ) ) {
wp_schedule_single_event( time() + 300, 'savvy_delayed_cache_clear' );
}
} );
add_action( 'savvy_delayed_cache_clear', function() {
if ( function_exists( 'rocket_clean_domain' ) ) {
rocket_clean_domain();
}
} );Performance Monitoring with Code
WP Rocket fires several action hooks during cache operations. You can use them to monitor cache behavior and catch issues before users notice.
Log Cache Invalidation Events
If your cache seems to clear too often, log every invalidation event to find the cause:
add_action( 'rocket_clean_domain', function() {
error_log( '[WP Rocket] Full domain cache cleared. Backtrace: ' . wp_debug_backtrace_summary() );
} );
add_action( 'rocket_clean_post', function( $post_id ) {
$title = get_the_title( $post_id );
error_log( "[WP Rocket] Cache cleared for post #{$post_id}: {$title}" );
} );Review wp-content/debug.log to identify which plugin, cron job, or user action is purging the cache. Frequent full-domain clears are a red flag – they force WP Rocket to rebuild the entire cache from scratch.
Monitor Preload Crawl Progress
After clearing the cache, WP Rocket’s preload crawler rebuilds it by visiting each URL. On large sites this can take hours. Track the queue:
# Check how many URLs are in the preload queue
wp db query "SELECT COUNT(*) as pending FROM $(wp db prefix)wpr_rocket_cache WHERE status = 'pending'" --skip-column-namesIf you notice the preload queue never reaches zero, check for redirect loops, password-protected pages, or URLs that return non-200 status codes. These stall the crawler and prevent other URLs from being preloaded.
FAQs
Common questions about using WP Rocket programmatically:
rocket_cache_reject_uri filter to exclude the post type's URL pattern. For example, if your CPT slug is portfolio, add:add_filter( 'rocket_cache_reject_uri', function( $uris ) {
$uris[] = '/portfolio/(.*)';
return $uris;
} );This prevents WP Rocket from caching any URL that starts with /portfolio/.rocket_clean_post( $post_id ) to clear a specific post's cache, or rocket_clean_domain() to purge the entire site. Always wrap the call in function_exists() so it doesn't break if WP Rocket is deactivated. Place the call inside your AJAX handler callback after the data has been updated.rocket_cache_reject_uri filter:$uris[] = '/wp-json/my-plugin/v1/(.*)';data-no-optimize="1" attribute to your <script> tag. WP Rocket respects this attribute and will skip the script during minification, combining, and delay. For example:<script data-no-optimize="1">myCode();</script>This works for both inline and external scripts.pre_get_rocket_option_{option} filter combined with wp_get_environment_type(). Set WP_ENVIRONMENT_TYPE in your wp-config.php for each environment, then conditionally return 0 for features you want disabled on staging. This approach keeps a single codebase working correctly across environments.advanced-cache.php and the config in wp-rocket-config/. If your deployment replaces or clears wp-content, these files are lost and caching stops. Fix it by running these commands in your post-deploy script:wp rocket regenerate --file=advanced-cache.php
wp rocket regenerate --file=configSummary
WP Rocket’s UI covers the basics, but the real power is in its filters and CLI tools. The pre_get_rocket_option filter family alone lets you conditionally control every setting based on page type, user role, or environment. Pair that with WP-CLI commands in your deployment scripts, and you have a caching setup that works reliably across staging, production, and CI/CD pipelines.
I keep a single mu-plugin on most client sites with 5-10 WP Rocket filters. It takes 15 minutes to set up and saves hours of UI clicking and debugging down the road. If you’re managing more than one WordPress site, this approach is worth adopting.
For the complete UI walkthrough of every WP Rocket setting, check my full WP Rocket guide.

