Commit 28e21afa3c4 for woocommerce
commit 28e21afa3c4a4ba80699656bb17603e231105478
Author: Tom Cafferkey <tjcafferkey@gmail.com>
Date: Mon Aug 24 13:23:23 2026 +0100
Fix email verification prompt for guest checkout (#67960)
* Fix email verification prompt for guest checkout
* Simplify guest checkout prompt logic and fix filter type safety
* Stop the guest checkout prompt filter from overriding verified or logged-out users
---------
Co-authored-by: Jorge Torres <jorge.torres@automattic.com>
diff --git a/plugins/woocommerce/changelog/fix-email-verification-guest-checkout-prompt b/plugins/woocommerce/changelog/fix-email-verification-guest-checkout-prompt
new file mode 100644
index 00000000000..307e1b9ba17
--- /dev/null
+++ b/plugins/woocommerce/changelog/fix-email-verification-guest-checkout-prompt
@@ -0,0 +1,4 @@
+Significance: patch
+Type: fix
+
+Suppress the customer email verification prompt when guest checkout is disabled.
diff --git a/plugins/woocommerce/src/Internal/CustomerEmailVerification/VerificationController.php b/plugins/woocommerce/src/Internal/CustomerEmailVerification/VerificationController.php
index fae1a841c7d..1d2e4b97408 100644
--- a/plugins/woocommerce/src/Internal/CustomerEmailVerification/VerificationController.php
+++ b/plugins/woocommerce/src/Internal/CustomerEmailVerification/VerificationController.php
@@ -210,9 +210,7 @@ class VerificationController {
/**
* Return whether the verification prompt should be shown for the current user.
*
- * True for a logged-in, unverified customer, except one still using a temporary password (those
- * confirm via their set-password link, so the temporary-password notice already covers it). This
- * must not depend on whether matching guest orders exist, because that would disclose order
+ * This cannot depend on whether matching guest orders exist, since that would disclose order
* existence before the customer proves they control the email address.
*
* @since 11.0.0
@@ -222,21 +220,25 @@ class VerificationController {
public function should_show_prompt(): bool {
$user_id = get_current_user_id();
- if ( ! $user_id ) {
+ if ( ! $user_id || $this->service->is_verified( $user_id ) ) {
return false;
}
- if ( $this->service->is_verified( $user_id ) ) {
- return false;
- }
+ $should_show = wc_string_to_bool( get_option( 'woocommerce_enable_guest_checkout' ) );
// A temporary-password account already has a set-password link (which also verifies on use),
- // surfaced by the temporary-password notice — don't show a second prompt alongside it.
- if ( get_user_option( 'default_password_nag', $user_id ) ) {
- return false;
- }
+ // surfaced by the temporary-password notice, so skip a second prompt alongside it.
+ $should_show = $should_show && ! get_user_option( 'default_password_nag', $user_id );
- return true;
+ /**
+ * Filter whether to show the verification prompt for an unverified user.
+ *
+ * @since 11.1.0
+ *
+ * @param bool $should_show Whether to show the prompt, before this filter runs.
+ * @param int $user_id The WordPress user ID of the customer.
+ */
+ return (bool) apply_filters( 'woocommerce_customer_email_verification_should_show_prompt', $should_show, $user_id );
}
/**
diff --git a/plugins/woocommerce/tests/php/src/Internal/CustomerEmailVerification/MyAccountPromptTest.php b/plugins/woocommerce/tests/php/src/Internal/CustomerEmailVerification/MyAccountPromptTest.php
index 337bf3faae7..7838c0a440f 100644
--- a/plugins/woocommerce/tests/php/src/Internal/CustomerEmailVerification/MyAccountPromptTest.php
+++ b/plugins/woocommerce/tests/php/src/Internal/CustomerEmailVerification/MyAccountPromptTest.php
@@ -26,13 +26,22 @@ class MyAccountPromptTest extends WC_Unit_Test_Case {
*/
private $service;
+ /**
+ * Previous guest checkout option value.
+ *
+ * @var mixed
+ */
+ private $previous_guest_checkout_option;
+
/**
* Set up test fixtures.
*/
public function setUp(): void {
parent::setUp();
- $this->service = wc_get_container()->get( EmailVerificationService::class );
- $this->sut = wc_get_container()->get( VerificationController::class );
+ $this->service = wc_get_container()->get( EmailVerificationService::class );
+ $this->sut = wc_get_container()->get( VerificationController::class );
+ $this->previous_guest_checkout_option = get_option( 'woocommerce_enable_guest_checkout', null );
+ update_option( 'woocommerce_enable_guest_checkout', 'yes' );
}
/**
@@ -41,9 +50,25 @@ class MyAccountPromptTest extends WC_Unit_Test_Case {
public function tearDown(): void {
wp_set_current_user( 0 );
wc_clear_notices();
+ $this->restore_option( 'woocommerce_enable_guest_checkout', $this->previous_guest_checkout_option );
parent::tearDown();
}
+ /**
+ * Restore an option to its previous value.
+ *
+ * @param string $option_name Option name.
+ * @param mixed $previous_value Previous option value, or null if it did not exist.
+ */
+ private function restore_option( string $option_name, $previous_value ): void {
+ if ( null === $previous_value ) {
+ delete_option( $option_name );
+ return;
+ }
+
+ update_option( $option_name, $previous_value );
+ }
+
/**
* Render the My Account prompt and return its HTML.
*
@@ -114,6 +139,29 @@ class MyAccountPromptTest extends WC_Unit_Test_Case {
$this->assertTrue( $this->sut->should_show_prompt(), 'Prompt visibility must not reveal whether matching guest orders exist' );
}
+ /**
+ * @testdox should_show_prompt returns false when guest checkout is disabled.
+ */
+ public function test_should_show_prompt_returns_false_when_guest_checkout_is_disabled(): void {
+ $user_id = wc_create_new_customer( 'prompt-guest-disabled@example.com', 'promptguestdisabled', 'pw' );
+ wp_set_current_user( $user_id );
+ update_option( 'woocommerce_enable_guest_checkout', 'no' );
+
+ $this->assertFalse( $this->sut->should_show_prompt(), 'The prompt should not show when guest checkout is disabled.' );
+ }
+
+ /**
+ * @testdox should_show_prompt allows filters to override the guest checkout default.
+ */
+ public function test_should_show_prompt_allows_filter_to_override_guest_checkout_default(): void {
+ $user_id = wc_create_new_customer( 'prompt-guest-disabled-filtered@example.com', 'promptguestdisabledfiltered', 'pw' );
+ wp_set_current_user( $user_id );
+ update_option( 'woocommerce_enable_guest_checkout', 'no' );
+
+ add_filter( 'woocommerce_customer_email_verification_should_show_prompt', '__return_true' );
+ $this->assertTrue( $this->sut->should_show_prompt(), 'The prompt default should be overrideable by filter.' );
+ }
+
/**
* @testdox should_show_prompt returns false for an account using a temporary password.
*/
@@ -137,6 +185,18 @@ class MyAccountPromptTest extends WC_Unit_Test_Case {
$this->assertFalse( $this->sut->should_show_prompt(), 'Verified customers should not see the prompt' );
}
+ /**
+ * @testdox should_show_prompt never applies the filter for a verified customer.
+ */
+ public function test_should_show_prompt_ignores_filter_for_verified_customer(): void {
+ $user_id = wc_create_new_customer( 'prompt-verified-filtered@example.com', 'promptverifiedfiltered', 'pw' );
+ wp_set_current_user( $user_id );
+ $this->service->mark_verified( $user_id );
+
+ add_filter( 'woocommerce_customer_email_verification_should_show_prompt', '__return_true' );
+ $this->assertFalse( $this->sut->should_show_prompt(), 'A verified customer should never see the prompt, even if a filter tries to force it on.' );
+ }
+
// -------------------------------------------------------------------------
// render_prompt()
// -------------------------------------------------------------------------