Commit 061221e10ab for woocommerce

commit 061221e10ab2cc1d839dcadab03698144fcff19b
Author: Ján Mikláš <neosinner@gmail.com>
Date:   Sun Sep 13 23:28:55 2026 +0200

    Document Analytics customer hook timing (#68679)

    * Document Analytics customer hook timing

    * Add changelog entry for customer hook timing

    * Remove trailing changelog whitespace

diff --git a/plugins/woocommerce/changelog/docs-analytics-customer-hook-timing b/plugins/woocommerce/changelog/docs-analytics-customer-hook-timing
new file mode 100644
index 00000000000..b7a0a1b28b3
--- /dev/null
+++ b/plugins/woocommerce/changelog/docs-analytics-customer-hook-timing
@@ -0,0 +1,3 @@
+Significance: patch
+Type: dev
+Comment: Document Analytics customer creation hook timing and cover repeated customer-history views and imports.
diff --git a/plugins/woocommerce/src/Admin/API/Reports/Customers/DataStore.php b/plugins/woocommerce/src/Admin/API/Reports/Customers/DataStore.php
index 9002e69b9af..1b6a47104e9 100644
--- a/plugins/woocommerce/src/Admin/API/Reports/Customers/DataStore.php
+++ b/plugins/woocommerce/src/Admin/API/Reports/Customers/DataStore.php
@@ -727,6 +727,9 @@ class DataStore extends ReportsDataStore implements DataStoreInterface {
 		/**
 		 * Fires when a new report customer is created.
 		 *
+		 * This includes customers created during Analytics import. Rendering the order-edit
+		 * customer history panel uses a read-only lookup and does not fire this action.
+		 *
 		 * @param int $customer_id Customer ID.
 		 * @since 4.0.0
 		 */
diff --git a/plugins/woocommerce/tests/php/src/Internal/Admin/Orders/MetaBoxes/CustomerHistoryTest.php b/plugins/woocommerce/tests/php/src/Internal/Admin/Orders/MetaBoxes/CustomerHistoryTest.php
index 05955ee0262..4c7e61ac7a3 100644
--- a/plugins/woocommerce/tests/php/src/Internal/Admin/Orders/MetaBoxes/CustomerHistoryTest.php
+++ b/plugins/woocommerce/tests/php/src/Internal/Admin/Orders/MetaBoxes/CustomerHistoryTest.php
@@ -769,14 +769,17 @@ class CustomerHistoryTest extends WC_Unit_Test_Case {
 		\WC_Helper_Reports::reset_stats_dbs();

 		$new_customer_fired = 0;
-		$callback           = static function () use ( &$new_customer_fired ) {
+		$new_customer_id    = null;
+		$callback           = static function ( $customer_id ) use ( &$new_customer_fired, &$new_customer_id ) {
 			++$new_customer_fired;
+			$new_customer_id = $customer_id;
 		};
 		add_action( 'woocommerce_analytics_new_customer', $callback );

 		try {
 			ob_start();
 			try {
+				$this->sut->output( $order );
 				$this->sut->output( $order );
 				$output = (string) ob_get_contents();
 			} finally {
@@ -788,6 +791,17 @@ class CustomerHistoryTest extends WC_Unit_Test_Case {
 			$customers_after_render     = (int) $wpdb->get_var( "SELECT COUNT(*) FROM {$customer_lookup_table}" );
 			$new_customers_after_render = $new_customer_fired;

+			OrdersStatsDataStore::update( new AdminOrder( $order->get_id() ) );
+			$this->assertSame( 1, $new_customer_fired, 'The first import should fire the new-customer action once.' );
+			$this->assertSame( (int) CustomersDataStore::get_existing_customer_id_from_order( $order ), $new_customer_id, 'The action should receive the analytics customer ID linked to the order.' );
+
+			ob_start();
+			try {
+				$this->sut->output( $order );
+				$this->sut->output( $order );
+			} finally {
+				ob_end_clean();
+			}
 			OrdersStatsDataStore::update( new AdminOrder( $order->get_id() ) );

 			// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- Table name is provided by the data store.
@@ -799,8 +813,8 @@ class CustomerHistoryTest extends WC_Unit_Test_Case {
 		$this->assertStringContainsString( 'order-attribution-total-orders', $output, 'Should render the metabox template.' );
 		$this->assertSame( 0, $customers_after_render, 'Rendering customer history should not create an analytics customer.' );
 		$this->assertSame( 0, $new_customers_after_render, 'Rendering customer history should not fire the new-customer action.' );
-		$this->assertSame( 1, $customers_after_import, 'Importing the order should create one analytics customer.' );
-		$this->assertSame( 1, $new_customer_fired, 'Importing the order should fire the new-customer action once.' );
+		$this->assertSame( 1, $customers_after_import, 'Repeated views and imports should reuse the analytics customer.' );
+		$this->assertSame( 1, $new_customer_fired, 'Repeated views and imports should not fire the new-customer action again.' );
 	}

 	/**