Commit c21942c5824 for woocommerce
commit c21942c5824298254330e41c69137d1377aa6daf
Author: Tom Cafferkey <tjcafferkey@gmail.com>
Date: Tue Nov 10 09:09:18 2026 +0000
Prevent fatal errors when verification email is omitted (#70787)
* Prevent fatal errors when verification email is omitted
* Add changelog entry for email verification compatibility fix
* Remove redundant null email verification test
* Add debug log
* Doing it wrong
* wc_doing_it_wrong
* Fix test
diff --git a/plugins/woocommerce/changelog/fix-email-verification-legacy-callers b/plugins/woocommerce/changelog/fix-email-verification-legacy-callers
new file mode 100644
index 00000000000..a76994aea76
--- /dev/null
+++ b/plugins/woocommerce/changelog/fix-email-verification-legacy-callers
@@ -0,0 +1,4 @@
+Significance: patch
+Type: fix
+
+Prevent account activation crashes with extensions that verify customer emails using the legacy one-argument call.
diff --git a/plugins/woocommerce/src/Internal/CustomerEmailVerification/EmailVerificationService.php b/plugins/woocommerce/src/Internal/CustomerEmailVerification/EmailVerificationService.php
index b28c88b0c07..6647b23a408 100644
--- a/plugins/woocommerce/src/Internal/CustomerEmailVerification/EmailVerificationService.php
+++ b/plugins/woocommerce/src/Internal/CustomerEmailVerification/EmailVerificationService.php
@@ -90,18 +90,27 @@ class EmailVerificationService {
* @since 11.0.0
*
* @param int $user_id WordPress user ID.
- * @param string|null $expected_email Email address proven by the verification flow.
+ * @param string|null $expected_email Email address proven by the verification flow. If omitted or null, no verification is performed.
* @return void
*/
- public function mark_verified( int $user_id, ?string $expected_email ): void {
+ public function mark_verified( int $user_id, ?string $expected_email = null ): void {
if ( $this->is_verified( $user_id ) ) {
return;
}
+ if ( null === $expected_email ) {
+ wc_doing_it_wrong(
+ __METHOD__,
+ 'Verification was skipped because no expected email was provided. Pass the email address proven by the verification flow as the second argument.',
+ '11.3.0'
+ );
+ return;
+ }
+
$account_email = $this->get_account_email( $user_id );
- $expected_email = null !== $expected_email ? strtolower( $expected_email ) : null;
+ $expected_email = strtolower( $expected_email );
- if ( null === $expected_email || null === $account_email || $expected_email !== $account_email ) {
+ if ( null === $account_email || $expected_email !== $account_email ) {
return;
}
diff --git a/plugins/woocommerce/tests/php/src/Internal/CustomerEmailVerification/EmailVerificationServiceTest.php b/plugins/woocommerce/tests/php/src/Internal/CustomerEmailVerification/EmailVerificationServiceTest.php
index 19cf3bc1e88..95d8fd8e000 100644
--- a/plugins/woocommerce/tests/php/src/Internal/CustomerEmailVerification/EmailVerificationServiceTest.php
+++ b/plugins/woocommerce/tests/php/src/Internal/CustomerEmailVerification/EmailVerificationServiceTest.php
@@ -61,6 +61,22 @@ class EmailVerificationServiceTest extends WC_Unit_Test_Case {
remove_action( 'woocommerce_customer_email_verified', $listener );
}
+ /**
+ * @testdox Legacy one-argument calls report incorrect usage without changing verification state.
+ */
+ public function test_mark_verified_without_expected_email(): void {
+ $user_id = wc_create_new_customer( 'legacy@example.com', 'legacyuser', 'pw' );
+ $key = $this->sut->create_verification_key( $user_id );
+ $hook_calls = did_action( 'woocommerce_customer_email_verified' );
+
+ $this->setExpectedIncorrectUsage( EmailVerificationService::class . '::mark_verified' );
+ $this->sut->mark_verified( $user_id );
+
+ $this->assertFalse( $this->sut->is_verified( $user_id ), 'An omitted expected email must not verify the account' );
+ $this->assertTrue( $this->sut->check_verification_key( $user_id, $key ), 'An omitted expected email must not consume the pending key' );
+ $this->assertSame( $hook_calls, did_action( 'woocommerce_customer_email_verified' ), 'An omitted expected email must not fire the verification hook' );
+ }
+
/**
* @testdox create_verification_key() returns a fresh, pending key that passes its own check.
*/