Skip to content

Commit e418072

Browse files
Add jetpack_account_protection_send_auth_email filter to allow custom email handling
Add a filter in Email_Service::api_send_auth_email() that fires before the WPCOM API call, allowing sites to handle the verification email locally (e.g. via wp_mail()). When the filter returns truthy, the API call is skipped. Default behavior is unchanged. Fixes #47999
1 parent db81876 commit e418072

File tree

3 files changed

+67
-0
lines changed

3 files changed

+67
-0
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Significance: minor
2+
Type: added
3+
4+
Add `jetpack_account_protection_send_auth_email` filter to allow custom handling of the verification email.

projects/packages/account-protection/src/class-email-service.php

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,25 @@ public function __construct(
4444
public function api_send_auth_email( int $user_id, string $auth_code ) {
4545
$blog_id = Jetpack_Options::get_option( 'id' );
4646

47+
/**
48+
* Filters whether the Account Protection verification email should be handled externally.
49+
*
50+
* When the filter returns a truthy value, the default WPCOM API email send is skipped,
51+
* allowing sites to deliver the email locally (e.g. via `wp_mail()`).
52+
*
53+
* @since $$next-version$$
54+
*
55+
* @param bool $handled Whether the email has been handled. Default false.
56+
* @param int $user_id The user ID.
57+
* @param string $auth_code The authentication code.
58+
* @param int $blog_id The blog ID, or false if not available.
59+
*/
60+
$handled = apply_filters( 'jetpack_account_protection_send_auth_email', false, $user_id, $auth_code, $blog_id );
61+
62+
if ( $handled ) {
63+
return true;
64+
}
65+
4766
if ( ! $blog_id || ! $this->connection_manager->is_connected() ) {
4867
return new \WP_Error( 'jetpack_connection_error', __( 'Jetpack is not connected. Please connect and try again.', 'jetpack-account-protection' ) );
4968
}

projects/packages/account-protection/tests/php/Email_Service_Test.php

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,50 @@ public function test_resend_auth_mail_sends_mail_and_remembers_2fa_token_success
7979
$this->assertMatchesRegularExpression( '/^[0-9]{6}$/', $new_transient['auth_code'], 'Auth code should be 6 digits.' );
8080
}
8181

82+
public function test_api_send_auth_email_skips_api_call_when_filter_returns_truthy(): void {
83+
$sut = new Email_Service();
84+
$user = new \WP_User();
85+
$user->ID = 1;
86+
87+
$filter_args = null;
88+
$callback = function ( $handled, $user_id, $auth_code, $blog_id ) use ( &$filter_args ) {
89+
$filter_args = compact( 'handled', 'user_id', 'auth_code', 'blog_id' );
90+
return true;
91+
};
92+
93+
add_filter( 'jetpack_account_protection_send_auth_email', $callback, 10, 4 );
94+
95+
$result = $sut->api_send_auth_email( $user->ID, '123456' );
96+
97+
remove_filter( 'jetpack_account_protection_send_auth_email', $callback, 10 );
98+
99+
$this->assertTrue( $result, 'api_send_auth_email should return true when the filter short-circuits.' );
100+
$this->assertFalse( $filter_args['handled'], 'Default handled value should be false.' );
101+
$this->assertSame( 1, $filter_args['user_id'], 'Filter should receive the user ID.' );
102+
$this->assertSame( '123456', $filter_args['auth_code'], 'Filter should receive the auth code.' );
103+
}
104+
105+
public function test_api_send_auth_email_proceeds_normally_when_filter_returns_falsy(): void {
106+
Jetpack_Options::delete_option( 'id' );
107+
$sut = new Email_Service();
108+
$user = new \WP_User();
109+
$user->ID = 1;
110+
111+
$callback = function () {
112+
return false;
113+
};
114+
115+
add_filter( 'jetpack_account_protection_send_auth_email', $callback, 10, 4 );
116+
117+
$result = $sut->api_send_auth_email( $user->ID, '123456' );
118+
119+
remove_filter( 'jetpack_account_protection_send_auth_email', $callback, 10 );
120+
121+
// Should continue to the normal flow and fail because blog_id is not set
122+
$this->assertInstanceOf( \WP_Error::class, $result );
123+
$this->assertEquals( 'jetpack_connection_error', $result->get_error_code() );
124+
}
125+
82126
public function test_api_send_auth_email_returns_error_if_blog_id_not_available(): void {
83127
Jetpack_Options::delete_option( 'id' );
84128
$sut = new Email_Service();

0 commit comments

Comments
 (0)