Skip to content

Commit cc57ebb

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 cc57ebb

File tree

3 files changed

+68
-0
lines changed

3 files changed

+68
-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: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,51 @@ 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 = array();
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->assertNotEmpty( $filter_args, 'Filter callback should have been called.' );
101+
$this->assertFalse( $filter_args['handled'], 'Default handled value should be false.' );
102+
$this->assertSame( 1, $filter_args['user_id'], 'Filter should receive the user ID.' );
103+
$this->assertSame( '123456', $filter_args['auth_code'], 'Filter should receive the auth code.' );
104+
}
105+
106+
public function test_api_send_auth_email_proceeds_normally_when_filter_returns_falsy(): void {
107+
Jetpack_Options::delete_option( 'id' );
108+
$sut = new Email_Service();
109+
$user = new \WP_User();
110+
$user->ID = 1;
111+
112+
$callback = function () {
113+
return false;
114+
};
115+
116+
add_filter( 'jetpack_account_protection_send_auth_email', $callback, 10, 4 );
117+
118+
$result = $sut->api_send_auth_email( $user->ID, '123456' );
119+
120+
remove_filter( 'jetpack_account_protection_send_auth_email', $callback, 10 );
121+
122+
// Should continue to the normal flow and fail because blog_id is not set
123+
$this->assertInstanceOf( \WP_Error::class, $result );
124+
$this->assertEquals( 'jetpack_connection_error', $result->get_error_code() );
125+
}
126+
82127
public function test_api_send_auth_email_returns_error_if_blog_id_not_available(): void {
83128
Jetpack_Options::delete_option( 'id' );
84129
$sut = new Email_Service();

0 commit comments

Comments
 (0)