PluginProbe ʕ •ᴥ•ʔ
WP 2FA – Two-factor authentication for WordPress / 2.0.0
WP 2FA – Two-factor authentication for WordPress v2.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 4 years ago SettingsPages 4 years ago Views 4 years ago HelpContactUs.php 4 years ago PremiumFeatures.php 4 years ago SettingsPage.php 4 years ago SetupWizard.php 4 years ago User.php 4 years ago UserListing.php 4 years ago UserNotices.php 4 years ago UserProfile.php 4 years ago UserRegistered.php 4 years ago index.php 5 years ago
SetupWizard.php
592 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\SettingsPage as SettingsPage;
12 use WP2FA\Utils\SettingsUtils as SettingsUtils;
13 use \WP2FA\Utils\GenerateModal as GenerateModal;
14 use \WP2FA\Authenticator\Authentication as Authentication;
15 use WP2FA\Admin\SettingsPages\Settings_Page_Policies;
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( $user->roles[0] ) ) {
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 wp_enqueue_style(
192 'wp_2fa_admin-style',
193 Core\style_url( 'admin-style', 'admin' ),
194 WP_2FA_VERSION
195 );
196
197 \WP2FA\Core\enqueueSelect2Scripts();
198
199 if (\WP2FA\WP2FA::is_this_multisite()) {
200 \WP2FA\Core\enqueueMultiSelectScripts();
201 }
202
203 wp_enqueue_script(
204 'wp_2fa_admin',
205 Core\script_url( 'admin', 'admin' ),
206 array( 'jquery-ui-widget', 'jquery-ui-core', 'jquery-ui-autocomplete', 'select2' ),
207 WP_2FA_VERSION,
208 true
209 );
210
211 wp_enqueue_script(
212 'wp_2fa_micromodal',
213 Core\script_url( 'micromodal', 'admin', 'select2' ),
214 WP_2FA_VERSION,
215 true
216 );
217
218 // Data array.
219 $data_array = array(
220 'ajaxURL' => admin_url( 'admin-ajax.php' ),
221 'roles' => WP2FA::wp_2fa_get_roles(),
222 'nonce' => wp_create_nonce( 'wp-2fa-settings-nonce' )
223 );
224 wp_localize_script( 'wp_2fa_admin', 'wp2faData', $data_array );
225
226 // Data array.
227 $data_array = array(
228 'ajaxURL' => admin_url( 'admin-ajax.php' ),
229 'nonce' => wp_create_nonce( 'wp2fa-verify-wizard-page' ),
230 'codesPreamble' => esc_html__( 'These are the 2FA backup codes for the user', 'wp-2fa' ),
231 'readyText' => esc_html__( 'I\'m ready', 'wp-2fa' ),
232 'codeReSentText' => esc_html__( 'New code sent', 'wp-2fa' ),
233 );
234 wp_localize_script( 'wp_2fa_admin', 'wp2faWizardData', $data_array );
235
236 /**
237 * Save Wizard Settings.
238 */
239 $save_step = filter_input( INPUT_POST, 'save_step', FILTER_SANITIZE_STRING );
240 if ( ! empty( $save_step ) && ! empty( $this->wizard_steps[ $this->current_step ]['save'] ) ) {
241 call_user_func( $this->wizard_steps[ $this->current_step ]['save'] );
242 }
243
244 $this->setup_page_header();
245 $this->setup_page_steps();
246 $this->setup_page_content();
247 $this->setup_page_footer();
248
249 exit;
250 }
251
252 /**
253 * Setup Page Header.
254 */
255 private function setup_page_header() {
256 ?>
257 <!DOCTYPE html>
258 <html <?php language_attributes(); ?>>
259 <head>
260 <meta name="viewport" content="width=device-width" />
261 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
262 <title><?php esc_html_e( 'WP 2FA &rsaquo; Setup Wizard', 'wp-2fa' ); ?></title>
263 <?php wp_print_scripts( 'jquery' ); ?>
264 <?php wp_print_scripts( 'jquery-ui-core' ); ?>
265 <?php wp_print_scripts( 'wp_2fa_setup_wizard' ); ?>
266 <?php wp_print_scripts( 'wp_2fa_micromodal' ); ?>
267 <?php wp_print_scripts( 'wp_2fa_admin' ); ?>
268 <?php wp_print_scripts( 'multi-site-select' ); ?>
269 <?php wp_print_styles( 'common' ); ?>
270 <?php wp_print_styles( 'forms' ); ?>
271 <?php wp_print_styles( 'buttons' ); ?>
272 <?php wp_print_styles( 'wp-jquery-ui-dialog' ); ?>
273 <?php wp_print_styles( 'wp_2fa_admin' ); ?>
274 <?php do_action( 'admin_print_styles' ); ?>
275 </head>
276 <body class="wp2fa-setup wp-core-ui">
277 <div class="setup-wizard-wrapper wp-2fa-settings-wrapper">
278 <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>
279 <?php
280 }
281
282 /**
283 * Setup Page Footer.
284 */
285 private function setup_page_footer() {
286 $user = wp_get_current_user();
287 $roles = (array) $user->roles;
288
289 $redirect = Settings::get_settings_page_link();
290 ?>
291 <div class="wp2fa-setup-footer">
292 <?php if ( 'welcome' !== $this->current_step && 'finish' !== $this->current_step ) : // Don't show the link on the first & last step. ?>
293 <?php if ( ! get_user_meta( $user->ID, WP_2FA_PREFIX . 'user_enforced_instantly', true ) ) : ?>
294 <a class="close-wizard-link" href="<?php echo esc_url( $redirect ); ?>"><?php esc_html_e( 'Close Wizard', 'wp-2fa' ); ?></a>
295 <?php endif; ?>
296 <?php endif; ?>
297 </div>
298 </div>
299 </body>
300 </html>
301 <?php
302 echo GenerateModal::generate_modal(
303 'notify-admin-settings-page',
304 '',
305 __( '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' ),
306 [
307 '<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>',
308 '<a href="#" class="modal__btn modal__btn-primary button-secondary" data-close-2fa-modal>'. __( 'Continue with wizard', 'wp-2fa' ) .'</a>',
309 ],
310 '',
311 '450px'
312 );
313 ?>
314 <?php
315 }
316
317 /**
318 * Setup Page Steps.
319 */
320 private function setup_page_steps() {
321 ?>
322 <ul class="steps">
323 <?php
324 foreach ( $this->wizard_steps as $key => $step ) :
325 if ( 'welcome_wizard' === $step['wizard_type'] || is_array( $step['wizard_type'] ) && in_array( 'welcome_wizard', $step['wizard_type'], true ) ) :
326 if ( $key === $this->current_step ) :
327 ?>
328 <li class="is-active"><?php echo esc_html( $step['name'] ); ?></li>
329 <?php
330 else :
331 ?>
332 <li><?php echo esc_html( $step['name'] ); ?></li>
333 <?php
334 endif;
335 endif;
336 endforeach;
337 ?>
338 </ul>
339 <?php
340 }
341
342 /**
343 * Get Next Step URL.
344 *
345 * @return string
346 */
347 private function get_next_step() {
348 // Get current step.
349 $current_step = $this->current_step;
350
351 // Array of step keys.
352 $keys = array_keys( $this->wizard_steps );
353 if ( end( $keys ) === $current_step ) { // If last step is active then return WP Admin URL.
354 return admin_url();
355 }
356
357 // Search for step index in step keys.
358 $step_index = array_search( $current_step, $keys, true );
359 if ( false === $step_index ) { // If index is not found then return empty string.
360 return '';
361 }
362
363 // Return next step.
364 return add_query_arg( 'current-step', $keys[ $step_index + 1 ] );
365 }
366
367 /**
368 * Setup Page Content.
369 */
370 private function setup_page_content() {
371 ?>
372 <div class="wp2fa-setup-content">
373 <?php
374 if ( ! empty( $this->wizard_steps[ $this->current_step ]['content'] ) ) {
375 call_user_func( $this->wizard_steps[ $this->current_step ]['content'] );
376 }
377 ?>
378 </div>
379 <?php
380 }
381
382 /**
383 * Step View: `Welcome`
384 */
385 private function wp_2fa_step_welcome() {
386 WizardSteps::welcomeStep( $this->get_next_step() );
387 }
388
389 /**
390 * Step View: `Finish`
391 */
392 private function wp_2fa_step_finish() {
393 $wp2faUser = User::get_instance();
394 $wp2faUser->deleteUserMeta( WP_2FA_PREFIX . 'user_needs_to_reconfigure_2fa' );
395 WizardSteps::congratulations_step( true );
396 }
397
398 /**
399 * Step Save: `Finish`
400 */
401 private function wp_2fa_step_finish_save() {
402 // Verify nonce.
403 check_admin_referer( 'wp2fa-step-finish' );
404 wp_safe_redirect( esc_url_raw( $this->get_next_step() ) );
405 exit();
406 }
407
408 /**
409 * Step View: `Choose Methods`
410 */
411 private function wp_2fa_step_global_2fa_methods() {
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::select_method( 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 class="description"><?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_POLICY_SETTINGS_NAME ] ) ) ? wp_unslash( $_POST[ WP_2FA_POLICY_SETTINGS_NAME ] ) : array();
464
465 if ( ! WP2FA::is_this_multisite() ) {
466 unregister_setting(
467 WP_2FA_POLICY_SETTINGS_NAME,
468 WP_2FA_POLICY_SETTINGS_NAME
469 );
470 }
471 $settings_page = new Settings_Page_Policies();
472 $sanitized_settings = $settings_page->validate_and_sanitize( $input, 'setup_wizard' );
473 WP2FA::updatePluginSettings( $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 $nominated_email_address - The user custom address to use (name of the meta key to check for).
484 *
485 * @return bool
486 */
487 public static function send_authentication_setup_email( $user_id, $nominated_email_address = 'nominated_email_address' ) {
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 = '';
519 if ( ! empty( $nominated_email_address ) ) {
520 $enabled_email_address = get_user_meta( $user->ID, WP_2FA_PREFIX . $nominated_email_address, true );
521 }
522
523 // Generate a token and setup email.
524 $token = Authentication::generate_token( $user->ID );
525 $subject = wp_strip_all_tags( WP2FA::replace_email_strings( WP2FA::get_wp2fa_email_templates( 'login_code_email_subject' ), $user->ID ) );
526 $message = wpautop( WP2FA::replace_email_strings( WP2FA::get_wp2fa_email_templates( 'login_code_email_body' ), $user->ID, $token ) );
527
528 if ( ! empty( $enabled_email_address ) ) {
529 $email_address = $enabled_email_address;
530 } else {
531 $email_address = $user->user_email;
532 }
533
534 return SettingsPage::send_email( $email_address, $subject, $message );
535 }
536
537 /**
538 * Send email to setup authentication
539 */
540 public function regenerate_authentication_key() {
541 // Grab current user.
542 $user = wp_get_current_user();
543
544 $key = Authentication::generate_key();
545
546 $site_name = get_bloginfo( 'name', 'display' );
547 $totp_title = apply_filters( 'wp_2fa_totp_title', $site_name . ':' . $user->user_login, $user );
548 $new_qr = Authentication::get_google_qr_code( $totp_title, $key, $site_name );
549
550 wp_send_json_success(
551 array(
552 'key' => Authentication::decrypt_key_if_needed( $key ),
553 'qr' => $new_qr,
554 )
555 );
556 }
557
558 /**
559 * 3rd Party plugins
560 */
561 function wp_2fa_add_intro_step( $wizard_steps ) {
562 $new_wizard_steps = array(
563 'test' => array(
564 'name' => __( 'Welcome to WP 2FA', 'wp-2fa' ),
565 'content' => array( $this, 'introduction_step' ),
566 'save' => array( $this, 'introduction_step_save' ),
567 'wizard_type' => 'welcome_wizard',
568 ),
569 );
570
571 // combine the two arrays.
572 $wizard_steps = $new_wizard_steps + $wizard_steps;
573
574 return $wizard_steps;
575 }
576
577 private function introduction_step() {
578 WizardSteps::introductionStep();
579 }
580
581 /**
582 * Step Save: `Addons`
583 */
584 private function introduction_step_save() {
585 // Check nonce.
586 check_admin_referer( 'wp2fa-step-addon' );
587
588 wp_safe_redirect( esc_url_raw( $this->get_next_step() ) );
589 exit();
590 }
591 }
592