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.
*