Commit 761d4f5d6d for woocommerce
commit 761d4f5d6d453d3234dadbae5d2f63790f0e9f8d
Author: Vladimir Reznichenko <kalessil@gmail.com>
Date: Wed Jan 21 09:58:08 2026 +0100
[Performance] Admin: reduce the number of SQL queries on orders page (#62820)
This PR reduces the number of SQL queries needed to populate product collections:
- Prime post caches in bulk to prevent individual retrieval later.
- Optimize COGS data injection by using already fetched metadata instead of querying each individually.
diff --git a/plugins/woocommerce/changelog/performance-admin-reduce-sqls-number-on-roducts-page b/plugins/woocommerce/changelog/performance-admin-reduce-sqls-number-on-roducts-page
new file mode 100644
index 0000000000..45170e6d5a
--- /dev/null
+++ b/plugins/woocommerce/changelog/performance-admin-reduce-sqls-number-on-roducts-page
@@ -0,0 +1,4 @@
+Significance: patch
+Type: performance
+
+The number of SQL queries on the orders pages (admin and my account) has been reduced to improve performance.
diff --git a/plugins/woocommerce/includes/abstracts/abstract-wc-data.php b/plugins/woocommerce/includes/abstracts/abstract-wc-data.php
index 6fcacd5576..df82b59003 100644
--- a/plugins/woocommerce/includes/abstracts/abstract-wc-data.php
+++ b/plugins/woocommerce/includes/abstracts/abstract-wc-data.php
@@ -421,7 +421,6 @@ abstract class WC_Data {
}
}
- $this->maybe_read_meta_data();
$meta_data = $this->get_meta_data();
$array_keys = array_keys( wp_list_pluck( $meta_data, 'key' ), $key, true );
$value = $single ? '' : array();
@@ -450,7 +449,6 @@ abstract class WC_Data {
* @return boolean
*/
public function meta_exists( $key = '' ) {
- $this->maybe_read_meta_data();
$array_keys = wp_list_pluck( $this->get_meta_data(), 'key' );
return in_array( $key, $array_keys, true );
}
diff --git a/plugins/woocommerce/includes/class-wc-order-factory.php b/plugins/woocommerce/includes/class-wc-order-factory.php
index be167b6a53..f92699c197 100644
--- a/plugins/woocommerce/includes/class-wc-order-factory.php
+++ b/plugins/woocommerce/includes/class-wc-order-factory.php
@@ -71,8 +71,9 @@ class WC_Order_Factory {
return array();
}
- $result = array();
+ /** @var int[] $order_ids */ // phpcs:ignore Generic.Commenting.DocComment.MissingShort
$order_ids = array_filter( array_map( array( __CLASS__, 'get_order_id' ), $order_ids ) );
+ $result = array();
$original_order_sort = $order_ids;
$order_cache = wc_get_container()->get( OrderCache::class );
@@ -91,6 +92,8 @@ class WC_Order_Factory {
$order_ids = $uncached_order_ids;
}
+ _prime_post_caches( $order_ids, false, true );
+
// We separate order list by class, since their datastore might be different.
$order_list_by_class = array();
$order_id_classnames = self::get_class_names_for_order_ids( $order_ids );
diff --git a/plugins/woocommerce/phpstan-baseline.neon b/plugins/woocommerce/phpstan-baseline.neon
index 58ae1f7b27..e919f13a1a 100644
--- a/plugins/woocommerce/phpstan-baseline.neon
+++ b/plugins/woocommerce/phpstan-baseline.neon
@@ -15720,12 +15720,6 @@ parameters:
count: 1
path: includes/class-wc-order-factory.php
- -
- message: '#^Parameter \#1 \$input of function array_flip expects array\<int\|string\>, array\<int\<min, \-1\>\|int\<1, max\>\|true\> given\.$#'
- identifier: argument.type
- count: 1
- path: includes/class-wc-order-factory.php
-
-
message: '#^Parameter \#1 \$order_id of static method WC_Order_Factory\:\:get_class_name_for_order_id\(\) expects int, int\<min, \-1\>\|int\<1, max\>\|true given\.$#'
identifier: argument.type
@@ -69753,12 +69747,6 @@ parameters:
count: 1
path: src/Internal/DataStores/Orders/LegacyDataHandler.php
- -
- message: '#^@param WC_Abstract_Order \$product does not accept actual type of parameter\: WC_Data\.$#'
- identifier: parameter.phpDocType
- count: 1
- path: src/Internal/DataStores/Orders/OrdersTableDataStore.php
-
-
message: '#^@param WC_Order \$order does not accept actual type of parameter\: WC_Abstract_Order\.$#'
identifier: parameter.phpDocType
@@ -69801,12 +69789,6 @@ parameters:
count: 1
path: src/Internal/DataStores/Orders/OrdersTableDataStore.php
- -
- message: '#^Call to an undefined method WC_Data\:\:set_cogs_total_value\(\)\.$#'
- identifier: method.notFound
- count: 1
- path: src/Internal/DataStores/Orders/OrdersTableDataStore.php
-
-
message: '#^Call to an undefined method WC_Data_Store\:\:update_user_by_order_id\(\)\.$#'
identifier: method.notFound
@@ -69831,42 +69813,18 @@ parameters:
count: 1
path: src/Internal/DataStores/Orders/OrdersTableDataStore.php
- -
- message: '#^Cannot access offset 0 on stdClass\|true\.$#'
- identifier: offsetAccess.nonOffsetAccessible
- count: 2
- path: src/Internal/DataStores/Orders/OrdersTableDataStore.php
-
- -
- message: '#^Cannot access property \$key on false\.$#'
- identifier: property.nonObject
- count: 1
- path: src/Internal/DataStores/Orders/OrdersTableDataStore.php
-
-
message: '#^Cannot access property \$meta_key on object\|true\.$#'
identifier: property.nonObject
count: 1
path: src/Internal/DataStores/Orders/OrdersTableDataStore.php
- -
- message: '#^Cannot access property \$meta_value on false\.$#'
- identifier: property.nonObject
- count: 1
- path: src/Internal/DataStores/Orders/OrdersTableDataStore.php
-
-
message: '#^Cannot access property \$meta_value on object\|true\.$#'
identifier: property.nonObject
count: 1
path: src/Internal/DataStores/Orders/OrdersTableDataStore.php
- -
- message: '#^Cannot access property \$value on false\.$#'
- identifier: property.nonObject
- count: 1
- path: src/Internal/DataStores/Orders/OrdersTableDataStore.php
-
-
message: '#^Cannot call method getOffsetTimestamp\(\) on WC_DateTime\|null\.$#'
identifier: method.nonObject
@@ -70134,12 +70092,6 @@ parameters:
count: 1
path: src/Internal/DataStores/Orders/OrdersTableDataStore.php
- -
- message: '#^Parameter \#1 \$array_arg of function current expects array\|object, stdClass\|true given\.$#'
- identifier: argument.type
- count: 3
- path: src/Internal/DataStores/Orders/OrdersTableDataStore.php
-
-
message: '#^Parameter \#1 \$function of function call_user_func_array expects callable\(\)\: mixed, array\{Abstract_WC_Order_Data_Store_CPT, non\-falsy\-string\} given\.$#'
identifier: argument.type
@@ -70236,24 +70188,12 @@ parameters:
count: 2
path: src/Internal/DataStores/Orders/OrdersTableDataStore.php
- -
- message: '#^Parameter \#2 \$meta of method Automattic\\WooCommerce\\Internal\\DataStores\\Orders\\OrdersTableDataStoreMeta\:\:delete_meta\(\) expects stdClass, false given\.$#'
- identifier: argument.type
- count: 1
- path: src/Internal/DataStores/Orders/OrdersTableDataStore.php
-
-
message: '#^Parameter \#2 \$meta of method Automattic\\WooCommerce\\Internal\\DataStores\\Orders\\OrdersTableDataStoreMeta\:\:update_meta\(\) expects stdClass, WC_Meta_Data given\.$#'
identifier: argument.type
count: 1
path: src/Internal/DataStores/Orders/OrdersTableDataStore.php
- -
- message: '#^Parameter \#2 \$meta of method Automattic\\WooCommerce\\Internal\\DataStores\\Orders\\OrdersTableDataStoreMeta\:\:update_meta\(\) expects stdClass, false given\.$#'
- identifier: argument.type
- count: 1
- path: src/Internal/DataStores/Orders/OrdersTableDataStore.php
-
-
message: '#^Parameter \#2 \$output of function get_object_taxonomies expects ''names''\|''objects'', ''object'' given\.$#'
identifier: argument.type
@@ -70554,12 +70494,6 @@ parameters:
count: 1
path: src/Internal/DataStores/Orders/OrdersTableRefundDataStore.php
- -
- message: '#^Cannot access offset 0 on stdClass\|true\.$#'
- identifier: offsetAccess.nonOffsetAccessible
- count: 1
- path: src/Internal/DataStores/Orders/OrdersTableRefundDataStore.php
-
-
message: '#^Method Automattic\\WooCommerce\\Internal\\DataStores\\Orders\\OrdersTableRefundDataStore\:\:create\(\) has no return type specified\.$#'
identifier: missingType.return
diff --git a/plugins/woocommerce/src/Internal/DataStores/CustomMetaDataStore.php b/plugins/woocommerce/src/Internal/DataStores/CustomMetaDataStore.php
index 50a349470b..6da2d56242 100644
--- a/plugins/woocommerce/src/Internal/DataStores/CustomMetaDataStore.php
+++ b/plugins/woocommerce/src/Internal/DataStores/CustomMetaDataStore.php
@@ -204,7 +204,7 @@ abstract class CustomMetaDataStore {
* @param \WC_Data $object Object ID.
* @param string $meta_key Meta key.
*
- * @return \stdClass|bool Metadata object or FALSE if not found.
+ * @return \stdClass[]|false Metadata object or FALSE if not found.
*/
public function get_metadata_by_key( &$object, string $meta_key ) {
global $wpdb;
diff --git a/plugins/woocommerce/src/Internal/DataStores/Orders/OrdersTableDataStore.php b/plugins/woocommerce/src/Internal/DataStores/Orders/OrdersTableDataStore.php
index 21c0087b7c..bd0881493c 100644
--- a/plugins/woocommerce/src/Internal/DataStores/Orders/OrdersTableDataStore.php
+++ b/plugins/woocommerce/src/Internal/DataStores/Orders/OrdersTableDataStore.php
@@ -1402,8 +1402,8 @@ WHERE
$this->init_order_record( $order, $order_id, $order_data );
- if ( $order->has_cogs() && $cogs_is_enabled ) {
- $this->read_cogs_data( $order );
+ if ( $cogs_is_enabled && $order->has_cogs() ) {
+ $this->read_cogs_data( $order, $order_data->meta_data );
}
if ( $data_sync_enabled && isset( $post_orders[ $order_id ] ) && $this->should_sync_order( $order ) ) {
@@ -1416,11 +1416,12 @@ WHERE
/**
* Read the Cost of Goods Sold value for a given order from the database, if available, and apply it to the order.
*
- * @param \WC_Abstract_Order $order The order to get the COGS value for.
+ * @param \WC_Abstract_Order $order The order to get the COGS value for.
+ * @param object{meta_key:string,meta_value:string}[] $meta_data The original meta-data fetched for the order.
*/
- private function read_cogs_data( WC_Abstract_Order $order ) {
- $meta_entry = $this->data_store_meta->get_metadata_by_key( $order, '_cogs_total_value' );
- $cogs_value = false === $meta_entry ? 0 : (float) current( $meta_entry )->meta_value;
+ private function read_cogs_data( WC_Abstract_Order $order, array $meta_data ) {
+ $meta_entry = array_filter( $meta_data, fn( object $meta ) => '_cogs_total_value' === $meta->meta_key );
+ $cogs_value = array() === $meta_entry ? 0 : (float) current( $meta_entry )->meta_value;
/**
* Filter to customize the Cost of Goods Sold value that gets loaded for a given order.