Commit 72c56a65c1 for woocommerce

commit 72c56a65c1a8f6d27541984b7520abb1fd779bd4
Author: Vladimir Reznichenko <kalessil@gmail.com>
Date:   Mon Jan 26 08:57:55 2026 +0100

    [Performance] Tracks: defer `product_add_publish` event when importing products. (#62888)

    When `Allow usage of WooCommerce to be tracked` is enabled in settings, deferred event tracking improves products import performance.

diff --git a/plugins/woocommerce/changelog/performance-61316-defer-product-published-tracks-when-importing b/plugins/woocommerce/changelog/performance-61316-defer-product-published-tracks-when-importing
new file mode 100644
index 0000000000..15214cd359
--- /dev/null
+++ b/plugins/woocommerce/changelog/performance-61316-defer-product-published-tracks-when-importing
@@ -0,0 +1,4 @@
+Significance: patch
+Type: performance
+
+Products: defer publishing the 'product_add_publish' Tracks-event when importing products.
diff --git a/plugins/woocommerce/includes/tracks/class-wc-site-tracking.php b/plugins/woocommerce/includes/tracks/class-wc-site-tracking.php
index ace7306b2a..69462ae3f0 100644
--- a/plugins/woocommerce/includes/tracks/class-wc-site-tracking.php
+++ b/plugins/woocommerce/includes/tracks/class-wc-site-tracking.php
@@ -234,6 +234,24 @@ class WC_Site_Tracking {
 				call_user_func( $tracker_init_method );
 			}
 		}
+
+		add_filter( 'pre_update_option_woocommerce_allow_tracking', array( __CLASS__, 'maybe_unschedule_deferred_tracks' ) );
+	}
+
+	/**
+	 * When the tracking is getting disabled, unschedules all deferred tracks.
+	 *
+	 * @internal
+	 * @since 10.6.0
+	 *
+	 * @param string $new_option_value The new, unserialized option value.
+	 * @return string
+	 */
+	public static function maybe_unschedule_deferred_tracks( $new_option_value ) {
+		if ( 'yes' !== $new_option_value ) {
+			as_unschedule_all_actions( '', array(), 'woocommerce-tracks' );
+		}
+		return $new_option_value;
 	}

 	/**
diff --git a/plugins/woocommerce/includes/tracks/events/class-wc-products-tracking.php b/plugins/woocommerce/includes/tracks/events/class-wc-products-tracking.php
index 026e611bb4..971a77c14a 100644
--- a/plugins/woocommerce/includes/tracks/events/class-wc-products-tracking.php
+++ b/plugins/woocommerce/includes/tracks/events/class-wc-products-tracking.php
@@ -20,7 +20,15 @@ class WC_Products_Tracking {
 	/**
 	 * Tracks source.
 	 */
-	const TRACKS_SOURCE = 'product-legacy-editor';
+	public const TRACKS_SOURCE = 'product-legacy-editor';
+
+	/**
+	 * Deferred Tracks callback.
+	 *
+	 * @internal
+	 * @since 10.6.0
+	 */
+	public const TRACK_PRODUCT_PUBLISHED_CALLBACK = 'track_product_published';

 	/**
 	 * Init tracking.
@@ -37,6 +45,7 @@ class WC_Products_Tracking {
 		add_action( 'admin_enqueue_scripts', array( $this, 'possibly_add_product_import_scripts' ) );
 		add_action( 'admin_enqueue_scripts', array( $this, 'possibly_add_attribute_tracking_scripts' ) );
 		add_action( 'admin_enqueue_scripts', array( $this, 'possibly_add_tag_tracking_scripts' ) );
+		add_action( self::TRACK_PRODUCT_PUBLISHED_CALLBACK, array( $this, 'track_product_published_maybe_defer' ), 10, 3 );
 	}

 	/**
@@ -331,7 +340,8 @@ class WC_Products_Tracking {
 		$product_type_options        = self::get_product_type_options( $post_id );
 		$product_type_options_string = self::get_product_type_options_string( $product_type_options );

-		$properties = array(
+		$is_importing = self::is_importing();
+		$properties   = array(
 			'attributes'           => count( $product->get_attributes() ),
 			'categories'           => count( $product->get_category_ids() ),
 			'cross_sells'          => ! empty( $product->get_cross_sell_ids() ) ? 'yes' : 'no',
@@ -349,7 +359,7 @@ class WC_Products_Tracking {
 			'product_type_options' => $product_type_options_string,
 			'purchase_note'        => $product->get_purchase_note() ? 'yes' : 'no',
 			'sale_price'           => $product->get_sale_price() ? 'yes' : 'no',
-			'source'               => apply_filters( 'woocommerce_product_source', self::is_importing() ? 'import' : self::TRACKS_SOURCE ),
+			'source'               => apply_filters( 'woocommerce_product_source', $is_importing ? 'import' : self::TRACKS_SOURCE ),
 			'short_description'    => $product->get_short_description() ? 'yes' : 'no',
 			'tags'                 => count( $product->get_tag_ids() ),
 			'upsells'              => ! empty( $product->get_upsell_ids() ) ? 'yes' : 'no',
@@ -357,7 +367,31 @@ class WC_Products_Tracking {
 			'global_unique_id'     => $product->get_global_unique_id() ? 'yes' : 'no',
 		);

-		WC_Tracks::record_event( 'product_add_publish', $properties );
+		$this->track_product_published_maybe_defer( 'product_add_publish', $properties, $is_importing );
+	}
+
+	/**
+	 * Tracks the event, allowing deferred/asynchronous event recording.
+	 *
+	 * @internal
+	 * @since 10.6.0
+	 *
+	 * @param string $event_name       The name of the event.
+	 * @param array  $event_properties Custom properties to send with the event.
+	 * @param bool   $defer            Whether to defer the event publishing.
+	 * @return void
+	 */
+	public function track_product_published_maybe_defer( string $event_name, array $event_properties, bool $defer = false ): void {
+		if ( $defer ) {
+			as_schedule_single_action(
+				time(),
+				self::TRACK_PRODUCT_PUBLISHED_CALLBACK,
+				array( $event_name, $event_properties ),
+				'woocommerce-tracks'
+			);
+		} else {
+			WC_Tracks::record_event( $event_name, $event_properties );
+		}
 	}

 	/**
diff --git a/plugins/woocommerce/tests/php/includes/class-wc-products-tracking-test.php b/plugins/woocommerce/tests/php/includes/class-wc-products-tracking-test.php
index c7ef03bc55..2574b60fb1 100644
--- a/plugins/woocommerce/tests/php/includes/class-wc-products-tracking-test.php
+++ b/plugins/woocommerce/tests/php/includes/class-wc-products-tracking-test.php
@@ -118,4 +118,20 @@ class WC_Products_Tracking_Test extends \WC_Unit_Test_Case {
 		do_action( 'load-edit.php' );
 		$this->assertRecordedTracksEvent( 'wcadmin_products_search' );
 	}
+
+	/**
+	 * Test if track_product_published is deferring the even publishing for imports.
+	 */
+	public function test_track_product_published_deferred_when_importing(): void {
+		$_POST['action'] = 'woocommerce_do_ajax_product_import';
+		$this->assertFalse( as_has_scheduled_action( WC_Products_Tracking::TRACK_PRODUCT_PUBLISHED_CALLBACK, null, 'woocommerce-tracks' ) );
+
+		$product = new WC_Product_Simple();
+		$product->set_name( 'New name' );
+		$product->set_status( ProductStatus::PUBLISH );
+		$product->save();
+
+		$this->assertTrue( as_has_scheduled_action( WC_Products_Tracking::TRACK_PRODUCT_PUBLISHED_CALLBACK, null, 'woocommerce-tracks' ) );
+		as_unschedule_all_actions( WC_Products_Tracking::TRACK_PRODUCT_PUBLISHED_CALLBACK, null, 'woocommerce-tracks' );
+	}
 }