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!
- MilliRules Documentation — Complete rules engine reference
- Conditions Reference
- Actions Reference
- Cache Flags — Partner feature to rules