Commit 1de1607e7c for woocommerce

commit 1de1607e7cc6bd6c0e2d694af2f460836a08ebc9
Author: Leonardo Lopes de Albuquerque <leonardo.albuquerque@automattic.com>
Date:   Sun Jan 11 20:52:22 2026 -0300

    [Fraud Protection] Added tracking to visits to checkout and cart pages (#62745)

    * Dispatch event when a customer visits the checkout page

    * Dispatch event when a customer visits the cart page

    * Dispatch event when a customer visits add payment method page in My Account area

diff --git a/plugins/woocommerce/includes/shortcodes/class-wc-shortcode-cart.php b/plugins/woocommerce/includes/shortcodes/class-wc-shortcode-cart.php
index f273e52669..14430ef0c6 100644
--- a/plugins/woocommerce/includes/shortcodes/class-wc-shortcode-cart.php
+++ b/plugins/woocommerce/includes/shortcodes/class-wc-shortcode-cart.php
@@ -8,6 +8,9 @@
  * @version 2.3.0
  */

+use Automattic\WooCommerce\Internal\FraudProtection\CartEventTracker;
+use Automattic\WooCommerce\Internal\FraudProtection\FraudProtectionController;
+
 defined( 'ABSPATH' ) || exit;

 /**
@@ -78,6 +81,12 @@ class WC_Shortcode_Cart {
 		// Constants.
 		wc_maybe_define_constant( 'WOOCOMMERCE_CART', true );

+		// Track cart page loaded for fraud protection.
+		if ( wc_get_container()->get( FraudProtectionController::class )->feature_is_enabled() ) {
+			wc_get_container()->get( CartEventTracker::class )
+				->track_cart_page_loaded();
+		}
+
 		$atts        = shortcode_atts( array(), $atts, 'woocommerce_cart' );
 		$nonce_value = wc_get_var( $_REQUEST['woocommerce-shipping-calculator-nonce'], wc_get_var( $_REQUEST['_wpnonce'], '' ) ); // @codingStandardsIgnoreLine.

diff --git a/plugins/woocommerce/includes/shortcodes/class-wc-shortcode-checkout.php b/plugins/woocommerce/includes/shortcodes/class-wc-shortcode-checkout.php
index 46faae2384..33176cf2f1 100644
--- a/plugins/woocommerce/includes/shortcodes/class-wc-shortcode-checkout.php
+++ b/plugins/woocommerce/includes/shortcodes/class-wc-shortcode-checkout.php
@@ -11,6 +11,8 @@
 defined( 'ABSPATH' ) || exit;

 use Automattic\WooCommerce\Enums\OrderStatus;
+use Automattic\WooCommerce\Internal\FraudProtection\CheckoutEventTracker;
+use Automattic\WooCommerce\Internal\FraudProtection\FraudProtectionController;
 use Automattic\WooCommerce\Internal\Utilities\Users;

 /**
@@ -345,6 +347,12 @@ class WC_Shortcode_Checkout {
 			return;
 		}

+		// Track checkout page loaded for fraud protection.
+		if ( wc_get_container()->get( FraudProtectionController::class )->feature_is_enabled() ) {
+			wc_get_container()->get( CheckoutEventTracker::class )
+				->track_checkout_page_loaded();
+		}
+
 		// Check cart contents for errors.
 		do_action( 'woocommerce_check_cart_items' );

diff --git a/plugins/woocommerce/includes/shortcodes/class-wc-shortcode-my-account.php b/plugins/woocommerce/includes/shortcodes/class-wc-shortcode-my-account.php
index 38d5b12e0d..899e6ea65a 100644
--- a/plugins/woocommerce/includes/shortcodes/class-wc-shortcode-my-account.php
+++ b/plugins/woocommerce/includes/shortcodes/class-wc-shortcode-my-account.php
@@ -8,6 +8,9 @@
  * @version 2.0.0
  */

+use Automattic\WooCommerce\Internal\FraudProtection\FraudProtectionController;
+use Automattic\WooCommerce\Internal\FraudProtection\PaymentMethodEventTracker;
+
 defined( 'ABSPATH' ) || exit;

 /**
@@ -409,6 +412,12 @@ class WC_Shortcode_My_Account {
 			wp_safe_redirect( wc_get_page_permalink( 'myaccount' ) );
 			exit();
 		} else {
+			// Track add payment method page loaded for fraud protection.
+			if ( wc_get_container()->get( FraudProtectionController::class )->feature_is_enabled() ) {
+				wc_get_container()->get( PaymentMethodEventTracker::class )
+					->track_add_payment_method_page_loaded();
+			}
+
 			do_action( 'before_woocommerce_add_payment_method' );

 			wc_get_template( 'myaccount/form-add-payment-method.php' );
diff --git a/plugins/woocommerce/src/Blocks/BlockTypes/Cart.php b/plugins/woocommerce/src/Blocks/BlockTypes/Cart.php
index 23f6aed9fd..c1cc692282 100644
--- a/plugins/woocommerce/src/Blocks/BlockTypes/Cart.php
+++ b/plugins/woocommerce/src/Blocks/BlockTypes/Cart.php
@@ -2,7 +2,8 @@
 namespace Automattic\WooCommerce\Blocks\BlockTypes;

 use Automattic\WooCommerce\Blocks\Utils\CartCheckoutUtils;
-use Automattic\WooCommerce\StoreApi\Utilities\LocalPickupUtils;
+use Automattic\WooCommerce\Internal\FraudProtection\CartEventTracker;
+use Automattic\WooCommerce\Internal\FraudProtection\FraudProtectionController;

 /**
  * Cart class.
@@ -165,6 +166,12 @@ class Cart extends AbstractBlock {
 		// Dequeue the core scripts when rendering this block.
 		add_action( 'wp_enqueue_scripts', array( $this, 'dequeue_woocommerce_core_scripts' ), 20 );

+		// Track cart page loaded for fraud protection.
+		if ( wc_get_container()->get( FraudProtectionController::class )->feature_is_enabled() ) {
+			wc_get_container()->get( CartEventTracker::class )
+				->track_cart_page_loaded();
+		}
+
 		/**
 		 * We need to check if $content has any templates from prior iterations of the block, in order to update to the latest iteration.
 		 * We test the iteration version by searching for new blocks brought in by it.
diff --git a/plugins/woocommerce/src/Blocks/BlockTypes/Checkout.php b/plugins/woocommerce/src/Blocks/BlockTypes/Checkout.php
index 510a74ed05..8baf7f4933 100644
--- a/plugins/woocommerce/src/Blocks/BlockTypes/Checkout.php
+++ b/plugins/woocommerce/src/Blocks/BlockTypes/Checkout.php
@@ -10,6 +10,8 @@ use Automattic\WooCommerce\Blocks\Package;
 use Automattic\WooCommerce\StoreApi\Utilities\PaymentUtils;
 use Automattic\WooCommerce\Blocks\Domain\Services\CheckoutFieldsSchema\Validation;
 use Automattic\WooCommerce\Internal\AddressProvider\AddressProviderController;
+use Automattic\WooCommerce\Internal\FraudProtection\CheckoutEventTracker;
+use Automattic\WooCommerce\Internal\FraudProtection\FraudProtectionController;

 /**
  * Checkout class.
@@ -230,6 +232,12 @@ class Checkout extends AbstractBlock {
 			return wp_is_block_theme() ? do_shortcode( '[woocommerce_checkout]' ) : '[woocommerce_checkout]';
 		}

+		// Track checkout page loaded for fraud protection.
+		if ( wc_get_container()->get( FraudProtectionController::class )->feature_is_enabled() ) {
+			wc_get_container()->get( CheckoutEventTracker::class )
+				->track_checkout_page_loaded();
+		}
+
 		// Dequeue the core scripts when rendering this block.
 		add_action( 'wp_enqueue_scripts', array( $this, 'dequeue_woocommerce_core_scripts' ), 20 );

diff --git a/plugins/woocommerce/src/Internal/FraudProtection/CartEventTracker.php b/plugins/woocommerce/src/Internal/FraudProtection/CartEventTracker.php
index c666ac1f15..6b6e214e50 100644
--- a/plugins/woocommerce/src/Internal/FraudProtection/CartEventTracker.php
+++ b/plugins/woocommerce/src/Internal/FraudProtection/CartEventTracker.php
@@ -39,6 +39,20 @@ class CartEventTracker {
 		$this->dispatcher = $dispatcher;
 	}

+	/**
+	 * Track cart page loaded event.
+	 *
+	 * Triggers fraud protection event dispatching when the cart page is initially loaded.
+	 * This captures the initial session state before any user interactions.
+	 *
+	 * @internal
+	 * @return void
+	 */
+	public function track_cart_page_loaded(): void {
+		// Track the page load event. Session data will be collected by the dispatcher.
+		$this->dispatcher->dispatch_event( 'cart_page_loaded', array() );
+	}
+
 	/**
 	 * Track cart item added event.
 	 *
diff --git a/plugins/woocommerce/src/Internal/FraudProtection/CheckoutEventTracker.php b/plugins/woocommerce/src/Internal/FraudProtection/CheckoutEventTracker.php
index 92753f9c07..48c3c29928 100644
--- a/plugins/woocommerce/src/Internal/FraudProtection/CheckoutEventTracker.php
+++ b/plugins/woocommerce/src/Internal/FraudProtection/CheckoutEventTracker.php
@@ -48,6 +48,20 @@ class CheckoutEventTracker {
 		$this->session_data_collector = $session_data_collector;
 	}

+	/**
+	 * Track checkout page loaded event.
+	 *
+	 * Triggers fraud protection event dispatching when the checkout page is initially loaded.
+	 * This captures the initial session state before any user interactions.
+	 *
+	 * @internal
+	 * @return void
+	 */
+	public function track_checkout_page_loaded(): void {
+		// Track the page load event. Session data will be collected by the dispatcher.
+		$this->dispatcher->dispatch_event( 'checkout_page_loaded', array() );
+	}
+
 	/**
 	 * Track Store API customer update event (WooCommerce Blocks checkout).
 	 *
diff --git a/plugins/woocommerce/src/Internal/FraudProtection/PaymentMethodEventTracker.php b/plugins/woocommerce/src/Internal/FraudProtection/PaymentMethodEventTracker.php
index 48c9ba7916..3e7530a11f 100644
--- a/plugins/woocommerce/src/Internal/FraudProtection/PaymentMethodEventTracker.php
+++ b/plugins/woocommerce/src/Internal/FraudProtection/PaymentMethodEventTracker.php
@@ -39,6 +39,20 @@ class PaymentMethodEventTracker {
 		$this->dispatcher = $dispatcher;
 	}

+	/**
+	 * Track add payment method page loaded event.
+	 *
+	 * Triggers fraud protection event dispatching when the add payment method page is initially loaded.
+	 * This captures the initial session state before any user interactions.
+	 *
+	 * @internal
+	 * @return void
+	 */
+	public function track_add_payment_method_page_loaded(): void {
+		// Track the page load event. Session data will be collected by the dispatcher.
+		$this->dispatcher->dispatch_event( 'add_payment_method_page_loaded', array() );
+	}
+
 	/**
 	 * Track payment method added event.
 	 *
diff --git a/plugins/woocommerce/tests/php/src/Internal/FraudProtection/CartEventTrackerTest.php b/plugins/woocommerce/tests/php/src/Internal/FraudProtection/CartEventTrackerTest.php
index c403b827be..79d4f02357 100644
--- a/plugins/woocommerce/tests/php/src/Internal/FraudProtection/CartEventTrackerTest.php
+++ b/plugins/woocommerce/tests/php/src/Internal/FraudProtection/CartEventTrackerTest.php
@@ -72,6 +72,26 @@ class CartEventTrackerTest extends \WC_Unit_Test_Case {
 		WC()->cart->empty_cart();
 	}

+	/**
+	 * Test track_cart_page_loaded dispatches event.
+	 * The CartEventTracker::track_cart_page_loaded does not add any event data.
+	 * The data collection is handled by the SessionDataCollector.
+	 * So we only need to test if the dispatcher is called with no event data.
+	 */
+	public function test_track_cart_page_loaded_dispatches_event(): void {
+		// Mock dispatcher to verify event is dispatched with empty event data.
+		$this->mock_dispatcher
+			->expects( $this->once() )
+			->method( 'dispatch_event' )
+			->with(
+				$this->equalTo( 'cart_page_loaded' ),
+				$this->equalTo( array() )
+			);
+
+		// Call the method.
+		$this->sut->track_cart_page_loaded();
+	}
+
 	/**
 	 * Test track_cart_item_added tracks event.
 	 */
diff --git a/plugins/woocommerce/tests/php/src/Internal/FraudProtection/CheckoutEventTrackerTest.php b/plugins/woocommerce/tests/php/src/Internal/FraudProtection/CheckoutEventTrackerTest.php
index 2a1a0a498e..2fc5e62791 100644
--- a/plugins/woocommerce/tests/php/src/Internal/FraudProtection/CheckoutEventTrackerTest.php
+++ b/plugins/woocommerce/tests/php/src/Internal/FraudProtection/CheckoutEventTrackerTest.php
@@ -70,6 +70,30 @@ class CheckoutEventTrackerTest extends \WC_Unit_Test_Case {
 		$this->sut->init( $this->mock_dispatcher, $this->mock_session_data_collector );
 	}

+	// ========================================
+	// Checkout Page Load Tests
+	// ========================================
+
+	/**
+	 * Test track_checkout_page_loaded dispatches event.
+	 * The CheckoutEventTracker::track_checkout_page_loaded does not add any event data.
+	 * The data collection is handled by the SessionDataCollector.
+	 * So we only need to test if the dispatcher is called with no event data.
+	 */
+	public function test_track_checkout_page_loaded_dispatches_event(): void {
+		// Mock dispatcher to verify event is dispatched with empty event data.
+		$this->mock_dispatcher
+			->expects( $this->once() )
+			->method( 'dispatch_event' )
+			->with(
+				$this->equalTo( 'checkout_page_loaded' ),
+				$this->equalTo( array() )
+			);
+
+		// Call the method.
+		$this->sut->track_checkout_page_loaded();
+	}
+
 	// ========================================
 	// Blocks Checkout Tests
 	// ========================================
diff --git a/plugins/woocommerce/tests/php/src/Internal/FraudProtection/PaymentMethodEventTrackerTest.php b/plugins/woocommerce/tests/php/src/Internal/FraudProtection/PaymentMethodEventTrackerTest.php
index 5c4cc88c7b..5f7e787f36 100644
--- a/plugins/woocommerce/tests/php/src/Internal/FraudProtection/PaymentMethodEventTrackerTest.php
+++ b/plugins/woocommerce/tests/php/src/Internal/FraudProtection/PaymentMethodEventTrackerTest.php
@@ -26,6 +26,13 @@ class PaymentMethodEventTrackerTest extends \WC_Unit_Test_Case {
 	 */
 	private $sut;

+	/**
+	 * Mock fraud protection dispatcher.
+	 *
+	 * @var \Automattic\WooCommerce\Internal\FraudProtection\FraudProtectionDispatcher|\PHPUnit\Framework\MockObject\MockObject
+	 */
+	private $mock_dispatcher;
+
 	/**
 	 * Setup test.
 	 */
@@ -41,6 +48,32 @@ class PaymentMethodEventTrackerTest extends \WC_Unit_Test_Case {
 		$this->sut = $container->get( PaymentMethodEventTracker::class );
 	}

+	/**
+	 * Test add payment method page loaded event tracking.
+	 *
+	 * @testdox Should track add payment method page loaded event.
+	 */
+	public function test_track_add_payment_method_page_loaded_dispatches_event(): void {
+		// Create mock dispatcher.
+		$this->mock_dispatcher = $this->createMock( \Automattic\WooCommerce\Internal\FraudProtection\FraudProtectionDispatcher::class );
+
+		// Create system under test with mock dispatcher.
+		$sut = new PaymentMethodEventTracker();
+		$sut->init( $this->mock_dispatcher );
+
+		// Mock dispatcher to verify event is dispatched with empty event data.
+		$this->mock_dispatcher
+			->expects( $this->once() )
+			->method( 'dispatch_event' )
+			->with(
+				$this->equalTo( 'add_payment_method_page_loaded' ),
+				$this->equalTo( array() )
+			);
+
+		// Call the method.
+		$sut->track_add_payment_method_page_loaded();
+	}
+
 	/**
 	 * Test payment method added event tracking.
 	 *