Commit afbdcfa65e5 for woocommerce

commit afbdcfa65e529df362b6ded698ee04392764fdb3
Author: Jan Lysý <lysyjan@users.noreply.github.com>
Date:   Fri Aug 14 07:46:46 2026 +0200

    Restore Taxes report orders_count filter string, fix cache gap (#67679)

    Restore filter-carried orders_count SQL and close add_option cache gap

    Follow-up to #67553 addressing internal regression-review findings:

    - Revert the orders_count parent_id qualification in both Taxes data
      stores. The report_columns array is carried by the public
      woocommerce_admin_report_columns filter, so the released unqualified
      string is a contract for extension callbacks that inspect or rewrite
      it. Unqualified parent_id is unambiguous on every query path since
      wc_order_stats is the only joined table carrying that column and the
      join is now unconditional.
    - Also hook add_option_woocommerce_date_type for report cache
      invalidation: the first-ever save of the option takes the add_option
      path, where the update_option hook never fires.

    Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>

diff --git a/plugins/woocommerce/changelog/fix-wooairr-48-taxes-report-columns-bc b/plugins/woocommerce/changelog/fix-wooairr-48-taxes-report-columns-bc
new file mode 100644
index 00000000000..40b9a685706
--- /dev/null
+++ b/plugins/woocommerce/changelog/fix-wooairr-48-taxes-report-columns-bc
@@ -0,0 +1,4 @@
+Significance: patch
+Type: fix
+
+Analytics: restore the released unqualified parent_id form of the Taxes orders_count column carried by the woocommerce_admin_report_columns filter, and invalidate report caches on the first-ever save of the analytics date type.
diff --git a/plugins/woocommerce/src/Admin/API/Reports/Taxes/DataStore.php b/plugins/woocommerce/src/Admin/API/Reports/Taxes/DataStore.php
index d2a9f6752e9..34c78c974ac 100644
--- a/plugins/woocommerce/src/Admin/API/Reports/Taxes/DataStore.php
+++ b/plugins/woocommerce/src/Admin/API/Reports/Taxes/DataStore.php
@@ -87,8 +87,7 @@ class DataStore extends ReportsDataStore implements DataStoreInterface {
 	 */
 	protected function assign_report_columns() {
 		global $wpdb;
-		$table_name        = self::get_db_table_name();
-		$order_stats_table = $wpdb->prefix . 'wc_order_stats';
+		$table_name = self::get_db_table_name();

 		// Using wp_woocommerce_tax_rates table limits the result to only the existing tax rates and
 		// omits the historical records which differs from the purpose of wp_wc_order_tax_lookup table.
@@ -108,8 +107,10 @@ class DataStore extends ReportsDataStore implements DataStoreInterface {
 			'total_tax'    => 'SUM(total_tax) as total_tax',
 			'order_tax'    => 'SUM(order_tax) as order_tax',
 			'shipping_tax' => 'SUM(shipping_tax) as shipping_tax',
-			// parent_id is qualified to wc_order_stats to stay unambiguous now that the join is always present.
-			'orders_count' => "COUNT( DISTINCT ( CASE WHEN {$order_stats_table}.parent_id = 0 THEN {$table_name}.order_id END ) ) as orders_count",
+			// parent_id stays unqualified: wc_order_stats is the only joined table carrying it, and
+			// this string is carried by the public woocommerce_admin_report_columns filter, so it must
+			// match the released form for extension callbacks that inspect or rewrite it.
+			'orders_count' => "COUNT( DISTINCT ( CASE WHEN parent_id = 0 THEN {$table_name}.order_id END ) ) as orders_count",
 		);
 	}

diff --git a/plugins/woocommerce/src/Admin/API/Reports/Taxes/Stats/DataStore.php b/plugins/woocommerce/src/Admin/API/Reports/Taxes/Stats/DataStore.php
index ca82185bd1f..f1c15045b6a 100644
--- a/plugins/woocommerce/src/Admin/API/Reports/Taxes/Stats/DataStore.php
+++ b/plugins/woocommerce/src/Admin/API/Reports/Taxes/Stats/DataStore.php
@@ -81,16 +81,16 @@ class DataStore extends ReportsDataStore implements DataStoreInterface {
 	 * @override ReportsDataStore::assign_report_columns()
 	 */
 	protected function assign_report_columns() {
-		global $wpdb;
 		$table_name           = self::get_db_table_name();
-		$order_stats_table    = $wpdb->prefix . 'wc_order_stats';
 		$this->report_columns = array(
 			'tax_codes'    => 'COUNT(DISTINCT tax_rate_id) as tax_codes',
 			'total_tax'    => 'SUM(total_tax) AS total_tax',
 			'order_tax'    => 'SUM(order_tax) as order_tax',
 			'shipping_tax' => 'SUM(shipping_tax) as shipping_tax',
-			// parent_id is qualified to wc_order_stats to stay unambiguous now that the join is always present.
-			'orders_count' => "COUNT( DISTINCT ( CASE WHEN {$order_stats_table}.parent_id = 0 THEN {$table_name}.order_id END ) ) as orders_count",
+			// parent_id stays unqualified: wc_order_stats is the only joined table carrying it, and
+			// this string is carried by the public woocommerce_admin_report_columns filter, so it must
+			// match the released form for extension callbacks that inspect or rewrite it.
+			'orders_count' => "COUNT( DISTINCT ( CASE WHEN parent_id = 0 THEN {$table_name}.order_id END ) ) as orders_count",
 		);
 	}

diff --git a/plugins/woocommerce/src/Admin/ReportsSync.php b/plugins/woocommerce/src/Admin/ReportsSync.php
index 7ef88d05b1a..9b96649b0b3 100644
--- a/plugins/woocommerce/src/Admin/ReportsSync.php
+++ b/plugins/woocommerce/src/Admin/ReportsSync.php
@@ -30,6 +30,8 @@ class ReportsSync {
 		add_action( 'update_option_woocommerce_notify_no_stock_amount', array( __CLASS__, 'clear_stock_count_cache' ) );
 		// Invalidate report caches when the analytics date type changes, so all report families
 		// (Orders, Revenue, Taxes) reflect the new date basis immediately instead of after the cache TTL.
+		// The very first save of the option takes the add_option path, so hook both.
+		add_action( 'add_option_woocommerce_date_type', array( ReportsCache::class, 'invalidate' ) );
 		add_action( 'update_option_woocommerce_date_type', array( ReportsCache::class, 'invalidate' ) );
 		add_action( 'trashed_post', array( __CLASS__, 'maybe_clear_stock_count_cache_for_post' ) );
 		add_action( 'untrashed_post', array( __CLASS__, 'maybe_clear_stock_count_cache_for_post' ) );
diff --git a/plugins/woocommerce/tests/php/src/Admin/API/Reports/Taxes/DataStoreTest.php b/plugins/woocommerce/tests/php/src/Admin/API/Reports/Taxes/DataStoreTest.php
index afb9291b37d..22f2a6cea9f 100644
--- a/plugins/woocommerce/tests/php/src/Admin/API/Reports/Taxes/DataStoreTest.php
+++ b/plugins/woocommerce/tests/php/src/Admin/API/Reports/Taxes/DataStoreTest.php
@@ -290,6 +290,10 @@ class DataStoreTest extends WC_Unit_Test_Case {
 			has_action( 'update_option_woocommerce_date_type', array( ReportsCache::class, 'invalidate' ) ),
 			'Changing the analytics date type should invalidate the report cache so all report families reflect the new basis immediately.'
 		);
+		$this->assertNotFalse(
+			has_action( 'add_option_woocommerce_date_type', array( ReportsCache::class, 'invalidate' ) ),
+			'The very first save of the date type takes the add_option path and should invalidate the report cache too.'
+		);
 	}

 	/**