Rule Examples

Practical MilliCache rule examples for common scenarios. All examples use the MilliRules fluent API.

Setup#Copied!

Add rules early in your plugin or theme:

 1use MilliCacheDepsMilliRulesRules;
 2
 3// You do not need to wrap them into an add_action() call - rules register themselves
 4// Instead use ->on() to hook into WordPress actions if needed

Example 1: Different TTL by Content Type#Copied!

Cache news for 15 minutes, documentation for 1 week:

 1// Short TTL for news (bootstrap phase - runs before WordPress)
 2Rules::create( 'mysite:news-ttl', 'php' )
 3    ->order( 10 )
 4    ->when()
 5        ->request_url( '/news/*' )
 6    ->then()
 7        ->set_ttl( 900 )  // 15 minutes
 8    ->register();
 9
10// Long TTL for documentation
11Rules::create( 'mysite:docs-ttl', 'php' )
12    ->order( 10 )
13    ->when()
14        ->request_url( '/docs/*' )
15    ->then()
16        ->set_ttl( 604800 )  // 1 week
17    ->register();

Example 2: WooCommerce Cart/Checkout Bypass#Copied!

Never cache cart, checkout, or account pages:

 1// Bootstrap phase for early bypass
 2Rules::create( 'mysite:woo-no-cache', 'php' )
 3    ->order( 5 )
 4    ->when_any()
 5        ->request_url( '*/cart/*' )
 6        ->request_url( '*/checkout/*' )
 7        ->request_url( '*/my-account/*' )
 8        ->cookie( 'woocommerce_*' )
 9    ->then()
10        ->do_cache( false, 'WooCommerce dynamic page' )
11    ->register();

Example 3: Membership Site Caching#Copied!

Cache for guests, bypass for active members:

 1// WordPress phase - needs user context
 2Rules::create( 'mysite:members-no-cache', 'wp' )
 3    ->on( 'template_redirect', 25 )
 4    ->order( 10 )
 5    ->when()
 6        ->is_user_logged_in()
 7        ->custom( 'is-active-member', function() {
 8            // Check your membership plugin
 9            return function_exists( 'hasMembershipLevel' )
10                && hasMembershipLevel();
11        } )
12    ->then()
13        ->do_cache( false, 'Active member' )
14    ->register();

Example 4: A/B Testing Support#Copied!

Different cache entries for A/B test variants:

 1// Add a test variant as a flag
 2Rules::create( 'mysite:ab-test-flag', 'wp' )
 3    ->on( 'template_redirect', 25 )
 4    ->order( 10 )
 5    ->when()
 6        ->cookie( 'ab_variant' )
 7    ->then()
 8        ->add_flag( 'ab:' . ( $_COOKIE['ab_variant'] ?? 'control' ) )
 9    ->register();

Example 5: Preview and Draft Bypass#Copied!

Never cache previews or drafts:

 1Rules::create( 'mysite:no-preview', 'php' )
 2    ->order( 5 )
 3    ->when_any()
 4        ->request_param( 'preview', 'true' )
 5        ->request_param( 'draft', '1' )
 6        ->request_param( 'p' )  // Post preview by ID
 7    ->then()
 8        ->do_cache( false, 'Preview/draft mode' )
 9    ->register();

Example 6: Block-Based Rules#Copied!

Use has_block() to target pages containing specific Gutenberg blocks:

 1// Flag pages with a pricing table block
 2Rules::create( 'mysite:pricing-flag', 'wp' )
 3    ->on( 'template_redirect', 25 )
 4    ->order( 10 )
 5    ->when()
 6        ->is_singular()
 7        ->has_block( 'acme/pricing-table' )
 8    ->then()
 9        ->add_flag( 'block:pricing' )
10    ->register();
11
12// Short TTL for pages with live data blocks
13Rules::create( 'mysite:live-data-ttl', 'wp' )
14    ->on( 'template_redirect', 25 )
15    ->order( 10 )
16    ->when()
17        ->is_singular()
18        ->has_block( 'acme/live-stock-ticker' )
19    ->then()
20        ->set_ttl( 60 )  // 1 minute for live data
21        ->add_flag( 'live-data' )
22    ->register();

Example 7: Term-Based Rules#Copied!

Use has_term() for taxonomy-based caching decisions:

 1// Flag seasonal products
 2Rules::create( 'mysite:seasonal-flag', 'wp' )
 3    ->on( 'template_redirect', 25 )
 4    ->order( 10 )
 5    ->when()
 6        ->is_singular( 'product' )
 7        ->has_term( 'seasonal', 'product_cat' )
 8    ->then()
 9        ->add_flag( 'promo:seasonal' )
10    ->register();
11
12// Short TTL for featured content
13Rules::create( 'mysite:featured-ttl', 'wp' )
14    ->on( 'template_redirect', 25 )
15    ->order( 10 )
16    ->when()
17        ->is_singular( 'post' )
18        ->has_term( 'featured', 'post_tag' )
19    ->then()
20        ->set_ttl( 1800 )  // 30 minutes
21        ->add_flag( 'featured' )
22    ->register();

Example 8: Conditional TTL by Post Meta#Copied!

Short TTL for "breaking news" posts:

 1Rules::create( 'mysite:breaking-news-ttl', 'wp' )
 2    ->on( 'template_redirect', 25 )
 3    ->order( 10 )
 4    ->when()
 5        ->is_singular( 'post' )
 6        ->custom( 'is-breaking', function() {
 7            return get_post_meta( get_the_ID(), 'breaking_news', true );
 8        } )
 9    ->then()
10        ->set_ttl( 300 )  // 5 minutes for breaking news
11        ->add_flag( 'breaking' )
12    ->register();

Example 9: Geolocation-Based Caching#Copied!

Tag cache entries by country for geo-targeted content:

 1Rules::create( 'mysite:geo-flag', 'php' )
 2    ->order( 10 )
 3    ->when()
 4        ->request_header( 'CF-IPCountry' )  // Cloudflare header
 5    ->then()
 6        ->custom_action( function() {
 7            $country = $_SERVER['HTTP_CF_IPCOUNTRY'] ?? 'XX';
 8            millicache_add_flag( 'geo:' . strtolower( $country ) );
 9        } )
10    ->register();

Example 10: API Rate Limiting Support#Copied!

Short TTL for API responses:

 1Rules::create( 'mysite:api-ttl', 'php' )
 2    ->order( 10 )
 3    ->when()
 4        ->request_url( '/api/*' )
 5        ->request_method( 'GET' )
 6    ->then()
 7        ->set_ttl( 60 )      // 1 minute
 8        ->set_grace( 300 )   // 5 minute grace
 9    ->register();

Example 11: Mobile vs Desktop Caching#Copied!

Separate cache entries for mobile and desktop:

 1Rules::create( 'mysite:mobile-flag', 'php' )
 2    ->order( 10 )
 3    ->when()
 4        ->custom( 'is-mobile', function() {
 5            $ua = $_SERVER['HTTP_USER_AGENT'] ?? '';
 6            return preg_match( '/Mobile|Android|iPhone/i', $ua );
 7        } )
 8    ->then()
 9        ->custom_action( function() {
10            millicache_add_flag( 'device:mobile' );
11        } )
12    ->register();
13
14Rules::create( 'mysite:desktop-flag', 'php' )
15    ->order( 10 )
16    ->when()
17        ->custom( 'is-desktop', function() {
18            $ua = $_SERVER['HTTP_USER_AGENT'] ?? '';
19            return ! preg_match( '/Mobile|Android|iPhone/i', $ua );
20        } )
21    ->then()
22        ->custom_action( function() {
23            millicache_add_flag( 'device:desktop' );
24        } )
25    ->register();

Example 12: Clear Cache on External Event#Copied!

Clear product cache when inventory system updates:

 1Rules::create( 'mysite:inventory-clear', 'wp' )
 2    ->on( 'my_inventory_updated', 10 )  // Your custom hook
 3    ->when()
 4        ->custom( 'always', fn() => true )
 5    ->then()
 6        ->clear_cache( [ 'product:*', 'woo:sale' ] )
 7    ->register();

Compound Conditions#Copied!

Combine conditions with AND, OR, and NOT logic:

 1// AND (default) - all conditions must match
 2Rules::create( 'mysite:all-match', 'php' )
 3    ->when()
 4        ->request_method( 'GET' )
 5        ->request_url( '/shop/*' )
 6        ->cookie( 'currency', 'EUR' )
 7    ->then()
 8        // Only runs if ALL conditions match
 9        ->add_flag( 'shop:eur' )
10    ->register();
11
12// OR - any condition can match
13Rules::create( 'mysite:any-match', 'php' )
14    ->when_any()
15        ->request_url( '*/cart/*' )
16        ->request_url( '*/checkout/*' )
17        ->request_url( '*/account/*' )
18    ->then()
19        // Runs if ANY condition matches
20        ->do_cache( false, 'Dynamic page' )
21    ->register();
22
23// NOT - none of the conditions should match
24Rules::create( 'mysite:none-match', 'php' )
25    ->when_none()
26        ->request_method( 'GET' )
27        ->request_method( 'HEAD' )
28    ->then()
29        // Runs if NEITHER GET nor HEAD
30        ->do_cache( false, 'Non-cacheable method' )
31    ->register();

Tips#Copied!

Use Descriptive Rule IDs#Copied!

 1// Good - namespace:purpose
 2Rules::create( 'mysite:woo-cart-bypass', 'php' )
 3
 4// Avoid - generic
 5Rules::create( 'rule1', 'php' )

Choose the Right Phase#Copied!

Use Bootstrap (php) when... Use WordPress (wp) when...
Checking URL patterns Checking user roles
Checking cookies/headers Checking post meta
Setting TTL by path Checking template
Early bypass decisions Adding content-based flags

Keep Bootstrap Rules Simple#Copied!

Bootstrap rules run before WordPress, so keep them fast:

 1// Good - simple string match
 2->when()->request_url( '/api/*' )
 3
 4// Avoid in bootstrap - complex logic
 5->when()->custom( 'complex', function() {
 6    // Loading files, database, etc. defeats the purpose
 7} )

Learn More#Copied!