Experimental Product Object Caching in WooCommerce 10.5

WooCommerce 10.5 introduces an experimental Product Object Caching feature that improves performance by caching product instances during each request, preventing duplicate product loads from the database redundant object instantiation overhead when the same product is loaded multiple times within a single request

Update (January 26, 2026) and clarification:  An earlier version of this post incorrectly stated that this feature "prevents duplicate product loads from the database." Product data is already cached by WordPress. This feature prevents redundant object instantiation overhead. The post has been updated to clarify this distinction.

Product data itself (post data, meta, taxonomy terms) is already cached by WordPress's object cache and standard post caching mechanisms - used by the underlying Product Datastore. However, every call to wc_get_product() creates a fresh product instance from that cached data - a process that involves object creation, property setting, and meta loading. This hydration overhead often takes 0.5-0.9ms per product (or longer with heavy meta data).

How It Works

When enabled:

  • wc_get_product() / WC_Product_Factory::get_product() checks an in-memory cache before loading from the datastore
  • Products loaded from the datastore are cached for subsequent calls within the same request
  • Cache is automatically invalidated when products are updated via standard WooCommerce/WordPress APIs
  • The cache is non-persistent (in-memory only, clears between requests)

Enabling the Feature

  1. Navigate to WooCommerce → Settings → Advanced → Features
  2. Enable “Cache Product Objects”

Performance Impact

Performance improvements will vary significantly based on:

  • The extensions active on your site
  • How those extensions interact with products (how many times they load the same product)
  • The types of products being loaded (simple, variable, bundles, subscriptions)

Example benchmarks (with WooCommerce All Products for Subscriptions active):

Product TypeOperationImprovement
Variable ProductView Product Page-160ms to -227ms (~9-12%)
Variable ProductAdd to Cart-235ms to -250ms (~12-13%)
Bundle ProductPlace Order-165ms to -234ms (~6-12%)
Simple ProductPlace Order-22ms to -56ms (~2-6%)

Note: These benchmarks were captured with WooCommerce All Products for Subscriptions enabled, which triggers additional product loading operations. Sites with different extension combinations will see different results – some more, some less.

How can developers tell if they are affected?

The caching implementation uses standard WordPress and WooCommerce hooks for cache invalidation. In most cases, extensions should work without modification. However, there are edge cases to be aware of:

Cache invalidation is triggered by:

  • clean_post_cache action (WordPress post updates/deletions)
  • updated_post_meta, added_post_meta, deleted_post_meta actions
  • woocommerce_updated_product_stock and woocommerce_updated_product_sales actions
  • WooCommerce product datastore save() operations

Potential compatibility considerations:

  1. Direct SQL updates: If your extension updates product data using direct database queries without triggering WordPress meta hooks or calling clean_post_cache(), the cached product will become stale for the remainder of the request.
  2. Repeated product loading: If your extension calls wc_get_product() multiple times for the same product ID within a request, all calls will return clones of the same cached instance. This is the intended behavior and should be transparent to most code.

What action do developers need to take if affected?

This feature is disabled by default, but can be enabled by store owners. Third party developers should test for compatibility.

If you encounter unexpected behavior with this feature enabled, please open an issue with details about which extensions are active.


16 responses to “Experimental Product Object Caching in WooCommerce 10.5”

  1. You’re only just adding object caching to the product instance now? I’m amazed this wasn’t already in place.

    1. Amazing things are happening 🙂
      You will not need object cache for product if you have full page cache. And this does not persists between requests so that means this removes multiple calls to db for the same product. And you are right, this should already be prevented to happen inside get product class. As they show performance increases after enabling it means even default Woo was making multiple calls to db for the same product on the same page requests. Still good move.

    2. prettyboymp Avatar
      prettyboymp

      Hi Tony,

      Thanks for the comment – it helped us realize the original post was misleading! I’ve clarified the description above.

      To be clear: Product data (post data, meta, terms) is already cached by WordPress’s object cache. This feature caches the fully instantiated product objects themselves – avoiding the overhead of the hydration process.

  2. As per what is mentioned in the document, this Cache Product Objects option is not showing in my store. I checked the Features tab, but there is no option called ‘Cache Product Objects.’ How can I enable this option, and when does it appear in the WooCommerce settings? I have the latest version of WooCommerce installed. Please see the screenshot below.

    See this screenshot: https://prnt.sc/wiryC1GZBnAz

    1. Brent MacKinnon Avatar
      Brent MacKinnon

      Hi Nikul — this feature is coming in WooCommerce 10.5, which is currently available for beta testing. If you’d like, you can use the WooCommerce Beta Tester plugin to try beta versions: https://woocommerce.com/products/woocommerce-beta-tester/

  3. Okay, Thanks.

  4. Is there an event that fires when an object is cloned from the cache? That’s important to have for me, because I have a few projects where product instances carry around extra data using a WeakMap. If you clone an object, the corresponding WeakMap data must also be cloned, hence the need for an event.

  5. In addition to my last comment, does the feature allow to explicitly fetch a fresh instance of a product, instead of a cached one? This is important too, because product instances might be modified by some code, but the changes don’t necessarily need to be persisted to the database.

    Currently, if one wants to make a persistent change, without risking to save other modifications, one can simply get a new product instance, change the required property and save the product. If the cache returns a modified instance from the cache, the “save” call would end up storing other changes as well.

    1. Hi Diego,
      This is not a persistent cache between requests. It is temporary for each request, to reduce stress on the database by avoiding multiple queries for the same product. So it should not affect your use case.

    2. prettyboymp Avatar
      prettyboymp

      Diego,

      The end behavior shouldn’t be any different with or without the product instance caching enabled. Either way, you will get a new instance of a product object, whether it was cloned or re-instantiated. Any modifications to that instance won’t effect other instances unless you explicitly save it.

  6. PeterPan Avatar

    Hey Guys,

    would be nice if “WooCommerce Beta Tester” would already declare compatibility “product_instance_caching”. Testing would be smoother that way 😉

  7. How to declare compatibility in our plugin?

  8. I am confused, it shows incompatible plugins (ofc they did not declare compatibility), but does that mean that compatible ones (eg. Woo core) uses it? I am confused as it’s not clear (like it was with HPOS transition) if it runs with some, or all or none at all!??

    1. prettyboymp Avatar
      prettyboymp

      Hi Eduard,

      When the feature is enabled, it applies globally to all product loading — it’s not limited to plugins that have declared compatibility. The compatibility declarations are informational only; they don’t control whether the feature is active.

      The reason it currently defaults to showing plugins as “incompatible” is caution — since this is a caching layer, if an extension does conflict with it, the effects could be subtle (e.g., stale product data within a request). We wanted to err on the side of surfacing that most extensions haven’t been explicitly tested with it yet.

      That said, we recognize the current messaging is confusing. Showing everything as “incompatible” when it really means “hasn’t declared either way” isn’t helpful. We’re looking into improving the UI to distinguish between extensions that have explicitly declared themselves incompatible vs. those that simply haven’t declared anything yet (https://github.com/woocommerce/woocommerce/issues/63233).

      In the meantime, if you enable the feature and your store behaves normally, your extensions are almost certainly fine — the vast majority of plugins that use standard WooCommerce APIs will work without any issues.

      1. Hi Prettyboymp,

        Thank you for the response, it kind of clarifies a few things, I tried local testing and I have a constant nag about incompatible plugins. I guess this means every plugin developer has to update their plugin/theme/integration so the nag will go away, correct? Because if so, you said that it should work fine with “standard WooCommerce APIs”, yet the nag reads there’s a problem and you cannot dismiss it, just like in HPOS.

  9. Found it:

    add_action(
    'before_woocommerce_init',
    function () {
    if ( class_exists( FeaturesUtil::class ) ) {
    FeaturesUtil::declare_compatibility( 'custom_order_tables', __FILE__, true );
    FeaturesUtil::declare_compatibility( 'product_instance_caching', __FILE__, true );
    }
    }
    );

Leave a Reply

Your email address will not be published. Required fields are marked *