Commit cf26536d6e for woocommerce
commit cf26536d6ec3203d55077406f4f29aa298226fb0
Author: Vladimir Reznichenko <kalessil@gmail.com>
Date: Fri Jan 30 08:33:40 2026 +0100
[Performance] Products: consolidate cache priming in product data stores (#62999)
Consolidated previous work on adding cache priming in product data stores to make it more uniform, and added priming where it was missing (bulk-products construction involved).
diff --git a/plugins/woocommerce/changelog/performance-62987-cache-priming-in-product-data-stores b/plugins/woocommerce/changelog/performance-62987-cache-priming-in-product-data-stores
new file mode 100644
index 0000000000..bd334f3231
--- /dev/null
+++ b/plugins/woocommerce/changelog/performance-62987-cache-priming-in-product-data-stores
@@ -0,0 +1,4 @@
+Significance: minor
+Type: performance
+
+Products: consolidate cache priming calls within product data stores.
diff --git a/plugins/woocommerce/includes/abstracts/abstract-wc-product.php b/plugins/woocommerce/includes/abstracts/abstract-wc-product.php
index cf5ec54636..3cb8eea96f 100644
--- a/plugins/woocommerce/includes/abstracts/abstract-wc-product.php
+++ b/plugins/woocommerce/includes/abstracts/abstract-wc-product.php
@@ -1939,7 +1939,7 @@ class WC_Product extends WC_Abstract_Legacy_Product {
/**
* Returns the children IDs if applicable. Overridden by child classes.
*
- * @return array of IDs
+ * @return int[] of IDs
*/
public function get_children() {
return array();
diff --git a/plugins/woocommerce/includes/class-wc-product-grouped.php b/plugins/woocommerce/includes/class-wc-product-grouped.php
index 3d08e6c3c9..33357ff3eb 100644
--- a/plugins/woocommerce/includes/class-wc-product-grouped.php
+++ b/plugins/woocommerce/includes/class-wc-product-grouped.php
@@ -142,7 +142,7 @@ class WC_Product_Grouped extends WC_Product {
* Return the children of this product.
*
* @param string $context What the value is for. Valid values are view and edit.
- * @return array
+ * @return int[]
*/
public function get_children( $context = 'view' ) {
return $this->get_prop( 'children', $context );
@@ -152,11 +152,14 @@ class WC_Product_Grouped extends WC_Product {
* Return the product's children - visible only.
*
* @since 9.8.0
- * @return array Child products
+ * @return WC_Product[] Child products
*/
public function get_visible_children() {
$grouped_products = array_map( 'wc_get_product', $this->get_children() );
- return array_filter( $grouped_products, 'wc_products_array_filter_visible_grouped' );
+ $grouped_products = array_filter( $grouped_products, 'wc_products_array_filter_visible_grouped' );
+ /** @var WC_Product[] $grouped_products */ // phpcs:ignore Generic.Commenting.DocComment.MissingShort
+
+ return $grouped_products;
}
/**
diff --git a/plugins/woocommerce/includes/class-wc-product-variable.php b/plugins/woocommerce/includes/class-wc-product-variable.php
index d8b597f3b8..400aac33ad 100644
--- a/plugins/woocommerce/includes/class-wc-product-variable.php
+++ b/plugins/woocommerce/includes/class-wc-product-variable.php
@@ -216,7 +216,7 @@ class WC_Product_Variable extends WC_Product {
* This is lazy loaded as it's not used often and does require several queries.
*
* @param bool|string $visible_only Visible only.
- * @return array Children ids
+ * @return int[] Children ids
*/
public function get_children( $visible_only = '' ) {
if ( is_bool( $visible_only ) ) {
@@ -240,7 +240,7 @@ class WC_Product_Variable extends WC_Product {
* This is lazy loaded as it's not used often and does require several queries.
*
* @since 3.0.0
- * @return array Children ids
+ * @return int[] Children ids
*/
public function get_visible_children() {
if ( null === $this->visible_children ) {
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 6098c7b98e..bc15fb8cb0 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
@@ -1506,15 +1506,22 @@ class WC_Product_Data_Store_CPT extends WC_Data_Store_WP implements WC_Object_Da
return $count;
}
- // Get existing variations so we don't create duplicates.
- $existing_variations = array_map( 'wc_get_product', $product->get_children() );
$existing_attributes = array();
- foreach ( $existing_variations as $existing_variation ) {
- $existing_attributes[] = $existing_variation->get_attributes();
+ $child_ids = $product->get_children();
+ if ( ! empty( $child_ids ) ) {
+ _prime_post_caches( $child_ids );
+ // Get existing variations so we don't create duplicates.
+ foreach ( $child_ids as $child_id ) {
+ $child = wc_get_product( $child_id );
+ if ( $child ) {
+ $existing_attributes[] = $child->get_attributes();
+ }
+ }
}
$possible_attributes = array_reverse( wc_array_cartesian( $attributes ) );
+ $product_id = $product->get_id();
foreach ( $possible_attributes as $possible_attribute ) {
// Allow any order if key/values -- do not use strict mode.
@@ -1526,7 +1533,7 @@ class WC_Product_Data_Store_CPT extends WC_Data_Store_WP implements WC_Object_Da
foreach ( $metadata as $meta ) {
$variation->add_meta_data( $meta['key'], $meta['value'] );
}
- $variation->set_parent_id( $product->get_id() );
+ $variation->set_parent_id( $product_id );
$variation->set_attributes( $possible_attribute );
$variation_id = $variation->save();
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 41e45b815b..d770a9e447 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
@@ -70,31 +70,31 @@ class WC_Product_Grouped_Data_Store_CPT extends WC_Product_Data_Store_CPT implem
* @param WC_Product $product Product object.
*/
protected function update_prices_from_children( &$product ) {
- $child_ids = $product->get_children( 'edit' );
+ $product_id = $product->get_id();
$child_prices = array();
- // Prime caches for all child products at once to reduce queries.
- if ( is_callable( '_prime_post_caches' ) && ! empty( $child_ids ) ) {
+ $child_ids = $product->get_children( 'edit' );
+ if ( ! empty( $child_ids ) ) {
_prime_post_caches( $child_ids );
- }
-
- foreach ( $child_ids as $child_id ) {
- $child = wc_get_product( $child_id );
- if ( $child ) {
- $child_prices[] = $child->get_price( 'edit' );
+ foreach ( $child_ids as $child_id ) {
+ $child = wc_get_product( $child_id );
+ if ( $child ) {
+ $child_prices[] = $child->get_price( 'edit' );
+ }
}
+ $child_prices = array_filter( $child_prices );
}
- $child_prices = array_filter( $child_prices );
- delete_post_meta( $product->get_id(), '_price' );
- delete_post_meta( $product->get_id(), '_sale_price' );
- delete_post_meta( $product->get_id(), '_regular_price' );
+
+ delete_post_meta( $product_id, '_price' );
+ delete_post_meta( $product_id, '_sale_price' );
+ delete_post_meta( $product_id, '_regular_price' );
if ( ! empty( $child_prices ) ) {
- add_post_meta( $product->get_id(), '_price', min( $child_prices ) );
- add_post_meta( $product->get_id(), '_price', max( $child_prices ) );
+ add_post_meta( $product_id, '_price', min( $child_prices ) );
+ add_post_meta( $product_id, '_price', max( $child_prices ) );
}
- $this->update_lookup_table( $product->get_id(), 'wc_product_meta_lookup' );
+ $this->update_lookup_table( $product_id, 'wc_product_meta_lookup' );
/**
* Fire an action for this direct update so it can be detected by other code.
@@ -102,6 +102,6 @@ class WC_Product_Grouped_Data_Store_CPT extends WC_Product_Data_Store_CPT implem
* @since 3.6
* @param int $product_id Product ID that was updated directly.
*/
- do_action( 'woocommerce_updated_product_price', $product->get_id() );
+ do_action( 'woocommerce_updated_product_price', $product_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 3805a8ebae..3f88f99949 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
@@ -315,12 +315,12 @@ class WC_Product_Variable_Data_Store_CPT extends WC_Product_Data_Store_CPT imple
$variation_ids = $product->get_visible_children();
- if ( is_callable( '_prime_post_caches' ) ) {
+ if ( ! empty( $variation_ids ) ) {
_prime_post_caches( $variation_ids );
}
$tax_display_mode = $for_display ? get_option( 'woocommerce_tax_display_shop' ) : null;
-
+ $price_decimals = wc_get_price_decimals();
foreach ( $variation_ids as $variation_id ) {
$variation = wc_get_product( $variation_id );
@@ -359,6 +359,11 @@ class WC_Product_Variable_Data_Store_CPT extends WC_Product_Data_Store_CPT imple
*/
$price = apply_filters( 'woocommerce_variation_prices_price', $variation->get_price( 'edit' ), $variation, $product );
+ // Skip empty prices.
+ if ( '' === $price ) {
+ continue;
+ }
+
/**
* Filters the regular price for a product variation before it is used in price calculations and caching.
*
@@ -385,11 +390,6 @@ class WC_Product_Variable_Data_Store_CPT extends WC_Product_Data_Store_CPT imple
*/
$sale_price = apply_filters( 'woocommerce_variation_prices_sale_price', $variation->get_sale_price( 'edit' ), $variation, $product );
- // Skip empty prices.
- if ( '' === $price ) {
- continue;
- }
-
// If sale price does not equal price, the product is not yet on sale.
if ( $sale_price === $regular_price || $sale_price !== $price ) {
$sale_price = $regular_price;
@@ -444,9 +444,9 @@ class WC_Product_Variable_Data_Store_CPT extends WC_Product_Data_Store_CPT imple
}
}
- $prices_array['price'][ $variation_id ] = wc_format_decimal( $price, wc_get_price_decimals() );
- $prices_array['regular_price'][ $variation_id ] = wc_format_decimal( $regular_price, wc_get_price_decimals() );
- $prices_array['sale_price'][ $variation_id ] = wc_format_decimal( $sale_price, wc_get_price_decimals() );
+ $prices_array['price'][ $variation_id ] = wc_format_decimal( $price, $price_decimals );
+ $prices_array['regular_price'][ $variation_id ] = wc_format_decimal( $regular_price, $price_decimals );
+ $prices_array['sale_price'][ $variation_id ] = wc_format_decimal( $sale_price, $price_decimals );
if ( has_filter( 'woocommerce_variation_prices_array' ) ) {
$original_prices_array = $prices_array;
diff --git a/plugins/woocommerce/includes/legacy/abstract-wc-legacy-product.php b/plugins/woocommerce/includes/legacy/abstract-wc-legacy-product.php
index 532410a0de..4b0fe30282 100644
--- a/plugins/woocommerce/includes/legacy/abstract-wc-legacy-product.php
+++ b/plugins/woocommerce/includes/legacy/abstract-wc-legacy-product.php
@@ -588,6 +588,7 @@ abstract class WC_Abstract_Legacy_Product extends WC_Data {
$children = $product->get_children( 'edit' );
}
+ /** @var int[] $children */ // phpcs:ignore Generic.Commenting.DocComment.MissingShort
foreach ( $children as $child_id ) {
$all_meta = get_post_meta( $child_id );
diff --git a/plugins/woocommerce/phpstan-baseline.neon b/plugins/woocommerce/phpstan-baseline.neon
index 86c3d4f138..b0dca53332 100644
--- a/plugins/woocommerce/phpstan-baseline.neon
+++ b/plugins/woocommerce/phpstan-baseline.neon
@@ -21996,12 +21996,6 @@ parameters:
count: 1
path: includes/data-stores/class-wc-product-data-store-cpt.php
- -
- message: '#^Cannot call method get_attributes\(\) on WC_Product\|false\|null\.$#'
- identifier: method.nonObject
- count: 1
- path: includes/data-stores/class-wc-product-data-store-cpt.php
-
-
message: '#^Method WC_Product_Data_Store_CPT\:\:clear_caches\(\) has no return type specified\.$#'
identifier: missingType.return
@@ -22182,12 +22176,6 @@ parameters:
count: 1
path: includes/data-stores/class-wc-product-data-store-cpt.php
- -
- message: '#^Call to function is_callable\(\) with ''_prime_post_caches'' will always evaluate to true\.$#'
- identifier: function.alreadyNarrowedType
- count: 1
- path: includes/data-stores/class-wc-product-grouped-data-store-cpt.php
-
-
message: '#^Method WC_Product\:\:get_children\(\) invoked with 1 parameter, 0 required\.$#'
identifier: arguments.count
@@ -22254,12 +22242,6 @@ parameters:
count: 1
path: includes/data-stores/class-wc-product-variable-data-store-cpt.php
- -
- message: '#^Call to function is_callable\(\) with ''_prime_post_caches'' will always evaluate to true\.$#'
- identifier: function.alreadyNarrowedType
- count: 1
- path: includes/data-stores/class-wc-product-variable-data-store-cpt.php
-
-
message: '#^Method WC_Product_Variable_Data_Store_CPT\:\:delete_variations\(\) has no return type specified\.$#'
identifier: missingType.return
@@ -25566,12 +25548,6 @@ parameters:
count: 1
path: includes/legacy/abstract-wc-legacy-product.php
- -
- message: '#^Argument of an invalid type array\|true supplied for foreach, only iterables are supported\.$#'
- identifier: foreach.nonIterable
- count: 1
- path: includes/legacy/abstract-wc-legacy-product.php
-
-
message: '#^Call to an undefined method WC_Abstract_Legacy_Product\:\:child_has_dimensions\(\)\.$#'
identifier: method.notFound