Commit c37c64554a8 for woocommerce

commit c37c64554a879cb5be84193e84f1e6d02cd69a5d
Author: Vladimir Reznichenko <kalessil@gmail.com>
Date:   Tue Mar 17 11:03:55 2026 +0100

    [dev] Performance: introduce new skill for using cache priming (reviews and code generation) (#63706)

diff --git a/.ai/skills/woocommerce-performance/SKILL.md b/.ai/skills/woocommerce-performance/SKILL.md
new file mode 100644
index 00000000000..b837faba07a
--- /dev/null
+++ b/.ai/skills/woocommerce-performance/SKILL.md
@@ -0,0 +1,10 @@
+---
+name: woocommerce-performance
+description: Identify missing _prime_post_caches calls in WooCommerce PHP code. Use when writing or reviewing code that loads collections of post-based objects (products, orders) or renders product lists with images.
+---
+
+# WooCommerce Performance
+
+## Cache Priming — [cache-priming.md](cache-priming.md)
+
+Use when writing or reviewing code that loads collections of post-based objects (products, orders) or renders product lists with images. Covers `_prime_post_caches()` usage patterns — both as a generation guide (apply these patterns when writing new code) and a review guide (flag missing priming in existing code).
diff --git a/.ai/skills/woocommerce-performance/cache-priming.md b/.ai/skills/woocommerce-performance/cache-priming.md
new file mode 100644
index 00000000000..78c2baa658e
--- /dev/null
+++ b/.ai/skills/woocommerce-performance/cache-priming.md
@@ -0,0 +1,132 @@
+# Cache Priming
+
+Covers correct usage of `_prime_post_caches()` to reduce SQL query counts when loading or rendering collections of post-based objects.
+
+## Patterns
+
+### 1. Missing cache priming before iterating post-based objects
+
+**Apply when:** any `array_map` or loop fetches multiple objects by ID using `get_post()`, `wc_get_product()`, `wc_get_order()`, or any function that resolves to a `get_post()` call per item (e.g. a `format_*` helper that calls `get_post()` internally).
+
+**Correct pattern:**
+
+```php
+if ( ! empty( $ids ) ) {
+    // Prime caches to reduce future queries.
+    _prime_post_caches( $ids );
+    $products = array_map( 'wc_get_product', $ids );
+}
+```
+
+The comment `// Prime caches to reduce future queries.` must always sit **inside** the `if` block, directly above the call. Do not place it before the `if`. Place the prime immediately before the loop or `array_map` that consumes the IDs. Exception: if a `do_action` call between the guard and the loop passes the IDs as arguments (e.g. `do_action( 'wc_before_products_starting_sales', $product_ids )`), move the prime before that action so hooked callbacks loading the same objects also benefit from the warmed cache. If the action does not receive the IDs, keep the prime directly above the loop.
+
+`_prime_post_caches()` is a WordPress internal (underscore-prefixed) that has existed since WP 4.1. The minimum supported WordPress version for WooCommerce guarantees its presence — `is_callable( '_prime_post_caches' )` guards are unnecessary and must be removed when encountered. Always wrap in `! empty()` to avoid a no-op SQL on empty arrays.
+
+---
+
+### 2. Missing two-phase image priming when rendering product collections
+
+**Apply when:** Code that fetches products and then renders them (templates, blocks), especially with thumbnails.
+
+**Correct pattern:**
+
+```php
+if ( ! empty( $product_ids ) ) {
+    // Prime caches to reduce future queries.
+    _prime_post_caches( $product_ids );
+    $products = array_filter( array_map( 'wc_get_product', $product_ids ), 'wc_products_array_filter_visible' );
+
+    // Prime caches to reduce future queries.
+    _prime_post_caches( array_filter( array_map( fn( $p ) => (int) $p->get_image_id(), $products ) ) );
+}
+```
+
+Applies to: `woocommerce_related_products()`, `woocommerce_upsell_display()`, block type `RelatedProducts`, and any similar rendering functions.
+
+---
+
+### 3. Priming the full ID list instead of only uncached IDs
+
+**Apply when:** `_prime_post_caches()` called on the original full list of IDs, even when an object cache layer (e.g., `OrderCache`) has already resolved some of them.
+
+Prime only the IDs not already in cache:
+
+```php
+$uncached_ids = ...; // IDs remaining after object cache lookup
+if ( ! empty( $uncached_ids ) ) {
+    _prime_post_caches( $uncached_ids );
+}
+```
+
+---
+
+### 4. Priming at each rendering entry point independently
+
+**Apply when:** Cache priming added in one rendering function but not in the equivalent block type or REST API handler serving the same data.
+
+Blocks and classic templates are separate entry points — each must be audited and primed independently.
+
+**Check pairs:**
+
+- `woocommerce_related_products()` ↔ `RelatedProducts` block type
+- `woocommerce_upsell_display()` ↔ any upsells block
+- Legacy template functions ↔ StoreApi schema handlers
+
+---
+
+### 5. Prefer native batching arguments over manual priming
+
+**Apply when:** A loop iterates over results from a WordPress query function that natively supports post cache warming.
+
+**Decision process:**
+
+1. Identify the N+1: a loop or `array_map` calls `wc_get_product()`, `get_post()`, or similar on each item.
+2. Before adding `_prime_post_caches()`, check whether the data source has a native batching argument.
+
+**`get_comments()`** supports `update_comment_post_cache => true`, which batch-loads the parent post cache as part of the query itself — no separate prime needed. The post type of the parent can be `product`, `order`, `post`, or any other — the argument applies regardless:
+
+```php
+$comments = get_comments(
+    array(
+        'post_type'                 => 'product', // or 'order', 'post', etc.
+        'update_comment_post_cache' => true,
+        // ...
+    )
+);
+foreach ( $comments as $comment ) {
+    $product = wc_get_product( $comment->comment_post_ID ); // cache already warm
+}
+```
+
+Use `_prime_post_caches()` only when no such native argument exists on the data source.
+
+---
+
+### 6. Do not prime after WP_Query — it already handles caching
+
+**Apply when:** Code runs `WP_Query::query()` (or `new WP_Query(...)`) and then calls `_prime_post_caches()` on the returned value.
+
+**Why it is wrong:** `WP_Query` automatically primes the post, meta, and term caches for every post it loads (controlled by `update_post_meta_cache` and `update_post_term_cache`, both `true` by default). Calling `_prime_post_caches()` afterward is redundant.
+
+Additionally, `WP_Query::query()` returns an array of `WP_Post` objects (when no `fields` argument is set), not integer IDs. `_prime_post_caches()` internally calls `intval()` on each item — `intval( WP_Post )` returns `1`, not the post ID. The function silently misbehaves.
+
+**Do not add priming here:**
+
+```php
+$result = $query->query( $query_args );
+// Wrong — $result is WP_Post[] and WP_Query already primed all caches.
+_prime_post_caches( $result );
+$products = array_map( 'wc_get_product', $result );
+```
+
+Priming is only needed when starting from a raw list of IDs not loaded through `WP_Query` — see pattern 1.
+
+---
+
+## Backward Compatibility
+
+Pass `false` for the `$update_meta_cache` parameter when meta is being handled separately, to avoid double-priming:
+
+```php
+_prime_post_caches( $order_ids, true, false ); // skip meta priming, include terms
+```
diff --git a/plugins/woocommerce/changelog/performance-extract-cache-priming-prs-into-skill b/plugins/woocommerce/changelog/performance-extract-cache-priming-prs-into-skill
new file mode 100644
index 00000000000..3d9f5c35e83
--- /dev/null
+++ b/plugins/woocommerce/changelog/performance-extract-cache-priming-prs-into-skill
@@ -0,0 +1,4 @@
+Significance: patch
+Type: dev
+
+Introduce a new performance skill focused on effectively using caching priming APIs.
diff --git a/plugins/woocommerce/includes/class-wc-cart-session.php b/plugins/woocommerce/includes/class-wc-cart-session.php
index 426174b8cdb..c99bd9b39cd 100644
--- a/plugins/woocommerce/includes/class-wc-cart-session.php
+++ b/plugins/woocommerce/includes/class-wc-cart-session.php
@@ -131,8 +131,8 @@ final class WC_Cart_Session {
 			$update_cart_session = true;
 		}

-		// Prime caches to reduce future queries.
-		if ( is_callable( '_prime_post_caches' ) ) {
+		if ( ! empty( $cart ) ) {
+			// Prime caches to reduce future queries.
 			_prime_post_caches( wp_list_pluck( $cart, 'product_id' ) );
 		}

diff --git a/plugins/woocommerce/includes/class-wc-order-factory.php b/plugins/woocommerce/includes/class-wc-order-factory.php
index f92699c1970..dcce79b8913 100644
--- a/plugins/woocommerce/includes/class-wc-order-factory.php
+++ b/plugins/woocommerce/includes/class-wc-order-factory.php
@@ -92,7 +92,10 @@ class WC_Order_Factory {
 			$order_ids = $uncached_order_ids;
 		}

-		_prime_post_caches( $order_ids, false, true );
+		if ( ! empty( $order_ids ) ) {
+			// Prime caches to reduce future queries.
+			_prime_post_caches( $order_ids, false, true );
+		}

 		// We separate order list by class, since their datastore might be different.
 		$order_list_by_class = array();
diff --git a/plugins/woocommerce/includes/class-wc-product-factory.php b/plugins/woocommerce/includes/class-wc-product-factory.php
index b1d6f7fc0dd..8ccf7d6b84e 100644
--- a/plugins/woocommerce/includes/class-wc-product-factory.php
+++ b/plugins/woocommerce/includes/class-wc-product-factory.php
@@ -41,6 +41,7 @@ class WC_Product_Factory {
 				return $product;
 			}
 		}
+		// Prime caches to reduce future queries.
 		_prime_post_caches( array( $product_id ) );

 		$product_type = self::get_product_type( $product_id );
diff --git a/plugins/woocommerce/includes/class-wc-product-grouped.php b/plugins/woocommerce/includes/class-wc-product-grouped.php
index 23706bb1f0d..87558073937 100644
--- a/plugins/woocommerce/includes/class-wc-product-grouped.php
+++ b/plugins/woocommerce/includes/class-wc-product-grouped.php
@@ -200,7 +200,10 @@ class WC_Product_Grouped extends WC_Product {
 	 */
 	private function get_primed_visible_children( $context = 'view' ) {
 		$child_ids = $this->get_children( $context );
-		_prime_post_caches( $child_ids );
+		if ( ! empty( $child_ids ) ) {
+			// Prime caches to reduce future queries.
+			_prime_post_caches( $child_ids );
+		}
 		$children = array_filter( array_map( 'wc_get_product', $child_ids ), 'wc_products_array_filter_visible_grouped' );
 		/** @var WC_Product[] $children */ // phpcs:ignore Generic.Commenting.DocComment.MissingShort
 		return $children;
diff --git a/plugins/woocommerce/includes/class-wc-product-variable.php b/plugins/woocommerce/includes/class-wc-product-variable.php
index 400aac33ad3..b18085e979b 100644
--- a/plugins/woocommerce/includes/class-wc-product-variable.php
+++ b/plugins/woocommerce/includes/class-wc-product-variable.php
@@ -329,7 +329,8 @@ class WC_Product_Variable extends WC_Product {
 		$hide_out_of_stock_items = ( 'yes' === get_option( 'woocommerce_hide_out_of_stock_items' ) );
 		$available_variations    = array();

-		if ( is_callable( '_prime_post_caches' ) ) {
+		if ( ! empty( $variation_ids ) ) {
+			// Prime caches to reduce future queries.
 			_prime_post_caches( $variation_ids );
 		}

@@ -380,7 +381,8 @@ class WC_Product_Variable extends WC_Product {
 	public function has_purchasable_variations() {
 		$variation_ids = $this->get_children();

-		if ( is_callable( '_prime_post_caches' ) ) {
+		if ( ! empty( $variation_ids ) ) {
+			// Prime caches to reduce future queries.
 			_prime_post_caches( $variation_ids );
 		}

diff --git a/plugins/woocommerce/includes/data-stores/class-wc-product-data-store-cpt.php b/plugins/woocommerce/includes/data-stores/class-wc-product-data-store-cpt.php
index fb7101aac38..2d7716d9341 100644
--- a/plugins/woocommerce/includes/data-stores/class-wc-product-data-store-cpt.php
+++ b/plugins/woocommerce/includes/data-stores/class-wc-product-data-store-cpt.php
@@ -1561,6 +1561,7 @@ class WC_Product_Data_Store_CPT extends WC_Data_Store_WP implements WC_Object_Da

 		$child_ids = $product->get_children();
 		if ( ! empty( $child_ids ) ) {
+			// Prime caches to reduce future queries.
 			_prime_post_caches( $child_ids );
 			// Get existing variations so we don't create duplicates.
 			foreach ( $child_ids as $child_id ) {
diff --git a/plugins/woocommerce/includes/data-stores/class-wc-product-grouped-data-store-cpt.php b/plugins/woocommerce/includes/data-stores/class-wc-product-grouped-data-store-cpt.php
index d770a9e447f..f21b9e6fa74 100644
--- a/plugins/woocommerce/includes/data-stores/class-wc-product-grouped-data-store-cpt.php
+++ b/plugins/woocommerce/includes/data-stores/class-wc-product-grouped-data-store-cpt.php
@@ -75,6 +75,7 @@ class WC_Product_Grouped_Data_Store_CPT extends WC_Product_Data_Store_CPT implem

 		$child_ids = $product->get_children( 'edit' );
 		if ( ! empty( $child_ids ) ) {
+			// Prime caches to reduce future queries.
 			_prime_post_caches( $child_ids );
 			foreach ( $child_ids as $child_id ) {
 				$child = wc_get_product( $child_id );
diff --git a/plugins/woocommerce/includes/data-stores/class-wc-product-variable-data-store-cpt.php b/plugins/woocommerce/includes/data-stores/class-wc-product-variable-data-store-cpt.php
index c6c1f9af009..55c9a735151 100644
--- a/plugins/woocommerce/includes/data-stores/class-wc-product-variable-data-store-cpt.php
+++ b/plugins/woocommerce/includes/data-stores/class-wc-product-variable-data-store-cpt.php
@@ -338,6 +338,7 @@ class WC_Product_Variable_Data_Store_CPT extends WC_Product_Data_Store_CPT imple
 				$variation_ids = $product->get_visible_children();

 				if ( ! empty( $variation_ids ) ) {
+					// Prime caches to reduce future queries.
 					_prime_post_caches( $variation_ids );
 				}

diff --git a/plugins/woocommerce/includes/shortcodes/class-wc-shortcode-products.php b/plugins/woocommerce/includes/shortcodes/class-wc-shortcode-products.php
index 653a60b2db0..b50a61ce322 100644
--- a/plugins/woocommerce/includes/shortcodes/class-wc-shortcode-products.php
+++ b/plugins/woocommerce/includes/shortcodes/class-wc-shortcode-products.php
@@ -620,9 +620,7 @@ class WC_Shortcode_Products {

 		if ( $products && $products->ids ) {
 			// Prime caches to reduce future queries.
-			if ( is_callable( '_prime_post_caches' ) ) {
-				_prime_post_caches( $products->ids );
-			}
+			_prime_post_caches( $products->ids );

 			// Setup the loop.
 			wc_setup_loop(
diff --git a/plugins/woocommerce/includes/wc-template-functions.php b/plugins/woocommerce/includes/wc-template-functions.php
index 96931a81f7b..078c50a1f23 100644
--- a/plugins/woocommerce/includes/wc-template-functions.php
+++ b/plugins/woocommerce/includes/wc-template-functions.php
@@ -2366,7 +2366,7 @@ if ( ! function_exists( 'woocommerce_related_products' ) ) {
 		$related_products    = array();
 		$related_product_ids = wc_get_related_products( $product->get_id(), $args['posts_per_page'], $product->get_upsell_ids() );
 		if ( ! empty( $related_product_ids ) ) {
-			// Optimization: reduce the number of SQLs needed to populate product objects.
+			// Prime caches to reduce future queries.
 			_prime_post_caches( $related_product_ids );

 			// Get visible related products then sort them at random, then handle orderby.
@@ -2374,7 +2374,7 @@ if ( ! function_exists( 'woocommerce_related_products' ) ) {
 			$related_products = wc_products_array_orderby( $related_products, $args['orderby'], $args['order'] );
 			/** @var WC_Product[] $related_products */ // phpcs:ignore Generic.Commenting.DocComment.MissingShort

-			// Optimization: reduce the number of SQLs needed to fetch images when rendering.
+			// Prime caches to reduce future queries.
 			_prime_post_caches( array_filter( array_map( fn( $product ) => (int) $product->get_image_id(), $related_products ) ) );
 		}
 		$args['related_products'] = $related_products;
@@ -2431,7 +2431,7 @@ if ( ! function_exists( 'woocommerce_upsell_display' ) ) {
 		$upsells    = array();
 		$upsell_ids = $product->get_upsell_ids();
 		if ( ! empty( $upsell_ids ) ) {
-			// Optimization: reduce the number of SQLs needed to populate product objects.
+			// Prime caches to reduce future queries.
 			_prime_post_caches( $upsell_ids );

 			// Get visible upsells then sort them at random, then limit result set.
@@ -2439,7 +2439,7 @@ if ( ! function_exists( 'woocommerce_upsell_display' ) ) {
 			$upsells = $limit > 0 ? array_slice( $upsells, 0, $limit ) : $upsells;
 			/** @var WC_Product[] $upsells */ // phpcs:ignore Generic.Commenting.DocComment.MissingShort

-			// Optimization: reduce the number of SQLs needed to fetch images when rendering.
+			// Prime caches to reduce future queries.
 			_prime_post_caches( array_filter( array_map( fn( $product ) => (int) $product->get_image_id(), $upsells ) ) );
 		}

diff --git a/plugins/woocommerce/phpstan-baseline.neon b/plugins/woocommerce/phpstan-baseline.neon
index b5186936054..6ffe4954fe8 100644
--- a/plugins/woocommerce/phpstan-baseline.neon
+++ b/plugins/woocommerce/phpstan-baseline.neon
@@ -9930,12 +9930,6 @@ parameters:
 			count: 1
 			path: includes/class-wc-cart-session.php

-		-
-			message: '#^Call to function is_callable\(\) with ''_prime_post_caches'' will always evaluate to true\.$#'
-			identifier: function.alreadyNarrowedType
-			count: 1
-			path: includes/class-wc-cart-session.php
-
 		-
 			message: '#^Cannot call method get_id\(\) on WC_Order\|WC_Order_Refund\|false\.$#'
 			identifier: method.nonObject
@@ -14220,12 +14214,6 @@ parameters:
 			count: 1
 			path: includes/class-wc-product-variable.php

-		-
-			message: '#^Call to function is_callable\(\) with ''_prime_post_caches'' will always evaluate to true\.$#'
-			identifier: function.alreadyNarrowedType
-			count: 2
-			path: includes/class-wc-product-variable.php
-
 		-
 			message: '#^Method WC_Product_Variable\:\:get_available_variations\(\) should return array\<array\|WC_Product_Variation\> but returns list\<array\|bool\|WC_Product\>\.$#'
 			identifier: return.type
@@ -32253,12 +32241,6 @@ parameters:
 			count: 1
 			path: includes/shortcodes/class-wc-shortcode-products.php

-		-
-			message: '#^Call to function is_callable\(\) with ''_prime_post_caches'' will always evaluate to true\.$#'
-			identifier: function.alreadyNarrowedType
-			count: 1
-			path: includes/shortcodes/class-wc-shortcode-products.php
-
 		-
 			message: '#^Method WC_Shortcode_Products\:\:set_attributes_query_args\(\) has no return type specified\.$#'
 			identifier: missingType.return
@@ -50781,12 +50763,6 @@ parameters:
 			count: 1
 			path: src/Blocks/Assets/Api.php

-		-
-			message: '#^Call to function is_callable\(\) with ''_prime_post_caches'' will always evaluate to true\.$#'
-			identifier: function.alreadyNarrowedType
-			count: 1
-			path: src/Blocks/Assets/AssetDataRegistry.php
-
 		-
 			message: '#^Class Automattic\\WooCommerce\\Blocks\\Assets\\Api referenced with incorrect case\: Automattic\\WooCommerce\\Blocks\\Assets\\API\.$#'
 			identifier: class.nameCase
@@ -51339,12 +51315,6 @@ parameters:
 			count: 1
 			path: src/Blocks/BlockTypes/AbstractProductGrid.php

-		-
-			message: '#^Call to function is_callable\(\) with ''_prime_post_caches'' will always evaluate to true\.$#'
-			identifier: function.alreadyNarrowedType
-			count: 1
-			path: src/Blocks/BlockTypes/AbstractProductGrid.php
-
 		-
 			message: '#^Call to method get_average_rating\(\) on an unknown class Automattic\\WooCommerce\\Blocks\\BlockTypes\\WC_Product\.$#'
 			identifier: class.notFound
@@ -75270,12 +75240,6 @@ parameters:
 			count: 4
 			path: src/StoreApi/Utilities/ProductQuery.php

-		-
-			message: '#^Call to function is_callable\(\) with ''_prime_post_caches'' will always evaluate to true\.$#'
-			identifier: function.alreadyNarrowedType
-			count: 1
-			path: src/StoreApi/Utilities/ProductQuery.php
-
 		-
 			message: '#^Method Automattic\\WooCommerce\\StoreApi\\Utilities\\ProductQuery\:\:get_objects\(\) has parameter \$request with generic class WP_REST_Request but does not specify its types\: T$#'
 			identifier: missingType.generics
diff --git a/plugins/woocommerce/src/Blocks/Assets/AssetDataRegistry.php b/plugins/woocommerce/src/Blocks/Assets/AssetDataRegistry.php
index 754531e89b6..8de3d098441 100644
--- a/plugins/woocommerce/src/Blocks/Assets/AssetDataRegistry.php
+++ b/plugins/woocommerce/src/Blocks/Assets/AssetDataRegistry.php
@@ -154,9 +154,7 @@ class AssetDataRegistry {
 			'terms'     => wc_terms_and_conditions_page_id(),
 		];

-		if ( is_callable( '_prime_post_caches' ) ) {
-			_prime_post_caches( array_values( $store_pages ), false, false );
-		}
+		_prime_post_caches( array_values( $store_pages ), false, false );

 		return array_map(
 			[ $this, 'format_page_resource' ],
diff --git a/plugins/woocommerce/src/Blocks/BlockTypes/AbstractProductGrid.php b/plugins/woocommerce/src/Blocks/BlockTypes/AbstractProductGrid.php
index 32da9b06f15..8c809178943 100644
--- a/plugins/woocommerce/src/Blocks/BlockTypes/AbstractProductGrid.php
+++ b/plugins/woocommerce/src/Blocks/BlockTypes/AbstractProductGrid.php
@@ -361,9 +361,8 @@ abstract class AbstractProductGrid extends AbstractDynamicBlock {
 		// Remove ordering query arguments which may have been added by get_catalog_ordering_args.
 		WC()->query->remove_ordering_args();

-		// Prime caches to reduce future queries. Note _prime_post_caches is private--we could replace this with our own
-		// query if it becomes unavailable.
-		if ( is_callable( '_prime_post_caches' ) ) {
+		if ( ! empty( $results ) ) {
+			// Prime caches to reduce future queries.
 			_prime_post_caches( $results );
 		}

diff --git a/plugins/woocommerce/src/Blocks/BlockTypes/RelatedProducts.php b/plugins/woocommerce/src/Blocks/BlockTypes/RelatedProducts.php
index a3f4a94969a..0ea8487e3cf 100644
--- a/plugins/woocommerce/src/Blocks/BlockTypes/RelatedProducts.php
+++ b/plugins/woocommerce/src/Blocks/BlockTypes/RelatedProducts.php
@@ -170,14 +170,14 @@ class RelatedProducts extends AbstractBlock {

 		$related_products_ids = wc_get_related_products( $product->get_id(), $product_per_page, $product->get_upsell_ids() );
 		if ( ! empty( $related_products_ids ) ) {
-			// Optimization: reduce the number of SQLs needed to populate product objects.
+			// Prime caches to reduce future queries.
 			_prime_post_caches( $related_products_ids );

 			$related_products = array_filter( array_map( 'wc_get_product', $related_products_ids ), 'wc_products_array_filter_visible' );
 			$related_products = wc_products_array_orderby( $related_products, 'rand', 'desc' );
 			/** @var \WC_Product[] $related_products */ // phpcs:ignore Generic.Commenting.DocComment.MissingShort

-			// Optimization: reduce the number of SQLs needed to fetch images when rendering.
+			// Prime caches to reduce future queries.
 			_prime_post_caches( array_filter( array_map( fn( $product ) => (int) $product->get_image_id(), $related_products ) ) );

 			$related_products_ids = array_map( fn( $product ) => $product->get_id(), $related_products );
diff --git a/plugins/woocommerce/src/Blocks/Utils/BlockTemplateUtils.php b/plugins/woocommerce/src/Blocks/Utils/BlockTemplateUtils.php
index 2081d5c25cd..0b2a3d7f8c9 100644
--- a/plugins/woocommerce/src/Blocks/Utils/BlockTemplateUtils.php
+++ b/plugins/woocommerce/src/Blocks/Utils/BlockTemplateUtils.php
@@ -748,6 +748,7 @@ class BlockTemplateUtils {
 		if ( null === ( $request_level_cache[ $template_type ][ $theme ] ?? null ) ) {
 			$request_level_cache[ $template_type ][ $theme ] = array();
 			if ( ! empty( $ids[ $theme ] ) ) {
+				// Prime caches to reduce future queries.
 				_prime_post_caches( $ids[ $theme ], false, false );
 				$request_level_cache[ $template_type ][ $theme ] = array_filter( array_map( 'get_post', $ids[ $theme ] ) );
 			}
diff --git a/plugins/woocommerce/src/Internal/Admin/ProductReviews/ReviewsUtil.php b/plugins/woocommerce/src/Internal/Admin/ProductReviews/ReviewsUtil.php
index cdeec1ad591..76d6674158f 100644
--- a/plugins/woocommerce/src/Internal/Admin/ProductReviews/ReviewsUtil.php
+++ b/plugins/woocommerce/src/Internal/Admin/ProductReviews/ReviewsUtil.php
@@ -74,6 +74,7 @@ class ReviewsUtil {

 		if ( ! empty( $comment_query->query_vars['post__in'] ) ) {
 			$post_ids = wp_parse_id_list( $comment_query->query_vars['post__in'] );
+			// Prime caches to reduce future queries.
 			_prime_post_caches( $post_ids, false, false );
 			foreach ( $post_ids as $post_id ) {
 				if ( 'product' === get_post_type( $post_id ) ) {
diff --git a/plugins/woocommerce/src/Internal/RestApi/Routes/V4/Orders/Controller.php b/plugins/woocommerce/src/Internal/RestApi/Routes/V4/Orders/Controller.php
index e05b1503d89..127fa72ab91 100644
--- a/plugins/woocommerce/src/Internal/RestApi/Routes/V4/Orders/Controller.php
+++ b/plugins/woocommerce/src/Internal/RestApi/Routes/V4/Orders/Controller.php
@@ -319,6 +319,7 @@ class Controller extends AbstractController {
 		}
 		$product_ids = array_unique( array_filter( $product_ids ) );
 		if ( ! empty( $product_ids ) ) {
+			// Prime caches to reduce future queries.
 			_prime_post_caches( $product_ids, true, true );
 		}

diff --git a/plugins/woocommerce/src/StoreApi/Schemas/V1/CartSchema.php b/plugins/woocommerce/src/StoreApi/Schemas/V1/CartSchema.php
index 822a0b4cfbe..9a849a2cf22 100644
--- a/plugins/woocommerce/src/StoreApi/Schemas/V1/CartSchema.php
+++ b/plugins/woocommerce/src/StoreApi/Schemas/V1/CartSchema.php
@@ -344,7 +344,7 @@ class CartSchema extends AbstractSchema {
 		$cross_sells    = array();
 		$cross_sell_ids = $cart->get_cross_sells();
 		if ( ! empty( $cross_sell_ids ) ) {
-			// Optimization note: priming reduces the number of SQLs required to populate the product objects.
+			// Prime caches to reduce future queries.
 			_prime_post_caches( $cross_sell_ids );
 			$cross_sells = array_filter( array_map( 'wc_get_product', $cross_sell_ids ), 'wc_products_array_filter_visible' );
 		}
diff --git a/plugins/woocommerce/src/StoreApi/Utilities/ProductQuery.php b/plugins/woocommerce/src/StoreApi/Utilities/ProductQuery.php
index 82d3edd7fed..ea67ab1b9b8 100644
--- a/plugins/woocommerce/src/StoreApi/Utilities/ProductQuery.php
+++ b/plugins/woocommerce/src/StoreApi/Utilities/ProductQuery.php
@@ -339,7 +339,8 @@ class ProductQuery implements QueryClausesGenerator {
 	public function get_objects( $request ) {
 		$results = $this->get_results( $request );

-		if ( is_callable( '_prime_post_caches' ) ) {
+		if ( ! empty( $results['results'] ) ) {
+			// Prime caches to reduce future queries.
 			_prime_post_caches( $results['results'] );
 		}