Commit df1dc8f4fe5 for woocommerce

commit df1dc8f4fe575b39daa2f9880792a367b60b3ce4
Author: Vladimir Reznichenko <kalessil@gmail.com>
Date:   Fri Jul 24 13:00:33 2026 +0200

    [Performance] Reduce the number of SQL queries on the cart page for multi-product carts (#66774)

    This PR introduces the following changes:
    - cache priming for variations when populating the cart from the session
    - request-level cache for fetching tax rates in order to reduce the number of SQL queries on the cart page

diff --git a/plugins/woocommerce/changelog/perfromance-reduce-sqls-cart-page b/plugins/woocommerce/changelog/perfromance-reduce-sqls-cart-page
new file mode 100644
index 00000000000..f89b108fefc
--- /dev/null
+++ b/plugins/woocommerce/changelog/perfromance-reduce-sqls-cart-page
@@ -0,0 +1,4 @@
+Significance: minor
+Type: performance
+
+Reduced the number of SQL queries on the cart page for multi-product carts.
diff --git a/plugins/woocommerce/includes/class-wc-cart-session.php b/plugins/woocommerce/includes/class-wc-cart-session.php
index c99bd9b39cd..676503adeb9 100644
--- a/plugins/woocommerce/includes/class-wc-cart-session.php
+++ b/plugins/woocommerce/includes/class-wc-cart-session.php
@@ -133,7 +133,9 @@ final class WC_Cart_Session {

 		if ( ! empty( $cart ) ) {
 			// Prime caches to reduce future queries.
-			_prime_post_caches( wp_list_pluck( $cart, 'product_id' ) );
+			$product_ids    = array_filter( array_column( $cart, 'product_id' ) );
+			$variations_ids = array_filter( array_column( $cart, 'variation_id' ) );
+			_prime_post_caches( array_merge( $product_ids, $variations_ids ) );
 		}

 		$cart_contents = array();
diff --git a/plugins/woocommerce/src/Internal/Tax/TaxRateDataStore.php b/plugins/woocommerce/src/Internal/Tax/TaxRateDataStore.php
index 9d48c9c15e1..09c69de3bd6 100644
--- a/plugins/woocommerce/src/Internal/Tax/TaxRateDataStore.php
+++ b/plugins/woocommerce/src/Internal/Tax/TaxRateDataStore.php
@@ -8,6 +8,12 @@ namespace Automattic\WooCommerce\Internal\Tax;
  * Data store for tax rates.
  */
 class TaxRateDataStore {
+	/**
+	 * Request-level cache of fetched tax rate rows, keyed by tax_rate_id.
+	 *
+	 * @var array<int,object>
+	 */
+	private array $rate_objects_cache = array();

 	/**
 	 * Fetch multiple tax rate rows in a single query, keyed by tax_rate_id.
@@ -18,20 +24,26 @@ class TaxRateDataStore {
 	 * @return array<int,object>
 	 */
 	public function get_rate_objects_for_ids( array $ids ): array {
-		$tax_rate_objects = array();
-		$ids              = array_values( array_filter( array_map( 'absint', array_unique( $ids ) ) ) );
-
-		if ( ! empty( $ids ) ) {
-			global $wpdb;
+		global $wpdb;

-			$list = implode( ', ', $ids );
+		$ids          = array_filter( array_map( 'absint', array_unique( $ids ) ) );
+		$uncached_ids = array_diff( $ids, array_keys( $this->rate_objects_cache ) );
+		if ( ! empty( $uncached_ids ) ) {
+			$list = implode( ', ', $uncached_ids );
 			// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
 			$rows = $wpdb->get_results( "SELECT * FROM {$wpdb->prefix}woocommerce_tax_rates WHERE tax_rate_id IN ( $list )" );
 			foreach ( $rows as $row ) {
-				$tax_rate_objects[ (int) $row->tax_rate_id ] = $row;
+				$this->rate_objects_cache[ (int) $row->tax_rate_id ] = $row;
+			}
+		}
+
+		$result = array();
+		foreach ( $ids as $id ) {
+			if ( isset( $this->rate_objects_cache[ $id ] ) ) {
+				$result[ $id ] = $this->rate_objects_cache[ $id ];
 			}
 		}

-		return $tax_rate_objects;
+		return $result;
 	}
 }
diff --git a/plugins/woocommerce/tests/php/src/Internal/Tax/TaxRateDataStoreTest.php b/plugins/woocommerce/tests/php/src/Internal/Tax/TaxRateDataStoreTest.php
index 14c176169f7..2248b157e24 100644
--- a/plugins/woocommerce/tests/php/src/Internal/Tax/TaxRateDataStoreTest.php
+++ b/plugins/woocommerce/tests/php/src/Internal/Tax/TaxRateDataStoreTest.php
@@ -25,29 +25,46 @@ class TaxRateDataStoreTest extends \WC_Unit_Test_Case {
 	}

 	/**
-	 * @testdox get_rate_objects_for_ids() deduplicates mixed int/string IDs and returns a map keyed by int tax_rate_id.
+	 * @testdox get_rate_objects_for_ids() deduplicates mixed int/string IDs, returns a map keyed by int tax_rate_id, and serves subsequent calls from the request-level cache.
 	 */
 	public function test_get_rate_objects_for_ids(): void {
-		// Arrange.
-		$tax_rate    = array(
-			'tax_rate_country'  => 'DE',
-			'tax_rate_state'    => '',
-			'tax_rate'          => '19.0000',
-			'tax_rate_name'     => 'VAT',
-			'tax_rate_priority' => '1',
-			'tax_rate_compound' => '1',
-			'tax_rate_shipping' => '1',
-			'tax_rate_order'    => '1',
-			'tax_rate_class'    => '',
+		// Arrange: two GB rates as seen on a cart with standard + reduced VAT.
+		$standard_id = \WC_Tax::_insert_tax_rate(
+			array(
+				'tax_rate_country'  => 'GB',
+				'tax_rate_state'    => '',
+				'tax_rate'          => '20.0000',
+				'tax_rate_name'     => 'Standard Rate',
+				'tax_rate_priority' => '1',
+				'tax_rate_compound' => '0',
+				'tax_rate_shipping' => '1',
+				'tax_rate_order'    => '1',
+				'tax_rate_class'    => '',
+			)
 		);
-		$tax_rate_id = \WC_Tax::_insert_tax_rate( $tax_rate );
+		$reduced_id  = \WC_Tax::_insert_tax_rate(
+			array(
+				'tax_rate_country'  => 'GB',
+				'tax_rate_state'    => '',
+				'tax_rate'          => '5.0000',
+				'tax_rate_name'     => 'Reduced Rate',
+				'tax_rate_priority' => '1',
+				'tax_rate_compound' => '0',
+				'tax_rate_shipping' => '0',
+				'tax_rate_order'    => '2',
+				'tax_rate_class'    => 'reduced-rate',
+			)
+		);
+
+		// Act: deduplication — pass standard_id as both int and string, plus a non-existent ID.
+		$ids    = array( $reduced_id, $standard_id, (string) $standard_id, PHP_INT_MAX );
+		$result = $this->sut->get_rate_objects_for_ids( $ids );

-		// Act.
-		$result = $this->sut->get_rate_objects_for_ids( array( $tax_rate_id, (string) $tax_rate_id, PHP_INT_MAX ) );
+		// Assert: both rates present, each keyed by its own ID with correct values.
+		$this->assertSame( array( $reduced_id, $standard_id ), array_keys( $result ) );
+		$this->assertSame( array( '5.0000', '20.0000' ), array_column( $result, 'tax_rate' ) );

-		// Assert.
-		$this->assertCount( 1, $result );
-		$this->assertSame( array( $tax_rate_id ), array_keys( $result ) );
-		$this->assertSame( 'VAT', $result[ $tax_rate_id ]->tax_rate_name );
+		// Verify a third call (full cache hit) returns identical result.
+		$this->assertSame( $result, $this->sut->get_rate_objects_for_ids( $ids ) );
 	}
 }