WooCommerce 11.0 Caches Product Objects July 28 — Only Raw SQL Breaks Prices
WooCommerce 11.0 enables product object caching by default on July 28, 2026, but only for new stores — existing stores keep whatever setting they already have. The cache is in-memory and request-scoped, so it clears at the end of every request rather than holding prices for minutes. That narrows the tracking risk to one pattern: extensions that write price meta with raw SQL, bypassing the hooks that invalidate the cache. Where that happens, a purchase event can carry the pre-write price to GA4, Meta and Google Ads for the remainder of that request.
What Changes on July 28, and for Whom
The scope is narrower than the headline suggests, and the distinction decides whether you need to do anything at all.
WooCommerce 11.0 reaches general availability on July 28, 2026, and product object caching becomes the default for new stores. The word doing the work in that sentence is “new”. WooCommerce has been explicit: existing stores are left unchanged on upgrade, and if the toggle was off before, it stays off.
The feature lives at WooCommerce, Settings, Advanced, Features, under Cache Product Objects. Existing store owners who want the performance gain have to opt in deliberately, which is a more conservative rollout than platform releases usually get credit for.
The gain is real but modest. WooCommerce measured variable products loading roughly 9 to 12 percent faster on product pages, and bundle products processing 6 to 12 percent faster during checkout. A related variation-price change is more dramatic: on a product with 800 variations, get_variation_prices() fell from about 500ms to 40-50ms on cached requests.
One forward-looking note worth putting in your calendar rather than your inbox: WooCommerce intends to enable this for all stores, existing ones included, once adoption data supports it. No timeline has been set. So the audit below is work you’ll want done eventually regardless of what you run today.
WooCommerce 11.0 enables product object caching by default only for new stores, leaving every existing store’s setting untouched on upgrade.
The Cache Is Request-Scoped, Which Narrows Everything
Most of the alarm about this feature assumes a cache that outlives the page load. It doesn’t.
Here’s the thing that gets lost in the summaries: this is not a persistent object cache. It intercepts wc_get_product() calls and serves product objects from an in-memory store for the duration of a single request. The cache is non-persistent and clears after each request, with no manual management required.
That single design choice removes most of the theoretical risk. A price cannot be cached at nine o’clock and served wrong at nine-oh-five, because nothing survives between those two page loads. Repeated calls to wc_get_product() for the same ID inside one request return clones of the same cached instance, which is the intended behaviour and transparent to nearly all code.
So the failure mode requires a specific sequence, all inside one request: the product is loaded, its price is then changed by something that doesn’t invalidate the cache, and the product is read again. Three conditions, one request. That’s a much smaller target than “your tracking plugin will send stale prices”.
It’s also not zero, and checkout is precisely where all three conditions can line up.
You may be interested in: WooCommerce 11.0 Adds Checkout Recovery — Your Ad Platforms Won’t See It
The One Pattern That Actually Breaks
Raw SQL writes to price meta bypass every hook the cache depends on.
Cache invalidation here rides on standard WordPress and WooCommerce hooks. Write price meta through the normal channels and the cache is cleared for you. Write it with a direct database query and nothing fires — the cached product stays stale for the remainder of that request.
Concretely, the code to worry about writes to the _price, _regular_price or _sale_price meta keys using raw queries such as wpdb update or wpdb query, without calling clean_post_cache() afterwards. Extensions that retrieve products exclusively through wc_get_product() and the standard WooCommerce APIs are not affected at all.
Which extensions do this? Almost always the ones recalculating prices from something outside WooCommerce. A dynamic pricing plugin pulling live commodity rates and writing new prices in bulk is the archetype — one store owner raised exactly this case on the WooCommerce developer blog, running a precious-metals plugin that repriced against metal fluctuations. Bulk repricing tools, ERP sync bridges, and currency or margin engines fall in the same class, because writing thousands of rows through the meta API is slow and raw SQL is the obvious optimisation.
Translation: the plugins most likely to bypass the hooks are the ones whose whole purpose is changing prices. That’s an uncomfortable overlap.
The Three Safe Pricing Patterns
WooCommerce documented what’s cache-transparent, and the list is short enough to check against your code.
| Pattern | Mechanism | Cache-safe |
|---|---|---|
| Price filters (woocommerce_product_get_price and siblings) | Fire on every price read | Yes — cache-transparent |
| WordPress meta API (update_post_meta, add_post_meta, delete_post_meta) | WordPress fires invalidating action hooks after each call | Yes — automatic invalidation |
| Product setters plus save() (set_regular_price, set_sale_price) | Save path triggers meta hooks and calls clean_post_cache() | Yes — invalidates on save |
| Raw SQL writes to price meta (wpdb update, wpdb query) | No hooks fire | No — stale for the rest of the request |
Note the asymmetry in that table. The safe patterns are also the readable, maintainable, conventional ones. The unsafe pattern is the performance shortcut. That’s usually how data-quality bugs are distributed.
Only extensions writing price meta through raw SQL bypass cache invalidation, leaving a product stale for the remainder of that single request.
How a Stale Price Reaches GA4, Meta and Google Ads
The tracking consequence nobody covering this release has mentioned.
Every performance write-up on this feature stops at the page-load numbers. None of them follow the stale value into the measurement layer, which is where a wrong price stops being cosmetic.
If a purchase event is built from a product object read after an uninvalidated raw SQL write, the revenue figure it carries is the pre-write price. From there it propagates. GA4 receives a purchase event with understated or overstated revenue, and your reported return on ad spend is wrong by the same margin. Google Ads Enhanced Conversions receives an incorrect transaction amount, and value-based bidding optimises against a number that never existed.
Meta is the worst case, because the Conversions API compares values when deduplicating browser and server events for the same purchase. Send one value from the pixel and a different one from the server for the same order, and you risk the platform treating them as separate conversions rather than collapsing them — inflating conversion counts while corrupting value data.
None of that shows up as an error. Your order table holds the correct price, because the database write succeeded. Only the tracking layer carries the stale one, which means the discrepancy surfaces as a slow drift between platform-reported revenue and actual revenue.
You may be interested in: Enhanced Conversions Need the Right Hashed Fields From WooCommerce
Your Pre-Upgrade Audit
Twenty minutes of grep, and a reconciliation habit worth keeping afterwards.
Search your plugins and theme for raw writes to the three price meta keys. If nothing in your stack writes _price, _regular_price or _sale_price outside the meta API and product setters, you’re done — enable the cache and take the performance.
If something does, don’t disable the feature as a reflex. The correct fix is one line in the offending code: call clean_post_cache() after the write, or move the write to the meta API. Turning caching off to accommodate a plugin that bypasses WordPress conventions solves the symptom and keeps the bug.
Then reconcile. Take a week of purchase events and compare the revenue your platforms report against the order totals in your database. That check catches stale prices, and it also catches the half-dozen other ways revenue drifts — currency rounding, tax handling, refunds, failed events. Reconciliation against the order record is the only test that survives whatever the platform changes next.
This is why the Transmute Engine™ builds events from the order record server-side rather than from a product read at page-render time. The order total is the number the customer was actually charged, and it is not subject to any cache.
Key Takeaways
What to act on before Tuesday.
- New stores only: product object caching defaults on for fresh installs of 11.0; existing stores keep their current setting untouched.
- Request-scoped cache: it is in-memory and non-persistent, clearing after every request, so prices cannot go stale across page loads.
- One real risk: raw SQL writes to _price, _regular_price or _sale_price bypass invalidation and leave the object stale for that request.
- Dynamic pricing is the exposure: bulk repricing, ERP sync and commodity-linked pricing tools are the extensions most likely to use raw SQL.
- Fix the write, not the feature: call clean_post_cache() or move to the meta API rather than disabling caching to accommodate bad code.
Frequently Asked Questions
What store owners and extension authors are asking ahead of the release.
No. The default applies to new store installations only. If you upgrade an existing store to 11.0, whatever setting you already have is preserved, including off. You can enable it yourself under WooCommerce, Settings, Advanced, Features by toggling Cache Product Objects. WooCommerce has said it intends to extend the default to existing stores once adoption data supports it, but no timeline has been published.
Only in a narrow case. Because the cache is request-scoped, a stale read requires a price to be written and re-read inside the same request, with the write bypassing cache invalidation. That means raw SQL writes to price meta. If your dynamic pricing runs through the standard price filters, the meta API, or product setters, the cache stays correct and your tracking values do too.
Three. Modifying prices through the woocommerce_product_get_price, get_regular_price or get_sale_price filters, which fire on every read and are cache-transparent. Writing price meta with update_post_meta, add_post_meta or delete_post_meta, since WordPress fires invalidating action hooks after each call. And using product setters such as set_regular_price followed by save(), which triggers the same hooks and calls clean_post_cache().
Search your plugins and theme for raw database writes to the _price, _regular_price and _sale_price meta keys — typically through wpdb update or query calls. Anything writing those keys outside the three safe patterns is the code to review. Dynamic pricing extensions that recalculate from external inputs, such as live commodity rates, are the most common example worth checking.
References
- WooCommerce Developer Blog, “Product Object Caching Enabled by Default for New Stores in WooCommerce 11.0,” June 17, 2026. Read the announcement
- WooCommerce Developer Blog, “WooCommerce 11.0: What’s coming for developers,” July 13, 2026. Read the pre-release notes
- WooCommerce Developer Blog, “Experimental Product Object Caching in WooCommerce 10.5.” Read the advisory
- WooCommerce Developer Blog, “Variation prices caching improvements in WooCommerce 10.5.” See the benchmarks
- WP Dude, “WooCommerce 11.0 Enables Default Product Object Caching for New Stores,” 2026. Read the summary
If you’d rather your revenue numbers came from the order record than from a cached product read, see how server-side event capture works.