PluginProbe ʕ •ᴥ•ʔ
WP 2FA – Two-factor authentication for WordPress / 2.9.0
WP 2FA – Two-factor authentication for WordPress v2.9.0
4.0.0 1.7.1 2.0.0 2.0.1 2.1.0 2.2.0 2.2.1 2.3.0 2.4.0 2.4.1 2.4.2 2.5.0 2.6.0 2.6.1 2.6.2 2.6.3 2.6.4 2.7.0 2.8.0 2.9.0 2.9.1 2.9.2 2.9.3 3.0.0 3.0.1 3.1.0 3.1.1 3.1.1.2 trunk 1.2.0 1.3.0 1.4.0 1.4.1 1.4.2 1.5.0 1.5.1 1.5.2 1.6.0 1.6.1 1.6.2 1.7.0
wp-2fa / includes / classes / Admin / SettingsPages / class-settings-page-email.php
wp-2fa / includes / classes / Admin / SettingsPages Last commit date
class-settings-page-email.php 11 months ago class-settings-page-general.php 11 months ago class-settings-page-policies.php 11 months ago class-settings-page-render.php 11 months ago class-settings-page-white-label.php 11 months ago index.php 11 months ago
class-settings-page-email.php
507 lines
1 <?php
2 /**
3 * Email settings class.
4 *
5 * @package wp2fa
6 * @subpackage settings-pages
7 * @copyright 2025 Melapress
8 * @license https://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0
9 * @link https://wordpress.org/plugins/wp-2fa/
10 */
11
12 namespace WP2FA\Admin\SettingsPages;
13
14 use WP2FA\Email_Template;
15 use WP2FA\WP2FA;
16 use WP2FA\Utils\Debugging;
17 use WP2FA\Admin\Helpers\WP_Helper;
18 use WP2FA\Admin\Controllers\Settings;
19 use WP2FA\Utils\Settings_Utils;
20 use WP2FA\Admin\Settings_Page;
21
22 /**
23 * Email settings tab
24 */
25 if ( ! class_exists( '\WP2FA\Admin\SettingsPages\Settings_Page_Email' ) ) {
26 /**
27 * Settings_Page_Email - Class for handling email settings
28 *
29 * @since 2.0.0
30 */
31 class Settings_Page_Email {
32
33 /**
34 * Render the settings
35 *
36 * @return void
37 *
38 * @since 2.0.0
39 */
40 public static function render() {
41 if ( ! \current_user_can( 'manage_options' ) ) {
42 return;
43 }
44
45 \settings_fields( WP_2FA_EMAIL_SETTINGS_NAME );
46 self::email_from_settings();
47 self::email_settings();
48 \submit_button( \esc_html__( 'Save email settings and templates', 'wp-2fa' ) );
49 }
50
51 /**
52 * Handle saving email options to the network main site options.
53 *
54 * @return void
55 *
56 * @since 2.0.0
57 */
58 public static function update_wp2fa_network_options() {
59 if ( ! \current_user_can( 'manage_options' ) ) {
60 return;
61 }
62
63 if ( isset( $_POST['email_from_setting'] ) ) { // phpcs:ignore
64 $options = self::validate_and_sanitize( wp_unslash( $_POST ) ); // phpcs:ignore
65
66 if ( isset( $_POST['email_from_setting'] ) && 'use-custom-email' === $_POST['email_from_setting'] && isset( $_POST['custom_from_display_name'] ) && empty( $_POST['custom_from_display_name'] ) || isset( $_POST['email_from_setting'] ) && 'use-custom-email' === $_POST['email_from_setting'] && isset( $_POST['custom_from_email_address'] ) && empty( $_POST['custom_from_email_address'] ) ) { // phpcs:ignore
67 // redirect back to our options page.
68 \wp_safe_redirect(
69 \add_query_arg(
70 array(
71 'page' => 'wp-2fa-settings',
72 'wp_2fa_network_settings_updated' => 'false',
73 'tab' => 'email-settings',
74 ),
75 \network_admin_url( 'admin.php' )
76 )
77 );
78 exit;
79 }
80
81 Settings_Utils::update_option( WP_2FA_EMAIL_SETTINGS_NAME, $options );
82 }
83
84 // redirect back to our options page.
85 \wp_safe_redirect(
86 \add_query_arg(
87 array(
88 'page' => 'wp-2fa-settings',
89 'wp_2fa_network_settings_updated' => 'true',
90 'tab' => 'email-settings',
91 ),
92 \network_admin_url( 'admin.php' )
93 )
94 );
95 exit;
96 }
97
98 /**
99 * Email settings
100 *
101 * @return void
102 *
103 * @since 2.0.0
104 */
105 private static function email_from_settings() {
106 ?>
107 <h3><?php \esc_html_e( 'Which email address should the plugin use as a from address?', 'wp-2fa' ); ?></h3>
108 <p class="description">
109 <?php \esc_html_e( 'Use these settings to customize the "from" name and email address for all correspondence sent from our plugin.', 'wp-2fa' ); ?>
110 </p>
111 <table class="form-table">
112 <tbody>
113 <tr>
114 <th><label for="2fa-method"><?php \esc_html_e( 'From email & name', 'wp-2fa' ); ?></label>
115 </th>
116 <td>
117 <fieldset class="contains-hidden-inputs">
118 <label for="use-defaults">
119 <input type="radio" name="email_from_setting" id="use-defaults" value="use-defaults"
120 <?php \checked( WP2FA::get_wp2fa_email_templates( 'email_from_setting' ), 'use-defaults' ); ?>
121 >
122 <span><?php \esc_html_e( 'Use the email address ', 'wp-2fa' ); ?> <?php echo Settings_Page::get_default_email_address(); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?></span>
123 </label>
124 <br/>
125 <label for="use-custom-email">
126 <input type="radio" name="email_from_setting" id="use-custom-email" value="use-custom-email"
127 <?php \checked( WP2FA::get_wp2fa_email_templates( 'email_from_setting' ), 'use-custom-email' ); ?>
128 data-unhide-when-checked=".custom-from-inputs">
129 <span><?php \esc_html_e( 'Use another email address', 'wp-2fa' ); ?></span>
130 </label>
131 <fieldset class="hidden custom-from-inputs">
132 <p class="description">
133 <?php \esc_html_e( 'A \'From email\' address with a domain different than that of your website domain name, or with a domain that the hosting does not relay might cause the notification emails to be blocked, marked as spam, or not delivered at all. If you are not 100% sure about this change, consult with your web host.', 'wp-2fa' ); ?>
134 </p>
135 <br/>
136 <span><?php \esc_html_e( 'Email Address:', 'wp-2fa' ); ?></span> <input type="text" id="custom_from_email_address" name="custom_from_email_address" value="<?php echo \esc_attr( WP2FA::get_wp2fa_email_templates( 'custom_from_email_address' ) ); ?>"><br><br>
137 <span><?php \esc_html_e( 'Display Name:', 'wp-2fa' ); ?></span> <input type="text" id="custom_from_display_name" name="custom_from_display_name" value="<?php echo \esc_attr( WP2FA::get_wp2fa_email_templates( 'custom_from_display_name' ) ); ?>">
138 </fieldset>
139
140 </fieldset>
141 </td>
142 </tr>
143 </tbody>
144 </table>
145 <div class="description"><i><?php \esc_html_e( 'Tip: The \'From email\' address should match your website domain. If the "from address" does not match your website domain, the emails may be blocked or marked as spam. If you are not sure about this please consult with your website administrator / developer or ', 'wp-2fa' ); ?><a href="<?php echo \esc_url( 'https://melapress.com/contact/?utm_source=plugin&utm_medium=wp2fa&utm_campaign=from_email_address' ); ?>" target="_blank"><?php \esc_html_e( 'contact us', 'wp-2fa' ); ?></a> <?php \esc_html_e( 'for more information.', 'wp-2fa' ); ?></i></div>
146 <br>
147 <hr>
148
149 <h3><?php \esc_html_e( 'Email delivery test', 'wp-2fa' ); ?></h3>
150 <p class="description">
151 <?php \esc_html_e( 'The plugin sends emails with one-time codes, blocked account notifications and more. Use the button below to confirm the plugin can successfully send emails.', 'wp-2fa' ); ?>
152 </p>
153 <p>
154 <button type="button" name="test_email_config_test"
155 class="button js-button-test-email-trigger"
156 data-email-id="config_test"
157 <?php echo WP_Helper::create_data_nonce( 'wp-2fa-email-test-config_test' ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>>
158 <?php \esc_html_e( 'Test email delivery', 'wp-2fa' ); ?>
159 </button>
160 </p>
161
162 <br>
163 <hr>
164
165 <?php
166 }
167
168 /**
169 * Creates the email notification definitions.
170 *
171 * @return Email_Template[]
172 *
173 * @since 2.0.0
174 */
175 public static function get_email_notification_definitions() {
176
177 $backup_codes = new Email_Template(
178 'user_backup_codes',
179 \esc_html__( 'User backup codes email', 'wp-2fa' ),
180 \esc_html__( 'This email can be sent a user once backup codes are generated.', 'wp-2fa' )
181 );
182 $backup_codes->set_can_be_toggled( false );
183
184 $result = array(
185 new Email_Template(
186 'login_code_setup',
187 \esc_html__( '2FA setup code email', 'wp-2fa' ),
188 \esc_html__( 'This is the email sent to a user when setting up 2FA via email.', 'wp-2fa' )
189 ),
190 new Email_Template(
191 'login_code',
192 \esc_html__( 'Login code email', 'wp-2fa' ),
193 \esc_html__( 'This is the email sent to a user when a login code is required.', 'wp-2fa' )
194 ),
195 new Email_Template(
196 'account_locked',
197 \esc_html__( 'User account locked email', 'wp-2fa' ),
198 \esc_html__( 'This is the email sent to a user upon grace period expiry.', 'wp-2fa' )
199 ),
200 new Email_Template(
201 'account_unlocked',
202 \esc_html__( 'User account unlocked email', 'wp-2fa' ),
203 \esc_html__( 'This is the email sent to a user when the user\'s account has been unlocked.', 'wp-2fa' )
204 ),
205 new Email_Template(
206 'reset_password_code',
207 \esc_html__( 'User reset password code email', 'wp-2fa' ),
208 \esc_html__( 'This is the email sent to a user when a password reset is requested.', 'wp-2fa' )
209 ),
210 $backup_codes,
211 );
212
213 /**
214 * Add an option for external providers to implement their own email template settings for the settings tab.
215 *
216 * @param array $result - The array with all the email templates.
217 *
218 * @since 2.0.0
219 */
220 $result = \apply_filters( WP_2FA_PREFIX . 'email_notification_definitions', $result );
221
222 if ( count( $result ) > 6 ) {
223 $result[0]->set_can_be_toggled( false );
224 $result[1]->set_can_be_toggled( false );
225 $result[2]->set_can_be_toggled( false );
226 $result[3]->set_email_content_id( 'user_account_locked' );
227 $result[4]->set_email_content_id( 'user_account_unlocked' );
228 $result[5]->set_can_be_toggled( false );
229 } else {
230 $result[0]->set_can_be_toggled( false );
231 $result[1]->set_can_be_toggled( false );
232 $result[2]->set_email_content_id( 'user_account_locked' );
233 $result[3]->set_email_content_id( 'user_account_unlocked' );
234 $result[4]->set_can_be_toggled( false );
235 }
236 return $result;
237 }
238
239 /**
240 * Validate email templates before saving
241 *
242 * @since 2.0.0
243 */
244 public static function validate_and_sanitize() {
245
246 // Bail if user doesn't have permissions to be here.
247 if ( ! \current_user_can( 'manage_options' ) ) {
248 return;
249 }
250
251 Debugging::log( 'The following settings will be processed (E-mail): ' . "\n" . wp_json_encode( $_POST ) ); // phpcs:ignore
252
253 if ( empty( $_POST ) || ! isset( $_POST['_wpnonce'] ) || empty( $_POST['_wpnonce'] ) || ! \wp_verify_nonce( $_POST['_wpnonce'], WP_2FA_PREFIX . 'email_settings-options' ) && ! \wp_verify_nonce( $_POST['_wpnonce'], WP_2FA_PREFIX . 'settings-options' ) || ! \wp_verify_nonce( $_POST['_wpnonce'], WP_2FA_PREFIX . 'email_settings-options' ) && ! \wp_verify_nonce( $_POST['_wpnonce'], WP_2FA_PREFIX . 'settings-options' ) ) { // phpcs:ignore
254 die( \esc_html__( 'Nonce verification failed.', 'wp-2fa' ) );
255 }
256
257 $output = array();
258
259 if ( isset( $_POST['email_from_setting'] ) && 'use-defaults' === $_POST['email_from_setting'] || isset( $_POST['email_from_setting'] ) && 'use-custom-email' === $_POST['email_from_setting'] ) {
260 $output['email_from_setting'] = \sanitize_text_field( \wp_unslash( $_POST['email_from_setting'] ) );
261 }
262
263 if ( isset( $_POST['email_from_setting'] ) && 'use-custom-email' === $_POST['email_from_setting'] && isset( $_POST['custom_from_email_address'] ) && empty( $_POST['custom_from_email_address'] ) ) {
264 \add_settings_error(
265 WP_2FA_SETTINGS_NAME,
266 \esc_attr( 'email_from_settings_error' ),
267 \esc_html__( 'Please provide an email address', 'wp-2fa' ),
268 'error'
269 );
270 $output['custom_from_email_address'] = '';
271 }
272
273 if ( isset( $_POST['email_from_setting'] ) && 'use-custom-email' === $_POST['email_from_setting'] && isset( $_POST['custom_from_display_name'] ) && empty( $_POST['custom_from_display_name'] ) ) {
274 \add_settings_error(
275 WP_2FA_SETTINGS_NAME,
276 \esc_attr( 'display_name_settings_error' ),
277 \esc_html__( 'Please provide a display name.', 'wp-2fa' ),
278 'error'
279 );
280 $output['custom_from_email_address'] = '';
281 }
282
283 if ( isset( $_POST['custom_from_email_address'] ) && ! empty( $_POST['custom_from_email_address'] ) ) {
284 if ( ! filter_var( \wp_unslash( $_POST['custom_from_email_address'] ), FILTER_VALIDATE_EMAIL ) ) {
285 \add_settings_error(
286 WP_2FA_SETTINGS_NAME,
287 \esc_attr( 'email_invalid_settings_error' ),
288 \esc_html__( 'Please provide a valid email address. Your email address has not been updated.', 'wp-2fa' ),
289 'error'
290 );
291 }
292 $output['custom_from_email_address'] = \sanitize_email( \wp_unslash( $_POST['custom_from_email_address'] ) );
293
294 Settings_Utils::delete_option( 'dismiss_notice_mail_domain' );
295 }
296
297 if ( ! isset( $_POST['email_from_setting'] ) ) {
298 Settings_Utils::delete_option( 'dismiss_notice_mail_domain' );
299 }
300
301 if ( isset( $_POST['custom_from_display_name'] ) && ! empty( $_POST['custom_from_display_name'] ) ) {
302 // Check if the string contains HTML/tags.
303 preg_match( "/<\/?\w+((\s+\w+(\s*=\s*(?:\".*?\"|'.*?'|[^'\">\s]+))?)+\s*|\s*)\/?>/", sanitize_text_field( wp_unslash( $_POST['custom_from_display_name'] ) ), $matches );
304 if ( count( $matches ) > 0 ) {
305 \add_settings_error(
306 WP_2FA_SETTINGS_NAME,
307 \esc_attr( 'display_name_invalid_settings_error' ),
308 \esc_html__( 'Please only use alphanumeric text. Your display name has not been updated.', 'wp-2fa' ),
309 'error'
310 );
311 } else {
312 $output['custom_from_display_name'] = \sanitize_text_field( \wp_unslash( $_POST['custom_from_display_name'] ) );
313 }
314 }
315
316 if ( isset( $_POST['login_code_email_subject'] ) ) {
317 $output['login_code_email_subject'] = \wp_kses_post( \wp_unslash( $_POST['login_code_email_subject'] ) );
318 }
319
320 if ( isset( $_POST['login_code_email_body'] ) ) {
321 $output['login_code_email_body'] = \wpautop( \wp_kses_post( \wp_unslash( $_POST['login_code_email_body'] ) ) );
322 }
323
324 if ( isset( $_POST['login_code_setup_email_subject'] ) ) {
325 $output['login_code_setup_email_subject'] = \wp_kses_post( \wp_unslash( $_POST['login_code_setup_email_subject'] ) );
326 }
327
328 if ( isset( $_POST['login_code_setup_email_body'] ) ) {
329 $output['login_code_setup_email_body'] = \wpautop( \wp_kses_post( \wp_unslash( $_POST['login_code_setup_email_body'] ) ) );
330 }
331
332 if ( isset( $_POST['user_account_locked_email_subject'] ) ) {
333 $output['user_account_locked_email_subject'] = \wp_kses_post( \wp_unslash( $_POST['user_account_locked_email_subject'] ) );
334 }
335
336 if ( isset( $_POST['user_account_locked_email_body'] ) ) {
337 $output['user_account_locked_email_body'] = \wpautop( \wp_kses_post( \wp_unslash( $_POST['user_account_locked_email_body'] ) ) );
338 }
339
340 if ( isset( $_POST['user_account_unlocked_email_subject'] ) ) {
341 $output['user_account_unlocked_email_subject'] = \wp_kses_post( \wp_unslash( $_POST['user_account_unlocked_email_subject'] ) );
342 }
343
344 if ( isset( $_POST['user_account_unlocked_email_body'] ) ) {
345 $output['user_account_unlocked_email_body'] = \wpautop( \wp_kses_post( \wp_unslash( $_POST['user_account_unlocked_email_body'] ) ) );
346 }
347
348 if ( isset( $_POST['reset_password_code_email_body'] ) ) {
349 $output['reset_password_code_email_body'] = \wpautop( \wp_kses_post( \wp_unslash( $_POST['reset_password_code_email_body'] ) ) );
350 }
351
352 if ( isset( $_POST['reset_password_code_email_subject'] ) ) {
353 $output['reset_password_code_email_subject'] = \wp_kses_post( \wp_unslash( $_POST['reset_password_code_email_subject'] ) );
354 }
355
356 $output['send_account_locked_email'] = '';
357 if ( isset( $_POST['send_account_locked_email'] ) && 'enable_account_locked_email' === $_POST['send_account_locked_email'] ) {
358 $output['send_account_locked_email'] = \sanitize_text_field( \wp_unslash( $_POST['send_account_locked_email'] ) );
359 }
360
361 $output['send_account_unlocked_email'] = '';
362 if ( isset( $_POST['send_account_unlocked_email'] ) && 'enable_account_unlocked_email' === $_POST['send_account_unlocked_email'] ) {
363 $output['send_account_unlocked_email'] = \sanitize_text_field( \wp_unslash( $_POST['send_account_unlocked_email'] ) );
364 }
365
366 $output['send_login_code_email'] = '';
367 if ( isset( $_POST['send_login_code_email'] ) && 'enable_send_login_code_email' === $_POST['send_login_code_email'] ) {
368 $output['send_login_code_email'] = \sanitize_text_field( \wp_unslash( $_POST['send_login_code_email'] ) );
369 }
370
371 if ( isset( $_POST['user_backup_codes_email_subject'] ) ) {
372 $output['user_backup_codes_email_subject'] = \wp_kses_post( \wp_unslash( $_POST['user_backup_codes_email_subject'] ) );
373 }
374
375 if ( isset( $_POST['user_backup_codes_email_body'] ) ) {
376 $output['user_backup_codes_email_body'] = \wpautop( \wp_kses_post( \wp_unslash( $_POST['user_backup_codes_email_body'] ) ) );
377 }
378
379 /**
380 * Filter the values we are about to store in the plugin settings.
381 *
382 * @param array $output - The output array with all the data we will store in the settings.
383 *
384 * @since 2.0.0
385 */
386 $output = \apply_filters( WP_2FA_PREFIX . 'filter_output_email_template_content', $output );
387
388 Debugging::log( 'The following settings are being saved (E-mail): ' . "\n" . \wp_json_encode( $output ) );
389
390 // Remove duplicates from settings errors. We do this as this sanitization callback is actually fired twice, so we end up with duplicates when saving the settings for the FIRST TIME only. The issue is not present once the settings are in the DB as the sanitization wont fire again. For details on this core issue - https://core.trac.wordpress.org/ticket/21989.
391 global $wp_settings_errors;
392 if ( isset( $wp_settings_errors ) ) {
393 $errors = array_map( 'unserialize', array_unique( array_map( 'serialize', $wp_settings_errors ) ) );
394 $wp_settings_errors = $errors; // phpcs:ignore
395 }
396
397 if ( isset( $output ) ) {
398 return $output;
399 } else {
400 return;
401 }
402 }
403
404 /**
405 * Email settings
406 *
407 * @return void
408 *
409 * @since 2.0.0
410 */
411 private static function email_settings() {
412 $custom_user_page_id = Settings::check_setting_in_all_roles( 'custom-user-page-id' );
413 if ( empty( $custom_user_page_id ) ) {
414 $custom_user_page_id = Settings::check_setting_in_all_roles( 'custom-user-page-url' );
415 }
416 $email_template_definitions = self::get_email_notification_definitions();
417 ?>
418 <h1><?php \esc_html_e( 'Email Templates', 'wp-2fa' ); ?></h1>
419 <?php foreach ( $email_template_definitions as $email_template ) : ?>
420 <?php $template_id = $email_template->get_id(); ?>
421 <h3><?php echo \esc_html( $email_template->get_title() ); ?></h3>
422 <p class="description"><?php echo $email_template->get_description(); // phpcs:ignore ?></p>
423 <table class="form-table">
424 <tbody>
425 <?php if ( $email_template->can_be_toggled() ) : ?>
426 <tr>
427 <th><label for="send_<?php echo \esc_attr( $template_id ); ?>_email"><?php \esc_html_e( 'Send this email', 'wp-2fa' ); ?></label></th>
428 <td>
429 <fieldset>
430 <input type="checkbox" id="send_<?php echo \esc_attr( $template_id ); ?>_email" name="send_<?php echo \esc_attr( $template_id ); ?>_email" value="enable_<?php echo \esc_attr( $template_id ); ?>_email"
431 <?php \checked( 'enable_' . $template_id . '_email', WP2FA::get_wp2fa_email_templates( 'send_' . $template_id . '_email' ) ); ?>
432 >
433 <label for="send_<?php echo \esc_attr( $template_id ); ?>_email"><?php \esc_html_e( 'Uncheck to disable this message.', 'wp-2fa' ); ?></label>
434 </fieldset>
435 </td>
436 </tr>
437 <?php endif; ?>
438 <?php $template_id = $email_template->get_email_content_id(); ?>
439 <tr>
440 <th><label for="<?php echo \esc_attr( $template_id ); ?>_email_subject"><?php \esc_html_e( 'Email subject', 'wp-2fa' ); ?></label></th>
441 <td>
442 <fieldset>
443 <input type="text" id="<?php echo \esc_attr( $template_id ); ?>_email_subject" name="<?php echo \esc_attr( $template_id ); ?>_email_subject" class="large-text" value="<?php echo \esc_attr( WP2FA::get_wp2fa_email_templates( $template_id . '_email_subject' ) ); ?>">
444 </fieldset>
445 </td>
446 </tr>
447 <tr>
448 <th>
449 <label for="<?php echo \esc_attr( $template_id ); ?>_email_body"><?php \esc_html_e( 'Email body', 'wp-2fa' ); ?></label>
450 </br>
451 <label for="<?php echo \esc_attr( $template_id ); ?>_email_tags" style="font-weight: 400;"><?php \esc_html_e( 'Available template tags:', 'wp-2fa' ); ?></label>
452 </br>
453 </br>
454 <span style="font-weight: 400;">
455 {site_url}</br>
456 {site_name}</br>
457 {grace_period}</br>
458 {user_login_name}</br>
459 {user_first_name}</br>
460 {user_last_name}</br>
461 {user_display_name}</br>
462 {login_code}</br>
463 {user_ip_address}</br>
464 {backup_codes}
465 {admin_email}
466 <?php
467 if ( ! empty( $custom_user_page_id ) ) {
468 echo '</br>{2fa_settings_page_url}';
469 }
470 ?>
471 </span>
472 </th>
473 <td>
474 <fieldset>
475 <?php
476 $message = WP2FA::get_wp2fa_email_templates( $template_id . '_email_body' );
477 $content = $message;
478 $editor_id = $template_id . '_email_body';
479 $settings = array(
480 'media_buttons' => false,
481 'editor_height' => 200,
482 );
483 \wp_editor( $content, $editor_id, $settings );
484 ?>
485 </fieldset>
486 <p>
487 <button type="button" name="test_email_<?php echo \esc_attr( $template_id ); ?>"
488 class="button js-button-test-email-trigger"
489 data-email-id="<?php echo \esc_attr( $template_id ); ?>"
490 <?php echo WP_Helper::create_data_nonce( 'wp-2fa-email-test-' . $template_id ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>>
491 <?php \esc_html_e( 'Send test email', 'wp-2fa' ); ?>
492 </button>
493 </p>
494 </td>
495 </tr>
496 </tbody>
497 </table>
498 <br>
499 <hr>
500 <?php endforeach; ?>
501 <?php
502 $additional_content = \apply_filters( WP_2FA_PREFIX . 'append_to_email_and_sms_template_settings', '' );
503 echo \wp_kses_post( $additional_content );
504 }
505 }
506 }
507