xSpeed Cache is officially live! Get 50% OFF during Launch Week — Lifetime starts at just $79Lifetime from $79 — 50% OFF, Launch Week! See Plans →

See Plans →
Features
xSpeed Hub Pricing Docs Blog Scan
Appearance
Get Plugin
All articles
CachingExclusionsTutorialWooCommerceWordPresscheck:D2platform:woocommerce

WordPress Cache Exclusions in 2026: Adding an Asterisk Makes the Rule Match Less

xSpeed Cache Team Updated Oct 4, 2026 10 min read
Cache exclusions that match what you mean, with the WordPress logo, xSpeed cover

Updated October 2026

WooCommerce’s own caching documentation, read on 2 October 2026, names exactly three pages that must stay dynamic: Cart, My Account, Checkout. LiteSpeed’s documentation warns on the same day that excluding one cookie which appears site-wide “effectively excludes your entire site from caching”. So the list of paths is the easy half.

The hard half is that the four exclusion fields do not match the same way, and nothing on the settings screen says so. A list of paths to paste is the guide you expect. Which field matches what string is the guide that decides whether your rule catches nothing or un-caches everything.

Quick Summary: Which Field Catches What

If you want to…Use this fieldWhy
Keep one page always dynamicExcluded URLsMatched against the path only, never the query string
Keep one visitor dynamicExcluded CookiesMatched against the cookie name only, never its value
Keep a bot or monitor dynamicBypass User AgentsCase-insensitive substring, no wildcards at all
Stop campaign tags duplicating a pageIgnored Query ParametersAn allow-list, matched on whole names

One rule governs the first three: a plain entry means “contains”, and adding *, ? or [ switches it to anchored whole-value matching. The fourth field inverts the logic entirely.

Four Fields, Three Matching Rules

Every field takes one pattern per line, and our Page Cache documentation lists 16 shipped URL exclusions covering /wp-admin/, /wp-json/, /feed/, sitemaps, /wp-login and the standard store pages. Three different matching rules are in play, and the differences are deliberate.

Pattern styleBehaviourExample
Plain textMatches anywhere in the value/cart also catches /cart/items and /foo/cart/bar
Glob (*, ?, [abc])Anchored, the whole value must match/cart/* catches /cart/items but not /foo/cart/bar
~ prefixRaw regular expression, unanchored~wp-.*\.php

Four exclusion fields mapped to the string each one is matched against: path, cookie name, user-agent header and parameter name

Excluded URLs and Excluded Cookies use that glob matcher. Bypass User Agents does not: it is a plain case-insensitive substring test, and class-glob-matcher.php in our published source gives the reason, that user-agent strings vary so wildly that anchoring them “rarely helps and confuses users”. Ignored Query Parameters goes the other way and matches whole names.

Why the Cart Default Has No Trailing Slash

Our shipped default is /cart, not /cart/ and not /cart/*. That is deliberate, and the reason is the contains rule above.

A bare /cart catches /cart, /cart/ and /cart/items together. Write /cart/ instead and a visitor landing on /cart with no slash gets a cached page. Write /cart/* and the pattern becomes anchored, so it no longer catches /cart itself, which is the page holding the basket.

An asterisk narrows an exclusion, it does not widen one. Everyone reads * as “and everything under here”. Here it means “and nothing outside here”.

Cookie matching keeps contains semantics for a separate reason, stated in the same file: the shipped defaults are prefixes of hash-suffixed real cookies, so comment_author has to catch comment_author_<hash>. Tightening that to an exact match would serve shared cached pages to commenters, and cached pages showing logged-in content is the fix guide for that symptom.

The Query Field Is an Allow-List, and It Runs First

The other three fields are deny-lists: an entry means “do not cache this”. Ignored Query Parameters is the opposite. It lists the keys that are safe to strip before the cache key is computed, so /post?utm_source=x and /post share one entry. The defaults cover utm_*, fbclid, gclid and friends.

The consequence catches people out. Any parameter not on that allow-list makes the request uncacheable. Reading Cache::should_cache() on 2 October 2026, the query gate runs before the URL gate, so /cart/?add-to-cart=12 is reported as a query-param bypass and never reaches the URL rule at all.

WooCommerce’s documentation recommends a Varnish rule matching ?add-to-cart=. You do not need its equivalent here, and could not write it in the URL field anyway: that field sees the path only. The source says why, that a visitor writes the query string, so /cart/?utm_source=/feed/ must not be able to talk a cart out of its hold. Two more properties:

  • Matching is whole-name, so an entry of ref matches ref and will not swallow preference.
  • xspeed_css and xspeed_nc can never be ignored by any entry, because our own measurement requests use them to ask for the page as it is before optimisation.

Where Your Rule Actually Runs: The Three-Layer Test

Here is the framework this article is for. Before trusting any exclusion, ask where it is enforced, because a cached page can be served by three different layers and only one of them runs your full rule list.

LayerRunsReads your settings from
Web server (nginx or Apache)Before PHP startsA generated config block
The advanced-cache.php drop-inBefore WordPress loadsRegexes baked in at save time
PHP Cache::should_cache()Full WordPress contextThe live settings

Three enforcement layers for a cache exclusion, showing which rule types each layer can see and where raw regex patterns drop out

The drop-in cannot read your settings, because WordPress is not loaded yet. So the cookie and user-agent lists are compiled into it when you save, and class-server-rules.php is explicit about why: before it existed, every cookie and user-agent entry “applied only while a page was cold”, meaning the settings screen said the rule was active and on a warm page it was not.

The limitation, stated plainly: this test tells you where a rule is enforced, not whether the pattern is right. A pattern matching nothing is enforced perfectly at all three layers.

Two things fall out of it. Raw ~ regex patterns are deliberately skipped at the web-server layer, because arbitrary user regex inside an nginx config is how you take down every site on the box, so those patterns are enforced by PHP only. And the arrangement is safe by design: xSpeed caps a generated server rule at 100 patterns and merges three session cookie names in as a floor, so that as the same file puts it, PHP remains the authority and a stale server config “can only ever cost speed, never correctness”.

Four Mistakes That Un-Cache More Than You Meant

  • Excluding a cookie that exists on every page. LiteSpeed’s own documentation warns that this “effectively excludes your entire site from caching”, and it is just as true here. woocommerce_recently_viewed is the trap: it sounds cart-related and it is set almost everywhere.
  • Writing *Googlebot* in the user-agent field. That field is a substring test, so the asterisks are literal characters and the entry matches nothing. Write Googlebot.
  • Pasting a LiteSpeed list unchanged. Per its documentation, LiteSpeed compares URI rules against REQUEST_URI and narrows them with ^ and $. Ours see the path and use glob syntax, so a pasted ^/cart is a literal caret. Prefix it with ~ to keep it a regex.
  • Excluding a page that is merely stale. Our own docs are blunt about this one: exclusions are “a safety tool, not a tuning knob”, and adding /blog because one post looked stale un-caches your entire blog. Purge first.

Confirming the Rule Fired

Start with the free xSpeed Scan. It needs no account and no plugin, and the check to read is D2, “Page served from cache”, confirmed against a live scan on rubric 2026.10.1 on 2 October 2026. Point it at the page you excluded and a failing D2 is the correct result: nothing is serving that page from a cache. Point it at an ordinary post and D2 should pass. Two scans settle it.

Run the free scan on your own site: xspeedcache.com/scan/

If you would rather check by hand, read the x-xspeed-cache response header. BYPASS means the request was deliberately never cached, HIT (nginx) means the server answered without starting PHP, and MISS means WordPress built the page and saved it.

One trap our documentation names. Only GET requests are served from cache, so curl -I sends a HEAD and reports BYPASS every time, whatever your settings say. Send a real GET instead.

curl -s -o /dev/null -D - https://example.com/cart/ | grep -i x-xspeed-cache

Understanding cache HITs and MISSes covers every value, and checking whether caching is actually working covers the wider question of proving a cache is live.

Running Exclusions Across Twenty-Five Client Sites

One store is four fields on one screen. Twenty-five stores is the per-site drift: one has an old ^/cart pasted from a previous plugin, another excluded /blog during an incident two years ago and nobody removed it.

xSpeed Cache is ours, built by WPDeveloper, and every exclusion field above is in the free tier, confirmed against Free vs Pro. A direct wordpress.org Plugin API query on 2 October 2026 returned xSpeed 1.3.7, rated 5.0 from 16 ratings.

For fleets, xSpeed Hub audits one exclusion list across sites instead of four fields twenty-five times. For one store, start with the WooCommerce setup and caching WooCommerce without breaking checkout.

Frequently Asked Questions

I added /cart/* and my cart page is still being cached. Why?

Because * anchors the pattern. /cart/* requires something after /cart/, so /cart itself no longer matches. Use the bare /cart.

I pasted an exclusion list from another plugin and nothing changed. What went wrong?

Those boxes commonly take regular expressions or their own anchors, as LiteSpeed’s documented ^ and $ do. Here a plain line is a literal substring, so prefix anything meant as a regex with ~.

The cookie you chose is set on every page. Check it in your browser’s developer tools against a page that should be cacheable, and pick a cookie that only appears for the visitors you meant.

My rule works on a cold page and not on a warm one. Is that a bug?

That was a real bug, and it is fixed. The fast path answers before WordPress loads, so cookie and user-agent rules are compiled into the drop-in when you save your settings. Re-save the panel to force that rebuild.

curl -I reports BYPASS on every page, even ones I did not exclude. What am I missing?

curl -I sends a HEAD request, and only GET requests are served from cache. Use curl -s -o /dev/null -D - instead.

Which other plugins handle exclusions well?

LiteSpeed Cache has the most granular controls, including exclusion by role and by category, and W3 Total Cache exposes more of the underlying rules. WP Fastest Cache is the simplest if you only need a path list. All three are reasonable choices; xSpeed is ours and our 80-capability comparison sets them side by side.

Do I need to exclude the WordPress login or admin pages?

No. Those are in the shipped defaults, and the drop-in also skips any request whose path contains /wp-admin or /wp-login before it looks at your settings.

Should I exclude logged-in users?

They are already excluded. xSpeed serves cached pages to logged-out visitors only, and three session cookie names are a permanent floor that an empty or broken setting cannot weaken.

Can I exclude a single product without a site-wide pattern?

Yes, from that product’s own editor screen. It applies to singular requests only, so archives and taxonomy pages keep the global policy.

Is there a limit to how many patterns I can add?

The server layer takes 100, and anything longer than 120 characters is left to PHP. PHP has no practical limit, but every pattern is a page rebuilt on each visit.

Conclusion: Your Exclusion Checklist

Your goalFieldEntry to write
One dynamic pageExcluded URLs/cart
One dynamic section, nothing elseExcluded URLs/private/*
One dynamic visitor typeExcluded Cookiesthe cookie name, no wildcards
One dynamic botBypass User Agentsa plain substring
A regex from another pluginany of the first threeprefix it with ~

What to do this week: scan the page you believe is excluded and read D2. Re-save the Page Cache panel so the drop-in is rebuilt. Delete any pattern you cannot explain. Replace pasted ^ and $ patterns with a ~ prefix or plain text. If you are running more than five sites, xSpeed Cache is free to start and Pro is $29/yr at the founding price with a 14-day money-back guarantee.

Got an exclusion that behaves in a way this article does not explain? The troubleshooting guide is the next place to look.

Written by

xSpeed Cache Team

Try xSpeed Cache

Make your site load in milliseconds.

One switch. Zero bloat. Always free to start.