PluginProbe ʕ •ᴥ•ʔ
WP 2FA – Two-factor authentication for WordPress / 1.7.0
WP 2FA – Two-factor authentication for WordPress v1.7.0
4.1.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 / SetupWizard.php
wp-2fa / includes / classes / Admin Last commit date
Controllers 5 years ago Views 5 years ago SettingsPage.php 5 years ago SetupWizard.php 5 years ago User.php 5 years ago UserListing.php 5 years ago UserNotices.php 5 years ago UserProfile.php 5 years ago UserRegistered.php 5 years ago index.php 5 years ago
SetupWizard.php
594 lines
1 <?php // phpcs:ignore
2
3 namespace WP2FA\Admin;
4
5 use \WP2FA\Core as Core;
6 use \WP2FA\WP2FA as WP2FA;
7 use WP2FA\Admin\Views\WizardSteps;
8 use WP2FA\Admin\Controllers\Settings;
9 use \WP2FA\Utils\UserUtils as UserUtils;
10 use WP2FA\Admin\Views\FirstTimeWizardSteps;
11 use \WP2FA\Admin\UserProfile as UserProfile;
12 use \WP2FA\Admin\SettingsPage as SettingsPage;
13 use WP2FA\Utils\SettingsUtils as SettingsUtils;
14 use \WP2FA\Utils\GenerateModal as GenerateModal;
15 use \WP2FA\Authenticator\Authentication as Authentication;
16
17 /**
18 * Our class for creating a step by step wizard for easy configuration.
19 */
20 class SetupWizard {
21
22 /**
23 * Wizard Steps
24 *
25 * @var array
26 */
27 private $wizard_steps;
28
29 /**
30 * Current Step
31 *
32 * @var string
33 */
34 private $current_step;
35
36 /**
37 * Notices Meta key
38 *
39 * @var array
40 */
41 const NOTICES_META_KEY = 'wp_2fa_totp_notices';
42
43 /**
44 * Method: Constructor.
45 */
46 public function __construct() { }
47
48 /**
49 * Add setup admin page. This is empty on purpose.
50 */
51 public function admin_menus() {
52 add_dashboard_page( '', '', 'read', 'wp-2fa-setup', '' );
53 }
54
55 public function network_admin_menus() {
56 add_dashboard_page( 'index.php', '', 'read', 'wp-2fa-setup', '' );
57 }
58
59 /**
60 * Setup Page Start.
61 */
62 public function setup_page() {
63
64 // Get page argument from $_GET array.
65 $page = filter_input( INPUT_GET, 'page', FILTER_SANITIZE_STRING );
66 if ( empty( $page ) || 'wp-2fa-setup' !== $page ) {
67 return;
68 }
69
70 // Clear out any old notices.
71 $user = wp_get_current_user();
72 delete_user_meta( $user->ID, self::NOTICES_META_KEY );
73
74 // First lets check if any options have been saved.
75 $settings_saved = true;
76 $settings = WP2FA::get_wp2fa_setting();
77 if ( empty( $settings ) || ! isset( $settings ) ) {
78 $settings_saved = false;
79 }
80
81 /**
82 * Wizard Steps.
83 */
84 $get_array = filter_input_array( INPUT_GET );
85 if ( isset( $get_array['wizard_type'] ) ) {
86 $wizard_type = sanitize_text_field( $get_array['wizard_type'] );
87 } else {
88 $wizard_type = 'default';
89 }
90
91 $is_user_forced_to_setup = get_user_meta( $user->ID, WP_2FA_PREFIX . 'user_enforced_instantly', true );
92 if ( ! empty( $is_user_forced_to_setup ) ) {
93 add_filter( 'wp_2fa_wizard_default_steps', array( $this, 'wp_2fa_add_intro_step' ) );
94 }
95
96 $user_type = UserUtils::determine_user_2fa_status( $user );
97
98 $wizard_steps = array(
99 'welcome' => array(
100 'name' => esc_html__( 'Welcome', 'wp-2fa' ),
101 'content' => array( $this, 'wp_2fa_step_welcome' ),
102 'wizard_type' => 'welcome_wizard',
103 ),
104 'settings_configuation' => array(
105 'name' => esc_html__( 'Select 2FA Methods', 'wp-2fa' ),
106 'content' => array( $this, 'wp_2fa_step_global_2fa_methods' ),
107 'save' => array( $this, 'wp_2fa_step_global_2fa_methods_save' ),
108 'wizard_type' => 'welcome_wizard',
109 ),
110 'finish' => array(
111 'name' => esc_html__( 'Setup Finish', 'wp-2fa' ),
112 'content' => array( $this, 'wp_2fa_step_finish' ),
113 'save' => array( $this, 'wp_2fa_step_finish_save' ),
114 'wizard_type' => 'welcome_wizard',
115 ),
116 );
117
118 // Admin user setting up fresh install of 2FA plugin.
119 if ( in_array( 'can_manage_options', $user_type, true ) && ! $settings_saved ) {
120 unset( $wizard_steps['user_choose_2fa_method'] );
121 unset( $wizard_steps['reconfigure_method'] );
122 }
123
124 // We will use this setting to determine if defaults have already been saved to the DB.
125 $have_defaults_been_applied = SettingsUtils::get_option( 'default_settings_applied', false );
126 // If we have settings, but they are the defaults, then we want to consider the settings to be unsaved at this point.
127 if ( in_array( 'can_manage_options', $user_type, true ) && $settings_saved && $have_defaults_been_applied ) {
128 $settings_saved = false;
129 }
130
131 // Ensure user has minimum capabitlies needed to be here.
132 if ( in_array( 'can_read', $user_type, true ) && $settings_saved ) {
133
134 switch ( $wizard_type ) {
135 case 'user_2fa_config':
136 $wizard_steps = array_intersect_key( $wizard_steps, array_flip( ['user_choose_2fa_method', 'setup_method', 'finish', 'backup_codes'] ) );
137 break;
138
139 case 'backup_codes_config':
140 $wizard_steps = array_intersect_key( $wizard_steps, array_flip( ['backup_codes'] ) );
141 break;
142
143 case 'user_reconfigure_config':
144 $wizard_steps = array_intersect_key( $wizard_steps, array_flip( ['reconfigure_method'] ) );
145 break;
146
147 default:
148 $wizard_steps = array_intersect_key( $wizard_steps, array_flip( ['choose_2fa_method', 'setup_method', 'finish', 'backup_codes', 'reconfigure_method' ] ) );
149 }
150
151 // Remove 1st step if only one method is available.
152 if ( empty( WP2FA::get_wp2fa_setting( 'enable_totp' ) ) || empty( WP2FA::get_wp2fa_setting( 'enable_email' ) ) ) {
153 unset( $wizard_steps['choose_2fa_method'] );
154 }
155
156 // If the user has codes setup already, no need to add the slide.
157 if ( ! in_array( 'user_needs_to_setup_backup_codes', $user_type, true ) && 'backup_codes_config' !== $wizard_type ) {
158 unset( $wizard_steps['backup_codes'] );
159 }
160 }
161
162 /**
163 * Filter: `Wizard Default Steps`
164 *
165 * WSAL filter to filter wizard steps before they are displayed.
166 *
167 * @param array $wizard_steps – Wizard Steps.
168 */
169 $this->wizard_steps = apply_filters( 'wp_2fa_wizard_default_steps', $wizard_steps );
170
171 // Set current step.
172 $current_step = filter_input( INPUT_GET, 'current-step', FILTER_SANITIZE_STRING );
173 $this->current_step = ! empty( $current_step ) ? $current_step : current( array_keys( $this->wizard_steps ) );
174
175 if ( 'backup_codes' === $this->current_step && ! SettingsPage::are_backup_codes_enabled() ) {
176
177 $redirectToFinish = add_query_arg( ['current-step' => 'finish', 'all-set' => 1] );
178 wp_safe_redirect( esc_url_raw( $redirectToFinish ) );
179 }
180
181 /**
182 * Enqueue Scripts.
183 */
184 wp_enqueue_style(
185 'wp_2fa_setup_wizard',
186 Core\style_url( 'setup-wizard', 'admin' ),
187 array( 'select2' ),
188 WP_2FA_VERSION
189 );
190
191 \WP2FA\Core\enqueueSelect2Scripts();
192
193 if (\WP2FA\WP2FA::is_this_multisite()) {
194 \WP2FA\Core\enqueueMultiSelectScripts();
195 }
196
197 wp_enqueue_script(
198 'wp_2fa_admin',
199 Core\script_url( 'admin', 'admin' ),
200 array( 'jquery-ui-widget', 'jquery-ui-core', 'jquery-ui-autocomplete', 'select2' ),
201 WP_2FA_VERSION,
202 true
203 );
204
205 wp_enqueue_script(
206 'wp_2fa_micromodal',
207 Core\script_url( 'micromodal', 'admin', 'select2' ),
208 WP_2FA_VERSION,
209 true
210 );
211
212 // Data array.
213 $data_array = array(
214 'ajaxURL' => admin_url( 'admin-ajax.php' ),
215 'roles' => WP2FA::wp_2fa_get_roles(),
216 'nonce' => wp_create_nonce( 'wp-2fa-settings-nonce' )
217 );
218 wp_localize_script( 'wp_2fa_admin', 'wp2faData', $data_array );
219
220 // Data array.
221 $data_array = array(
222 'ajaxURL' => admin_url( 'admin-ajax.php' ),
223 'nonce' => wp_create_nonce( 'wp2fa-verify-wizard-page' ),
224 'codesPreamble' => esc_html__( 'These are the 2FA backup codes for the user', 'wp-2fa' ),
225 'readyText' => esc_html__( 'I\'m ready', 'wp-2fa' ),
226 'codeReSentText' => esc_html__( 'New code sent', 'wp-2fa' ),
227 );
228 wp_localize_script( 'wp_2fa_admin', 'wp2faWizardData', $data_array );
229
230 /**
231 * Save Wizard Settings.
232 */
233 $save_step = filter_input( INPUT_POST, 'save_step', FILTER_SANITIZE_STRING );
234 if ( ! empty( $save_step ) && ! empty( $this->wizard_steps[ $this->current_step ]['save'] ) ) {
235 call_user_func( $this->wizard_steps[ $this->current_step ]['save'] );
236 }
237
238 $this->setup_page_header();
239 $this->setup_page_steps();
240 $this->setup_page_content();
241 $this->setup_page_footer();
242
243 exit;
244 }
245
246 /**
247 * Setup Page Header.
248 */
249 private function setup_page_header() {
250 ?>
251 <!DOCTYPE html>
252 <html <?php language_attributes(); ?>>
253 <head>
254 <meta name="viewport" content="width=device-width" />
255 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
256 <title><?php esc_html_e( 'WP 2FA &rsaquo; Setup Wizard', 'wp-2fa' ); ?></title>
257 <?php wp_print_scripts( 'jquery' ); ?>
258 <?php wp_print_scripts( 'jquery-ui-core' ); ?>
259 <?php wp_print_scripts( 'wp_2fa_setup_wizard' ); ?>
260 <?php wp_print_scripts( 'wp_2fa_micromodal' ); ?>
261 <?php wp_print_scripts( 'wp_2fa_admin' ); ?>
262 <?php wp_print_scripts( 'multi-site-select' ); ?>
263 <?php wp_print_styles( 'common' ); ?>
264 <?php wp_print_styles( 'forms' ); ?>
265 <?php wp_print_styles( 'buttons' ); ?>
266 <?php wp_print_styles( 'wp-jquery-ui-dialog' ); ?>
267 <?php wp_print_styles( 'wp_2fa_admin' ); ?>
268 <?php do_action( 'admin_print_styles' ); ?>
269 </head>
270 <body class="wp2fa-setup wp-core-ui">
271 <div class="setup-wizard-wrapper">
272 <h1 id="wp2fa-logo"><a href="https://wpsecurityauditlog.com" target="_blank"><img src="<?php echo esc_url( WP_2FA_URL . 'dist/images/wizard-logo.png' ); ?>"></a></h1>
273 <?php
274 }
275
276 /**
277 * Setup Page Footer.
278 */
279 private function setup_page_footer() {
280 $user = wp_get_current_user();
281 $roles = (array) $user->roles;
282
283 $redirect = Settings::getSettingsPageLink();
284 ?>
285 <div class="wp2fa-setup-footer">
286 <?php if ( 'welcome' !== $this->current_step && 'finish' !== $this->current_step ) : // Don't show the link on the first & last step. ?>
287 <?php if ( ! get_user_meta( $user->ID, WP_2FA_PREFIX . 'user_enforced_instantly', true ) ) : ?>
288 <a class="close-wizard-link" href="<?php echo esc_url( $redirect ); ?>"><?php esc_html_e( 'Close Wizard', 'wp-2fa' ); ?></a>
289 <?php endif; ?>
290 <?php endif; ?>
291 </div>
292 </div>
293 </body>
294 </html>
295 <?php
296 echo GenerateModal::generate_modal(
297 'notify-admin-settings-page',
298 '',
299 __( 'If you cancel this wizard, the default plugin settings will be applied. You can always configure the plugin settings and two-factor authentication policies at a later stage from the ', 'wp-2fa' ) .' <b>'.__( 'WP 2FA', 'wp-2fa' ).'</b>' . __( ' entry in your WordPress dashboard menu.', 'wp-2fa' ),
300 [
301 '<a href="#" id="close-settings" class="modal__btn modal__btn-primary button-primary" data-redirect-url="'.esc_url( $redirect ).'">'. __( 'OK, close wizard', 'wp-2fa' ) .'</a>',
302 '<a href="#" class="modal__btn modal__btn-primary button-secondary" data-close-2fa-modal>'. __( 'Continue with wizard', 'wp-2fa' ) .'</a>',
303 ],
304 '',
305 '450px'
306 );
307 ?>
308 <?php
309 }
310
311 /**
312 * Setup Page Steps.
313 */
314 private function setup_page_steps() {
315 ?>
316 <ul class="steps">
317 <?php
318 foreach ( $this->wizard_steps as $key => $step ) :
319 if ( 'welcome_wizard' === $step['wizard_type'] || is_array( $step['wizard_type'] ) && in_array( 'welcome_wizard', $step['wizard_type'], true ) ) :
320 if ( $key === $this->current_step ) :
321 ?>
322 <li class="is-active"><?php echo esc_html( $step['name'] ); ?></li>
323 <?php
324 else :
325 ?>
326 <li><?php echo esc_html( $step['name'] ); ?></li>
327 <?php
328 endif;
329 endif;
330 endforeach;
331 ?>
332 </ul>
333 <?php
334 }
335
336 /**
337 * Get Next Step URL.
338 *
339 * @return string
340 */
341 private function get_next_step() {
342 // Get current step.
343 $current_step = $this->current_step;
344
345 // Array of step keys.
346 $keys = array_keys( $this->wizard_steps );
347 if ( end( $keys ) === $current_step ) { // If last step is active then return WP Admin URL.
348 return admin_url();
349 }
350
351 // Search for step index in step keys.
352 $step_index = array_search( $current_step, $keys, true );
353 if ( false === $step_index ) { // If index is not found then return empty string.
354 return '';
355 }
356
357 // Return next step.
358 return add_query_arg( 'current-step', $keys[ $step_index + 1 ] );
359 }
360
361 /**
362 * Setup Page Content.
363 */
364 private function setup_page_content() {
365 ?>
366 <div class="wp2fa-setup-content">
367 <?php
368 if ( ! empty( $this->wizard_steps[ $this->current_step ]['content'] ) ) {
369 call_user_func( $this->wizard_steps[ $this->current_step ]['content'] );
370 }
371 ?>
372 </div>
373 <?php
374 }
375
376 /**
377 * Step View: `Welcome`
378 */
379 private function wp_2fa_step_welcome() {
380 WizardSteps::welcomeStep( $this->get_next_step() );
381 }
382
383 /**
384 * Step View: `Finish`
385 */
386 private function wp_2fa_step_finish() {
387
388 $wp2faUser = new User();
389 $wp2faUser->deleteUserMeta( WP_2FA_PREFIX . 'user_needs_to_reconfigure_2fa');
390
391 WizardSteps::congratulationsStep( true );
392 }
393
394 /**
395 * Step Save: `Finish`
396 */
397 private function wp_2fa_step_finish_save() {
398 // Verify nonce.
399 check_admin_referer( 'wp2fa-step-finish' );
400 wp_safe_redirect( esc_url_raw( $this->get_next_step() ) );
401 exit();
402 }
403
404 /**
405 * Step View: `Choose Methods`
406 */
407 private function wp_2fa_step_global_2fa_methods() {
408 $enforced_roles = WP2FA::get_wp2fa_setting( 'enforced_roles' );
409 $enforced_users = WP2FA::get_wp2fa_setting( 'enforced_users' );
410 $excluded_users = WP2FA::get_wp2fa_setting( 'excluded_users' );
411 $excluded_roles = WP2FA::get_wp2fa_setting( 'excluded_roles' );
412 ?>
413 <form method="post" class="wp2fa-setup-form" autocomplete="off">
414 <?php wp_nonce_field( 'wp2fa-step-choose-method' ); ?>
415 <div class="step-setting-wrapper active" data-step-title="<?php esc_html_e( 'Choose 2FA methods', 'wp-2fa' ); ?>">
416 <?php FirstTimeWizardSteps::selectMethod( true ); ?>
417 <div class="wp2fa-setup-actions">
418 <a class="button button-primary" name="next_step_setting" value="<?php esc_attr_e( 'Continue Setup', 'wp-2fa' ); ?>"><?php esc_html_e( 'Continue Setup', 'wp-2fa' ); ?></a>
419 </div>
420 </div>
421 <div class="step-setting-wrapper" data-step-title="<?php esc_html_e( '2FA policy', 'wp-2fa' ); ?>">
422 <?php FirstTimeWizardSteps::enforcementPolicy( true ); ?>
423 <div class="wp2fa-setup-actions">
424 <a class="button button-primary" name="next_step_setting" value="<?php esc_attr_e( 'Continue Setup', 'wp-2fa' ); ?>"><?php esc_html_e( 'Continue Setup', 'wp-2fa' ); ?></a>
425 </div>
426 </div>
427 <div class="step-setting-wrapper hidden" data-step-title="<?php esc_html_e( 'Exclude users', 'wp-2fa' ); ?>">
428 <?php FirstTimeWizardSteps::excludeUsers( true ); ?>
429 <div class="wp2fa-setup-actions">
430 <a class="button button-primary" name="next_step_setting" value="<?php esc_attr_e( 'Continue Setup', 'wp-2fa' ); ?>"><?php esc_html_e( 'Continue Setup', 'wp-2fa' ); ?></a>
431 </div>
432 </div>
433
434 <?php if ( WP2FA::is_this_multisite() ) : ?>
435 <div class="step-setting-wrapper" data-step-title="<?php esc_html_e( 'Exclude sites', 'wp-2fa' ); ?>">
436 <?php FirstTimeWizardSteps::excludedNetworkSites( true ) ?>
437 <div class="wp2fa-setup-actions">
438 <a class="button button-primary" name="next_step_setting" value="<?php esc_attr_e( 'Continue Setup', 'wp-2fa' ); ?>"><?php esc_html_e( 'Continue Setup', 'wp-2fa' ); ?></a>
439 </div>
440 </div>
441 <?php endif; ?>
442
443 <div class="step-setting-wrapper" data-step-title="<?php esc_html_e( 'Grace period', 'wp-2fa' ); ?>">
444 <h3><?php esc_html_e( 'How long should the grace period for your users be?', 'wp-2fa' ); ?></h3>
445 <p><?php esc_html_e( 'When you configure the 2FA policies and require users to configure 2FA, they can either have a grace period to configure 2FA, or can be required to configure 2FA before the next time they login. Choose which method you\'d like to use:', 'wp-2fa' ); ?></p>
446 <?php FirstTimeWizardSteps::gracePeriod( true ); ?>
447 <div class="wp2fa-setup-actions">
448 <button class="button button-primary save-wizard" type="submit" name="save_step" value="<?php esc_attr_e( 'All done', 'wp-2fa' ); ?>"><?php esc_html_e( 'All done', 'wp-2fa' ); ?></button>
449 </div>
450 </div>
451
452 </form>
453 <?php
454 }
455
456 /**
457 * Step Save: `Choose Method`
458 */
459 private function wp_2fa_step_global_2fa_methods_save() {
460 // Check nonce.
461 check_admin_referer( 'wp2fa-step-choose-method' );
462
463 $input = ( isset( $_POST[ WP_2FA_SETTINGS_NAME ] ) ) ? wp_unslash( $_POST[ WP_2FA_SETTINGS_NAME ] ) : array();
464
465 if ( ! WP2FA::is_this_multisite() ) {
466 unregister_setting(
467 WP_2FA_SETTINGS_NAME,
468 WP_2FA_SETTINGS_NAME
469 );
470 }
471 $settings_page = new SettingsPage;
472 $sanitized_settings = $settings_page->validate_and_sanitize( $input, 'setup_wizard' );
473 $update_options = SettingsUtils::update_option( WP_2FA_SETTINGS_NAME, $sanitized_settings );
474
475 wp_safe_redirect( esc_url_raw( $this->get_next_step() ) );
476 exit();
477 }
478
479 /**
480 * Send email with fresh code, or to setup email 2fa.
481 *
482 * @param int $user_id User id we want to send the message to.
483 * @param string $nonce The nonce.
484 *
485 * @return bool
486 */
487 public static function send_authentication_setup_email( $user_id, $nonce = '' ) {
488
489 // If we have a nonce posted, check it.
490 if ( wp_doing_ajax() && isset( $_POST['nonce'] ) ) {
491 $nonce_check = wp_verify_nonce( sanitize_text_field( $_POST['nonce'] ), 'wp-2fa-send-setup-email' );
492 if ( ! $nonce_check ) {
493 return false;
494 exit();
495 }
496 }
497
498 if ( isset( $_POST['user_id'] ) ) {
499 $user = get_userdata( intval( $_POST['user_id'] ) );
500 } else {
501 $user = get_userdata( $user_id );
502 }
503
504 // Seeing as we got this far, we need to clear notices to make way for anything fresh.
505 delete_user_meta( $user->ID, self::NOTICES_META_KEY );
506
507 // Grab email address is its provided.
508 if ( isset( $_POST['email_address'] ) ) {
509 $email = sanitize_email( $_POST['email_address'] );
510 } else {
511 $email = sanitize_email( $user->user_email );
512 }
513
514 if ( wp_doing_ajax() && isset( $_POST['nonce'] ) ) {
515 update_user_meta( $user->ID, WP_2FA_PREFIX . 'nominated_email_address', $email );
516 }
517
518 $enabled_email_address = get_user_meta( $user->ID, WP_2FA_PREFIX . 'nominated_email_address', true );
519
520 // Generate a token and setup email.
521 $token = Authentication::generate_token( $user->ID );
522 $subject = wp_strip_all_tags( WP2FA::replace_email_strings( WP2FA::get_wp2fa_email_templates( 'login_code_email_subject' ), $user->ID ) );
523 $message = wpautop( WP2FA::replace_email_strings( WP2FA::get_wp2fa_email_templates( 'login_code_email_body' ), $user->ID, $token ) );
524
525 if ( ! empty( $enabled_email_address ) ) {
526 $email_address = $enabled_email_address;
527 } else {
528 $email_address = $user->user_email;
529 }
530
531 return SettingsPage::send_email( $email_address, $subject, $message );
532 }
533
534 /**
535 * Send email to setup authentication
536 */
537 public function regenerate_authentication_key() {
538 // Grab current user.
539 $user = wp_get_current_user();
540
541 // Delete the key and enabled methods
542 Authentication::delete_user_totp_key( $user->ID );
543 delete_user_meta( $user->ID, WP_2FA_PREFIX . 'enabled_methods' );
544
545 $key = Authentication::generate_key();
546 update_user_meta( $user->ID, WP_2FA_PREFIX . 'totp_key', $key );
547
548 $site_name = get_bloginfo( 'name', 'display' );
549 $totp_title = apply_filters( 'wp_2fa_totp_title', $site_name . ':' . $user->user_login, $user );
550 $new_qr = Authentication::get_google_qr_code( $totp_title, $key, $site_name );
551
552 wp_send_json_success(
553 array(
554 'key' => $key,
555 'qr' => $new_qr,
556 )
557 );
558 }
559
560 /**
561 * 3rd Party plugins
562 */
563 function wp_2fa_add_intro_step( $wizard_steps ) {
564 $new_wizard_steps = array(
565 'test' => array(
566 'name' => __( 'Welcome to WP 2FA', 'wp-2fa' ),
567 'content' => array( $this, 'introduction_step' ),
568 'save' => array( $this, 'introduction_step_save' ),
569 'wizard_type' => 'welcome_wizard',
570 ),
571 );
572
573 // combine the two arrays.
574 $wizard_steps = $new_wizard_steps + $wizard_steps;
575
576 return $wizard_steps;
577 }
578
579 private function introduction_step() {
580 WizardSteps::introductionStep();
581 }
582
583 /**
584 * Step Save: `Addons`
585 */
586 private function introduction_step_save() {
587 // Check nonce.
588 check_admin_referer( 'wp2fa-step-addon' );
589
590 wp_safe_redirect( esc_url_raw( $this->get_next_step() ) );
591 exit();
592 }
593 }
594