WooCommerce 10.5 hides something worth having in the Experimental tab: WooCommerce product object caching. Anyone who has debugged a store with 50 plugins running knows the problem it solves. I have watched checkout pages sit there for seconds because one badly written extension kept reloading the same product object inside a loop and firing the same query over and over.
The change is in how wc_get_product() handles data across a single request. Product instances now stay in memory, which is WooCommerce taking a real swing at the N+1 problem that has followed complex stores around for years.
Why WooCommerce product object caching matters
Before this, most calls to wc_get_product() sent WooCommerce back to the datastore. WordPress does its own internal caching, but rebuilding a full WC_Product object, with its meta, variations and attributes, is not cheap. On a cart page or a variable product page with plenty of options, that cost repeats until it shows up in the load time.
The new implementation works as short-term memory. Load a product once during a request and it stays in a static cache, with later calls handed a clone of that same instance. The gains are largest on stores running extensions like All Products for Subscriptions.
Real-world benchmarks
The numbers come from the WooCommerce developer blog:
- Variable products: view product page load times fell by roughly 160ms to 227ms.
- Add to cart: around 12-13 percent faster.
- Simple products: 2-6 percent, small but consistent.
For another angle on the same problem, I wrote up WooCommerce variation price caching.
The gotcha: stale data
The risk is stale data inside a single request. Update a product with direct SQL, which I would rather you did not do, and the in-memory cache has no idea anything changed. Every later call in that request keeps handing back the old values.
Stick to the standard APIs, $product->save() or update_post_meta(), and invalidation is handled for you. WooCommerce hooks into clean_post_cache and the meta update actions to clear the entry.
How to invalidate the cache manually
When a direct database update is unavoidable, clear the cache yourself in the same function:
<?php
/**
* Example of manual cache invalidation when performing direct SQL updates.
* Prefixing with bbioon_ as per senior dev standards.
*/
function bbioon_update_product_price_manually( $product_id, $new_price ) {
global $wpdb;
// Direct SQL update (not recommended, but happens in legacy code)
$wpdb->update(
$wpdb->postmeta,
[ 'meta_value' => $new_price ],
[ 'post_id' => $product_id, 'meta_key' => '_price' ]
);
// CRITICAL: Invalidate the product object cache manually
if ( function_exists( 'wc_get_container' ) ) {
// This triggers the standard invalidation logic in Woo 10.5+
clean_post_cache( $product_id );
}
}
Whatever you do, walk the whole checkout flow after switching this on. If you want more in the same direction, I covered optimizing WooCommerce REST API performance separately.
How to enable it
It ships disabled because it is still experimental. Go to WooCommerce → Settings → Advanced → Features and tick “Cache Product Objects”. Try it on staging first if you depend on bundle plugins or a custom inventory sync.
If this breaks a custom integration and you would rather not lose a week to it, I can take it over. I have been working with WordPress since the 4.x days and I know where the bodies are buried in the schema.
Worth enabling
Product object caching is a straightforward scalability win. It shrinks the cost of wc_get_product() and quietly rewards anyone already using the official CRUD APIs. Move your direct SQL over, enable the feature on staging, and keep an eye on your clean_post_cache calls while you do. The speed is free once the code behaves.