Commit 7ba1bdbc9a for woocommerce

commit 7ba1bdbc9a4bbb2e95e13e2ba93a55268bfc8911
Author: Alba Rincón <albarin@users.noreply.github.com>
Date:   Fri Feb 13 09:34:34 2026 +0100

    Defer `has_products()` check to shutdown hook for bulk delete/trash (#63261)

    * Defer has_products() check to shutdown hook for bulk operations

    When bulk-trashing or bulk-deleting products, revert_task_completion()
    was firing once per product, each triggering a has_products() DB query.
    This defers the check to a shutdown hook using a static flag so that
    bulk operations only run a single query at the end of the request.

    * Add changefile(s) from automation for the following project(s): woocommerce

    ---------

    Co-authored-by: woocommercebot <woocommercebot@users.noreply.github.com>

diff --git a/plugins/woocommerce/changelog/63261-fix-products-task-bulk-trash-performance b/plugins/woocommerce/changelog/63261-fix-products-task-bulk-trash-performance
new file mode 100644
index 0000000000..128589a287
--- /dev/null
+++ b/plugins/woocommerce/changelog/63261-fix-products-task-bulk-trash-performance
@@ -0,0 +1,4 @@
+Significance: minor
+Type: performance
+
+Defer has_products() check to shutdown hook for bulk delete/trash products.
\ No newline at end of file
diff --git a/plugins/woocommerce/src/Admin/Features/OnboardingTasks/Tasks/Products.php b/plugins/woocommerce/src/Admin/Features/OnboardingTasks/Tasks/Products.php
index 90f06cbd8c..14dc0147fb 100644
--- a/plugins/woocommerce/src/Admin/Features/OnboardingTasks/Tasks/Products.php
+++ b/plugins/woocommerce/src/Admin/Features/OnboardingTasks/Tasks/Products.php
@@ -13,6 +13,13 @@ use Automattic\WooCommerce\Internal\Admin\Onboarding\OnboardingProfile;
 class Products extends Task {
 	const HAS_PRODUCT_TRANSIENT = 'woocommerce_product_task_has_product_transient';

+	/**
+	 * Whether a deferred revert check has already been scheduled for this request.
+	 *
+	 * @var bool
+	 */
+	private static $revert_scheduled = false;
+
 	/**
 	 * Constructor
 	 *
@@ -206,13 +213,34 @@ class Products extends Task {
 	}

 	/**
-	 * Re-check whether valid products still exist and revert task completion if none remain.
+	 * Schedule a deferred check to revert task completion if no products remain.
+	 *
+	 * Uses the shutdown hook so that bulk operations (e.g. trashing many products
+	 * at once) only trigger a single has_products() query instead of one per product.
 	 *
 	 * @return void
 	 */
-	private function revert_task_completion() {
+	private function revert_task_completion(): void {
 		delete_transient( self::HAS_PRODUCT_TRANSIENT );

+		if ( self::$revert_scheduled ) {
+			return;
+		}
+
+		self::$revert_scheduled = true;
+		add_action( 'shutdown', array( $this, 'maybe_revert_on_shutdown' ) );
+	}
+
+	/**
+	 * Re-check whether valid products still exist and revert task completion if none remain.
+	 *
+	 * Runs once at the end of the request via the shutdown hook.
+	 *
+	 * @return void
+	 */
+	public function maybe_revert_on_shutdown(): void {
+		self::$revert_scheduled = false;
+
 		if ( self::has_products() ) {
 			return;
 		}