class-first-time-wizard-steps-new.php
1 week ago
class-first-time-wizard-steps.php
1 week ago
class-grace-period-notifications.php
1 week ago
class-passord-reset-2fa.php
1 week ago
class-re-login-2fa.php
1 week ago
class-wizard-steps.php
1 week ago
index.php
1 week ago
class-first-time-wizard-steps-new.php
786 lines
| 1 | <?php |
| 2 | /** |
| 3 | * First Time Wizard Steps (New Design) – renders each wizard step |
| 4 | * using the Settings_Builder component system. |
| 5 | * |
| 6 | * @package wp2fa |
| 7 | * @subpackage views |
| 8 | * @since 4.0.0 |
| 9 | */ |
| 10 | |
| 11 | namespace WP2FA\Admin\Views; |
| 12 | |
| 13 | use WP2FA\WP2FA; |
| 14 | use WP2FA\Methods\TOTP; |
| 15 | use WP2FA\Methods\Email; |
| 16 | use WP2FA\Methods\Backup_Codes; |
| 17 | use WP2FA\Utils\Settings_Utils; |
| 18 | use WP2FA\Admin\Settings_Builder; |
| 19 | use WP2FA\Admin\Helpers\WP_Helper; |
| 20 | use WP2FA\Admin\Helpers\Methods_Helper; |
| 21 | use WP2FA\Admin\Views\Grace_Period_Notifications; |
| 22 | |
| 23 | defined( 'ABSPATH' ) || exit; |
| 24 | |
| 25 | if ( ! class_exists( '\WP2FA\Admin\Views\First_Time_Wizard_Steps_New' ) ) { |
| 26 | /** |
| 27 | * Static helper that outputs each wizard step's form fields |
| 28 | * using the new Settings_Builder components. |
| 29 | * |
| 30 | * @since 4.0.0 |
| 31 | */ |
| 32 | class First_Time_Wizard_Steps_New { |
| 33 | |
| 34 | /** |
| 35 | * Name prefix used in all form fields so they are collected |
| 36 | * under a single $_POST key. |
| 37 | */ |
| 38 | private const NAME_PREFIX = WP_2FA_POLICY_SETTINGS_NAME; |
| 39 | |
| 40 | /* |
| 41 | ============================================================== |
| 42 | * STEP 1 – 2FA Methods |
| 43 | * ============================================================== |
| 44 | */ |
| 45 | |
| 46 | /** |
| 47 | * Render the primary 2FA methods step. |
| 48 | * |
| 49 | * @return void |
| 50 | */ |
| 51 | public static function step_methods() { |
| 52 | $totp_enabled = ! empty( Settings_Utils::get_setting_role( null, TOTP::POLICY_SETTINGS_NAME, true ) ); |
| 53 | $email_enabled = ! empty( Settings_Utils::get_setting_role( null, Email::POLICY_SETTINGS_NAME, true ) ); |
| 54 | |
| 55 | // Build primary methods sortable list via the same filter used in policies. |
| 56 | $all_methods = array(); |
| 57 | $all_methods = \apply_filters( WP_2FA_PREFIX . 'methods_policy_settings_new', $all_methods, null ); |
| 58 | |
| 59 | $methods_order = Settings_Utils::get_setting_role( null, Methods_Helper::POLICY_SETTINGS_NAME, true ); |
| 60 | if ( \is_array( $methods_order ) && ! empty( $methods_order ) ) { |
| 61 | $ordered = array(); |
| 62 | foreach ( $methods_order as $slug ) { |
| 63 | if ( isset( $all_methods[ $slug ] ) ) { |
| 64 | $ordered[ $slug ] = $all_methods[ $slug ]; |
| 65 | } |
| 66 | } |
| 67 | foreach ( $all_methods as $slug => $m ) { |
| 68 | if ( ! isset( $ordered[ $slug ] ) ) { |
| 69 | $ordered[ $slug ] = $m; |
| 70 | } |
| 71 | } |
| 72 | $all_methods = $ordered; |
| 73 | } |
| 74 | ?> |
| 75 | <h3><?php \esc_html_e( 'Which 2FA methods can your users use?', 'wp-2fa' ); ?></h3> |
| 76 | <!-- <p class="description"> |
| 77 | <?php // \esc_html_e( 'Allowing users to set up a secondary 2FA method is highly recommended. You can do this in the next step of the wizard. This will allow users to log in using an alternative method should they, for example lose access to their phone.', 'wp-2fa' ); ?> |
| 78 | </p> --> |
| 79 | |
| 80 | <?php |
| 81 | $all_methods = null; |
| 82 | if ( ! empty( $all_methods ) ) { |
| 83 | $sortable_items = array(); |
| 84 | foreach ( $all_methods as $method ) { |
| 85 | $item = array( |
| 86 | 'id' => $method['setting'], |
| 87 | 'title' => $method['title'], |
| 88 | 'order_id' => $method['id'], |
| 89 | 'checkbox_name' => self::NAME_PREFIX . '[' . $method['setting'] . ']', |
| 90 | 'checked' => ! empty( $method['enabled'] ), |
| 91 | ); |
| 92 | if ( ! empty( $method['extra_settings'] ) ) { |
| 93 | $item['extra_settings'] = $method['extra_settings']; |
| 94 | } |
| 95 | $sortable_items[] = $item; |
| 96 | } |
| 97 | |
| 98 | Settings_Builder::build_option( |
| 99 | array( |
| 100 | 'id' => 'wizard-methods-order', |
| 101 | 'type' => 'sortable-list', |
| 102 | 'items' => $sortable_items, |
| 103 | 'name_prefix' => self::NAME_PREFIX . '[methods_order]', |
| 104 | ) |
| 105 | ); |
| 106 | } else { |
| 107 | // Fallback: render simple checkboxes for TOTP and Email. |
| 108 | ?> |
| 109 | <div class="wizard-methods-list"> |
| 110 | <div class="wizard-method-card"> |
| 111 | <!-- Hidden input ensures unchecked box submits empty value --> |
| 112 | <input type="hidden" name="<?php echo esc_attr( self::NAME_PREFIX . '[' . TOTP::POLICY_SETTINGS_NAME . ']' ); ?>" value=""> |
| 113 | <?php |
| 114 | Settings_Builder::build_option( |
| 115 | array( |
| 116 | 'id' => 'wizard-totp', |
| 117 | 'type' => 'checkbox', |
| 118 | 'option_name' => self::NAME_PREFIX . '[' . TOTP::POLICY_SETTINGS_NAME . ']', |
| 119 | 'default' => $totp_enabled ? TOTP::POLICY_SETTINGS_NAME : '', |
| 120 | 'text' => '<strong>' . \esc_html__( 'One-time code via 2FA app', 'wp-2fa' ). '</strong>'/*. ' - <a href="https://melapress.com/support/kb/wp-2fa-configuring-2fa-apps/?&utm_source=plugin&utm_medium=wp2fa&utm_campaign=totp_aplications_help" target="_blank" rel="noopener">' . \esc_html__( 'complete list of supported 2FA apps.', 'wp-2fa' ) . '</a>'*/, |
| 121 | 'not_bool' => true, |
| 122 | 'not_id' => true, |
| 123 | 'value' => TOTP::POLICY_SETTINGS_NAME, |
| 124 | ) |
| 125 | ); |
| 126 | ?> |
| 127 | <p class="wizard-method-desc"> |
| 128 | <?php |
| 129 | echo \wp_sprintf( |
| 130 | /* translators: link to the knowledge base website */ |
| 131 | \esc_html__( 'When using this method, users will need to configure a 2FA app to get the one-time login code. The plugin supports all standard 2FA apps. Refer to the %s for more information. Allowing users to configure a secondary 2FA method is highly recommended. You can configure this in the next step of the wizard. This allows users to log in using an alternative method if they lose access to their primary 2FA device, such as their phone.', 'wp-2fa' ), |
| 132 | '<a href="https://melapress.com/support/kb/wp-2fa-configuring-2fa-apps/?&utm_source=plugin&utm_medium=wp2fa&utm_campaign=guide_how_to_setup_2fa_apps" target="_blank">' . \esc_html__( 'guide on how to set up 2FA apps', 'wp-2fa' ) . '</a>' |
| 133 | ); |
| 134 | ?> |
| 135 | </p> |
| 136 | </div> |
| 137 | |
| 138 | <div class="wizard-method-card"> |
| 139 | <!-- Hidden input ensures unchecked box submits empty value --> |
| 140 | <input type="hidden" name="<?php echo \esc_attr( self::NAME_PREFIX . '[' . Email::POLICY_SETTINGS_NAME . ']' ); ?>" value=""> |
| 141 | <?php |
| 142 | Settings_Builder::build_option( |
| 143 | array( |
| 144 | 'id' => 'wizard-email', |
| 145 | 'type' => 'checkbox', |
| 146 | 'option_name' => self::NAME_PREFIX . '[' . Email::POLICY_SETTINGS_NAME . ']', |
| 147 | 'default' => $email_enabled ? Email::POLICY_SETTINGS_NAME : '', |
| 148 | 'text' => '<strong>' . \esc_html__( 'One-time code via email', 'wp-2fa' ) . '</strong>- ' . \esc_html__( 'ensure email deliverability with the free plugin ', 'wp-2fa' ) . '<a href="https://wordpress.org/plugins/wp-mail-smtp/" target="_blank" rel="nofollow">WP Mail SMTP</a>', |
| 149 | 'not_bool' => true, |
| 150 | 'not_id' => true, |
| 151 | 'value' => Email::POLICY_SETTINGS_NAME, |
| 152 | ) |
| 153 | ); |
| 154 | ?> |
| 155 | <p class="wizard-method-desc"> |
| 156 | <?php |
| 157 | echo \wp_sprintf( |
| 158 | /* translators: 1. Link to WP Mail SMTP plugin, 2. Recommendation to allow users to set up a secondary method. */ |
| 159 | \esc_html__( 'When using this method, users will receive the one-time login code over email. Therefore, email deliverability is very important. Users using this method should whitelist the address from which the codes are sent. By default, this is the email address configured in your WordPress. You can run an email test from the plugin\'s settings to confirm email deliverability. If you have had email deliverability / reliability issues, we highly recommend you to install the free plugin %1$s', 'wp-2fa' ), |
| 160 | '<a href="https://wordpress.org/plugins/wp-mail-smtp/" target="_blank" rel="nofollow">WP Mail SMTP</a>' |
| 161 | ); |
| 162 | ?> |
| 163 | </p> |
| 164 | </div> |
| 165 | </div> |
| 166 | <?php |
| 167 | } |
| 168 | |
| 169 | /** |
| 170 | * Allow extensions to add additional methods below the main list. |
| 171 | * |
| 172 | * @param bool $wizard True – this is the wizard context. |
| 173 | * @param string $data_role Data-role attribute (empty in new wizard). |
| 174 | * @param string|null $name Role name (null for global). |
| 175 | * |
| 176 | * @since 2.0.0 |
| 177 | */ |
| 178 | \do_action( WP_2FA_PREFIX . 'after_primary_methods_toggles', null ); |
| 179 | |
| 180 | ?> |
| 181 | |
| 182 | <div class="wizard-info-blue-notice"> |
| 183 | <p><?php \esc_html_e( 'Allowing users to configure a secondary 2FA method is highly recommended. You can configure this in the next step of the wizard. This allows users to log in using an alternative method if they lose access to their primary 2FA device, such as their phone.', 'wp-2fa' ); ?></p> |
| 184 | </div> |
| 185 | <?php |
| 186 | ?> |
| 187 | <?php |
| 188 | } |
| 189 | |
| 190 | /* |
| 191 | ============================================================== |
| 192 | * STEP 2 – Alternative Methods |
| 193 | * ============================================================== |
| 194 | */ |
| 195 | |
| 196 | /** |
| 197 | * Render the alternative / backup methods step. |
| 198 | * |
| 199 | * @return void |
| 200 | */ |
| 201 | public static function step_alternative_methods() { |
| 202 | $backup_enabled = Settings_Utils::string_to_bool( Settings_Utils::get_setting_role( null, Backup_Codes::get_settings_name(), true ) ); |
| 203 | $email_backup_enabled = Settings_Utils::get_setting_role( null, 'enable-email-backup', true ); |
| 204 | |
| 205 | ?> |
| 206 | <h3><?php \esc_html_e( 'Which secondary 2FA methods can users use?', 'wp-2fa' ); ?></h3> |
| 207 | <p class="description"> |
| 208 | <?php \esc_html_e( 'A secondary 2FA method acts as a backup when the primary method cannot be used. For example, if a user loses access to their phone, the device runs out of battery, or email delivery fails. We strongly recommend allowing users to configure at least one backup method at all times.', 'wp-2fa' ); ?> |
| 209 | </p> |
| 210 | <!-- <p class="description"> |
| 211 | <?php // \esc_html_e( 'Available secondary 2FA methods:', 'wp-2fa' ); ?> |
| 212 | </p> --> |
| 213 | |
| 214 | <div class="wizard-method-card"> |
| 215 | <?php |
| 216 | Settings_Builder::build_option( |
| 217 | array( |
| 218 | 'id' => 'wizard-backup-codes', |
| 219 | 'type' => 'checkbox', |
| 220 | 'option_name' => self::NAME_PREFIX . '[' . Backup_Codes::get_settings_name() . ']', |
| 221 | 'default' => $backup_enabled ? 'yes' : '', |
| 222 | 'text' => '<strong>' . \esc_html__( 'Backup codes', 'wp-2fa' ) . '</strong>', |
| 223 | 'not_bool' => true, |
| 224 | 'not_id' => true, |
| 225 | 'value' => 'yes', |
| 226 | ) |
| 227 | ); |
| 228 | ?> |
| 229 | <p class="wizard-method-desc"> |
| 230 | <?php |
| 231 | printf( |
| 232 | '%1$s <a href="%2$s" target="_blank" rel="noopener noreferrer">%3$s</a>', |
| 233 | \esc_html__( 'Backup codes allow users to log in to WordPress should they find themselves unable to log in via the primary 2FA method. Backup codes are enabled by default and are generated during the 2FA configuration process. Each backup code can be used only once. Once the initial list is exhausted, more backup codes can be generated through the user\'s WordPress profile page -', 'wp-2fa' ), |
| 234 | \esc_url( 'https://melapress.com/support/kb/wp-2fa-what-are-2fa-backup-codes/?&utm_source=plugin&utm_medium=wp2fa&utm_campaign=backup_codes_info' ), |
| 235 | \esc_html__( 'More information', 'wp-2fa' ) |
| 236 | ); |
| 237 | ?> |
| 238 | </p> |
| 239 | </div> |
| 240 | |
| 241 | |
| 242 | <?php |
| 243 | /** |
| 244 | * Allow extensions to register additional backup methods. |
| 245 | * |
| 246 | * @param bool $wizard True - wizard context. |
| 247 | * @param string $data_role Data-role attribute. |
| 248 | * @param string|null $role Role name. |
| 249 | * |
| 250 | * @since 2.0.0 |
| 251 | */ |
| 252 | \do_action( WP_2FA_PREFIX . 'after_secondary_methods_toggles', null ); |
| 253 | |
| 254 | // @free:start |
| 255 | ?> |
| 256 | <div class="wizard-upgrade-notice"> |
| 257 | <span> |
| 258 | <strong><?php \esc_html_e( 'Send backup codes instantly via email', 'wp-2fa' ); ?></strong><br> |
| 259 | <?php \esc_html_e( 'Let users receive a one-time backup code by email in seconds — plus more premium 2FA methods with WP 2FA Premium.', 'wp-2fa' ); ?> |
| 260 | </span> |
| 261 | <a href="https://melapress.com/wordpress-2fa/pricing/?&utm_source=plugin&utm_medium=wp2fa&utm_campaign=upgrade_now" target="_blank" class="button button-secondary"><?php \esc_html_e( 'Upgrade Now', 'wp-2fa' ); ?></a> |
| 262 | </div> |
| 263 | <?php |
| 264 | // @free:end |
| 265 | } |
| 266 | |
| 267 | /* |
| 268 | ============================================================== |
| 269 | * STEP 3 – 2FA Policy (Enforcement) |
| 270 | * ============================================================== |
| 271 | */ |
| 272 | |
| 273 | /** |
| 274 | * Render the enforcement policy step. |
| 275 | * |
| 276 | * @return void |
| 277 | */ |
| 278 | public static function step_enforcement_policy() { |
| 279 | $enforcement_policy = WP2FA::get_wp2fa_setting( 'enforcement-policy' ); |
| 280 | $enforced_users = array_filter( (array) WP2FA::get_wp2fa_setting( 'enforced_users' ) ); |
| 281 | $enforced_roles = array_filter( (array) WP2FA::get_wp2fa_setting( 'enforced_roles' ) ); |
| 282 | $all_roles = WP_Helper::get_roles_wp(); |
| 283 | |
| 284 | $enforced_users_items = array_map( |
| 285 | function ( $user ) { |
| 286 | return array( |
| 287 | 'id' => $user, |
| 288 | 'text' => $user, |
| 289 | ); |
| 290 | }, |
| 291 | $enforced_users |
| 292 | ); |
| 293 | |
| 294 | $enforced_roles_items = array_map( |
| 295 | function ( $role ) use ( $all_roles ) { |
| 296 | return array( |
| 297 | 'id' => $role, |
| 298 | 'text' => isset( $all_roles[ $role ] ) ? $all_roles[ $role ] : ucfirst( $role ), |
| 299 | ); |
| 300 | }, |
| 301 | $enforced_roles |
| 302 | ); |
| 303 | |
| 304 | // Build radio options – add multisite-specific choices when applicable. |
| 305 | $radio_options = array( |
| 306 | 'all-users' => \esc_html__( 'All users', 'wp-2fa' ), |
| 307 | ); |
| 308 | |
| 309 | $toggle_map = array( |
| 310 | 'all-users' => '', |
| 311 | ); |
| 312 | |
| 313 | if ( WP_Helper::is_multisite() ) { |
| 314 | $radio_options['superadmins-only'] = \esc_html__( 'Only super admins', 'wp-2fa' ); |
| 315 | $radio_options['superadmins-siteadmins-only'] = \esc_html__( 'Only super admins and site admins', 'wp-2fa' ); |
| 316 | $toggle_map['superadmins-only'] = ''; |
| 317 | $toggle_map['superadmins-siteadmins-only'] = ''; |
| 318 | } |
| 319 | |
| 320 | $radio_options['certain-roles-only'] = \esc_html__( 'Only for specific users and roles', 'wp-2fa' ); |
| 321 | $toggle_map['certain-roles-only'] = '#wizard-enforcement-specific-inputs'; |
| 322 | |
| 323 | if ( WP_Helper::is_multisite() ) { |
| 324 | $radio_options['enforce-on-multisite'] = \esc_html__( 'These sub-sites', 'wp-2fa' ); |
| 325 | $toggle_map['enforce-on-multisite'] = '#wizard-enforcement-sites-inputs'; |
| 326 | } |
| 327 | |
| 328 | $radio_options['do-not-enforce'] = \esc_html__( 'Do not enforce on any users', 'wp-2fa' ); |
| 329 | $toggle_map['do-not-enforce'] = ''; |
| 330 | |
| 331 | ?> |
| 332 | <h3><?php \esc_html_e( 'Do you want to enforce 2FA for some, or all users?', 'wp-2fa' ); ?></h3> |
| 333 | <p class="description"> |
| 334 | <?php \esc_html_e( 'When 2FA is enforced, users will be prompted to configure it the next time they log in. Users are given a grace period to complete the setup before 2FA becomes mandatory. You can configure the grace period and exclude specific users or roles later from the plugin\'s settings.', 'wp-2fa' ); ?> |
| 335 | <a href="https://melapress.com/support/kb/wp-2fa-configure-2fa-policies-enforce/?&utm_source=plugin&utm_medium=wp2fa&utm_campaign=enforcement_policy_help" target="_blank" rel="noopener"><?php \esc_html_e( 'Learn more.', 'wp-2fa' ); ?></a> |
| 336 | </p> |
| 337 | |
| 338 | <div class="form-group settings-row"> |
| 339 | <?php |
| 340 | Settings_Builder::build_option( |
| 341 | array( |
| 342 | 'id' => 'wizard-enforcement-policy', |
| 343 | 'type' => 'radio', |
| 344 | 'option_name' => self::NAME_PREFIX . '[enforcement-policy]', |
| 345 | 'default' => $enforcement_policy, |
| 346 | 'options' => $radio_options, |
| 347 | 'toggle' => $toggle_map, |
| 348 | ) |
| 349 | ); |
| 350 | ?> |
| 351 | </div> |
| 352 | |
| 353 | <!-- Specific users / roles selection --> |
| 354 | <div id="wizard-enforcement-specific-inputs" style="display:none; padding-bottom: 20px;"> |
| 355 | <div class="form-group settings-row" style="margin-top:12px;"> |
| 356 | <?php |
| 357 | Settings_Builder::build_option( |
| 358 | array( |
| 359 | 'text' => \esc_html__( 'Users', 'wp-2fa' ), |
| 360 | 'id' => 'wizard-enforced-users-label', |
| 361 | 'type' => 'settings-label', |
| 362 | ) |
| 363 | ); |
| 364 | |
| 365 | Settings_Builder::build_option( |
| 366 | array( |
| 367 | 'id' => 'wizard-enforced-users', |
| 368 | 'type' => 'multi-select-ajax', |
| 369 | 'option_name' => self::NAME_PREFIX . '[enforced_users]', |
| 370 | 'default' => implode( ',', $enforced_users ), |
| 371 | 'placeholder' => \esc_attr__( 'Type to search users…', 'wp-2fa' ), |
| 372 | 'items' => $enforced_users_items, |
| 373 | 'data_attrs' => array( |
| 374 | 'search-type' => 'users', |
| 375 | 'min-chars' => '2', |
| 376 | ), |
| 377 | ) |
| 378 | ); |
| 379 | ?> |
| 380 | </div> |
| 381 | |
| 382 | <div class="form-group settings-row"> |
| 383 | <?php |
| 384 | Settings_Builder::build_option( |
| 385 | array( |
| 386 | 'text' => \esc_html__( 'Roles', 'wp-2fa' ), |
| 387 | 'id' => 'wizard-enforced-roles-label', |
| 388 | 'type' => 'settings-label', |
| 389 | ) |
| 390 | ); |
| 391 | |
| 392 | Settings_Builder::build_option( |
| 393 | array( |
| 394 | 'id' => 'wizard-enforced-roles', |
| 395 | 'type' => 'multi-select-ajax', |
| 396 | 'option_name' => self::NAME_PREFIX . '[enforced_roles]', |
| 397 | 'default' => implode( ',', $enforced_roles ), |
| 398 | 'placeholder' => \esc_attr__( 'Type to search roles…', 'wp-2fa' ), |
| 399 | 'items' => $enforced_roles_items, |
| 400 | 'data_attrs' => array( |
| 401 | 'search-type' => 'roles', |
| 402 | 'min-chars' => '2', |
| 403 | ), |
| 404 | ) |
| 405 | ); |
| 406 | ?> |
| 407 | </div> |
| 408 | </div> |
| 409 | |
| 410 | <?php if ( WP_Helper::is_multisite() ) : ?> |
| 411 | <!-- Sub-sites selection --> |
| 412 | <div id="wizard-enforcement-sites-inputs" style="display:none; padding-bottom: 20px;"> |
| 413 | <div class="form-group settings-row" style="margin-top:12px;"> |
| 414 | <?php |
| 415 | $included_sites = array_filter( (array) WP2FA::get_wp2fa_setting( 'included_sites' ) ); |
| 416 | $included_sites_items = array(); |
| 417 | foreach ( WP_Helper::get_multi_sites() as $site ) { |
| 418 | if ( in_array( $site->blog_id, $included_sites, true ) || in_array( (string) $site->blog_id, $included_sites, true ) ) { |
| 419 | $included_sites_items[] = array( |
| 420 | 'id' => $site->blog_id, |
| 421 | 'text' => $site->blogname, |
| 422 | ); |
| 423 | } |
| 424 | } |
| 425 | |
| 426 | Settings_Builder::build_option( |
| 427 | array( |
| 428 | 'text' => \esc_html__( 'Sites', 'wp-2fa' ), |
| 429 | 'id' => 'wizard-enforced-sites-label', |
| 430 | 'type' => 'settings-label', |
| 431 | ) |
| 432 | ); |
| 433 | |
| 434 | Settings_Builder::build_option( |
| 435 | array( |
| 436 | 'id' => 'wizard-enforced-sites', |
| 437 | 'type' => 'multi-select-ajax', |
| 438 | 'option_name' => self::NAME_PREFIX . '[included_sites]', |
| 439 | 'default' => implode( ',', $included_sites ), |
| 440 | 'placeholder' => \esc_attr__( 'Type to search sites…', 'wp-2fa' ), |
| 441 | 'items' => $included_sites_items, |
| 442 | 'data_attrs' => array( |
| 443 | 'search-type' => 'sites', |
| 444 | 'min-chars' => '2', |
| 445 | ), |
| 446 | ) |
| 447 | ); |
| 448 | ?> |
| 449 | </div> |
| 450 | </div> |
| 451 | <?php endif; ?> |
| 452 | <?php |
| 453 | } |
| 454 | |
| 455 | /* |
| 456 | ============================================================== |
| 457 | * STEP 4 – Exclude Users |
| 458 | * ============================================================== |
| 459 | */ |
| 460 | |
| 461 | /** |
| 462 | * Render the exclusions step. |
| 463 | * |
| 464 | * @return void |
| 465 | */ |
| 466 | public static function step_exclude_users() { |
| 467 | $excluded_users = array_filter( (array) WP2FA::get_wp2fa_setting( 'excluded_users' ) ); |
| 468 | $excluded_roles = array_filter( (array) WP2FA::get_wp2fa_setting( 'excluded_roles' ) ); |
| 469 | $all_roles = WP_Helper::get_roles_wp(); |
| 470 | |
| 471 | $excluded_users_items = array_map( |
| 472 | function ( $user ) { |
| 473 | return array( |
| 474 | 'id' => $user, |
| 475 | 'text' => $user, |
| 476 | ); |
| 477 | }, |
| 478 | $excluded_users |
| 479 | ); |
| 480 | |
| 481 | $excluded_roles_items = array_map( |
| 482 | function ( $role ) use ( $all_roles ) { |
| 483 | return array( |
| 484 | 'id' => $role, |
| 485 | 'text' => isset( $all_roles[ $role ] ) ? $all_roles[ $role ] : ucfirst( $role ), |
| 486 | ); |
| 487 | }, |
| 488 | $excluded_roles |
| 489 | ); |
| 490 | ?> |
| 491 | <h3><?php \esc_html_e( 'Do you want to exclude any users or roles from 2FA?', 'wp-2fa' ); ?></h3> |
| 492 | <p class="description"> |
| 493 | <?php \esc_html_e( 'If you are enforcing 2FA on all users but for some reason you would like to exclude individual user(s) or users with a specific role, you can exclude them below:', 'wp-2fa' ); ?> |
| 494 | </p> |
| 495 | |
| 496 | <div class="form-group settings-row"> |
| 497 | <?php |
| 498 | Settings_Builder::build_option( |
| 499 | array( |
| 500 | 'text' => \esc_html__( 'Exclude the following users', 'wp-2fa' ), |
| 501 | 'id' => 'wizard-excluded-users-label', |
| 502 | 'type' => 'settings-label', |
| 503 | ) |
| 504 | ); |
| 505 | |
| 506 | Settings_Builder::build_option( |
| 507 | array( |
| 508 | 'id' => 'wizard-excluded-users', |
| 509 | 'type' => 'multi-select-ajax', |
| 510 | 'option_name' => self::NAME_PREFIX . '[excluded_users]', |
| 511 | 'default' => implode( ',', $excluded_users ), |
| 512 | 'placeholder' => \esc_attr__( 'Add users', 'wp-2fa' ), |
| 513 | 'items' => $excluded_users_items, |
| 514 | 'data_attrs' => array( |
| 515 | 'search-type' => 'users', |
| 516 | 'min-chars' => '2', |
| 517 | ), |
| 518 | ) |
| 519 | ); |
| 520 | ?> |
| 521 | </div> |
| 522 | |
| 523 | <div class="form-group settings-row"> |
| 524 | <?php |
| 525 | Settings_Builder::build_option( |
| 526 | array( |
| 527 | 'text' => \esc_html__( 'Exclude the following roles', 'wp-2fa' ), |
| 528 | 'id' => 'wizard-excluded-roles-label', |
| 529 | 'type' => 'settings-label', |
| 530 | ) |
| 531 | ); |
| 532 | |
| 533 | Settings_Builder::build_option( |
| 534 | array( |
| 535 | 'id' => 'wizard-excluded-roles', |
| 536 | 'type' => 'multi-select-ajax', |
| 537 | 'option_name' => self::NAME_PREFIX . '[excluded_roles]', |
| 538 | 'default' => implode( ',', $excluded_roles ), |
| 539 | 'placeholder' => \esc_attr__( 'Add roles', 'wp-2fa' ), |
| 540 | 'items' => $excluded_roles_items, |
| 541 | 'data_attrs' => array( |
| 542 | 'search-type' => 'roles', |
| 543 | 'min-chars' => '2', |
| 544 | ), |
| 545 | ) |
| 546 | ); |
| 547 | ?> |
| 548 | </div> |
| 549 | <?php |
| 550 | } |
| 551 | |
| 552 | /* |
| 553 | ============================================================== |
| 554 | * STEP 5 – Exclude Sites (Multisite only) |
| 555 | * ============================================================== |
| 556 | */ |
| 557 | |
| 558 | /** |
| 559 | * Render the exclude sites step (multisite only). |
| 560 | * |
| 561 | * @return void |
| 562 | */ |
| 563 | public static function step_exclude_sites() { |
| 564 | if ( ! WP_Helper::is_multisite() ) { |
| 565 | return; |
| 566 | } |
| 567 | |
| 568 | $excluded_sites = array_filter( (array) WP2FA::get_wp2fa_setting( 'excluded_sites' ) ); |
| 569 | $excluded_sites_items = array(); |
| 570 | foreach ( WP_Helper::get_multi_sites() as $site ) { |
| 571 | if ( in_array( $site->blog_id, $excluded_sites, true ) || in_array( (string) $site->blog_id, $excluded_sites, true ) ) { |
| 572 | $excluded_sites_items[] = array( |
| 573 | 'id' => $site->blog_id, |
| 574 | 'text' => $site->blogname, |
| 575 | ); |
| 576 | } |
| 577 | } |
| 578 | ?> |
| 579 | <h3><?php \esc_html_e( 'Do you want to exclude all the users of a site from 2FA?', 'wp-2fa' ); ?></h3> |
| 580 | <p class="description"> |
| 581 | <?php \esc_html_e( 'If you are enforcing 2FA on all users but for some reason you do not want to enforce it on a specific sub site, specify the sub site name below:', 'wp-2fa' ); ?> |
| 582 | </p> |
| 583 | |
| 584 | <div class="form-group settings-row" style="margin-top:12px;"> |
| 585 | <?php |
| 586 | Settings_Builder::build_option( |
| 587 | array( |
| 588 | 'text' => \esc_html__( 'Exclude the following sites', 'wp-2fa' ), |
| 589 | 'id' => 'wizard-excluded-sites-label', |
| 590 | 'type' => 'settings-label', |
| 591 | ) |
| 592 | ); |
| 593 | |
| 594 | Settings_Builder::build_option( |
| 595 | array( |
| 596 | 'id' => 'wizard-excluded-sites', |
| 597 | 'type' => 'multi-select-ajax', |
| 598 | 'option_name' => self::NAME_PREFIX . '[excluded_sites]', |
| 599 | 'default' => implode( ',', $excluded_sites ), |
| 600 | 'placeholder' => \esc_attr__( 'Type to search sites…', 'wp-2fa' ), |
| 601 | 'items' => $excluded_sites_items, |
| 602 | 'data_attrs' => array( |
| 603 | 'search-type' => 'sites', |
| 604 | 'min-chars' => '2', |
| 605 | ), |
| 606 | ) |
| 607 | ); |
| 608 | ?> |
| 609 | </div> |
| 610 | <?php |
| 611 | } |
| 612 | |
| 613 | /* |
| 614 | ============================================================== |
| 615 | * STEP 6 – Grace Period |
| 616 | * ============================================================== |
| 617 | */ |
| 618 | |
| 619 | /** |
| 620 | * Render the grace period step. |
| 621 | * |
| 622 | * @return void |
| 623 | */ |
| 624 | public static function step_grace_period() { |
| 625 | $grace_policy = WP2FA::get_wp2fa_setting( 'grace-policy', true ); |
| 626 | $grace_period = (int) WP2FA::get_wp2fa_setting( 'grace-period', true ); |
| 627 | $grace_period_denominator = WP2FA::get_wp2fa_setting( 'grace-period-denominator', true ); |
| 628 | $grace_after_expire_action = WP2FA::get_wp2fa_setting( 'grace-policy-after-expire-action', true ); |
| 629 | |
| 630 | if ( ! $grace_policy ) { |
| 631 | $grace_policy = 'use-grace-period'; |
| 632 | } |
| 633 | if ( ! $grace_period ) { |
| 634 | $grace_period = 3; |
| 635 | } |
| 636 | if ( ! $grace_period_denominator ) { |
| 637 | $grace_period_denominator = 'days'; |
| 638 | } |
| 639 | if ( ! $grace_after_expire_action ) { |
| 640 | $grace_after_expire_action = 'configure-right-away'; |
| 641 | } |
| 642 | |
| 643 | $user = \wp_get_current_user(); |
| 644 | $last_user_to_update_settings = $user->ID; |
| 645 | |
| 646 | $grace_notification = Settings_Utils::get_setting_role( null, Grace_Period_Notifications::GRACE_PERIOD_NOTIFICATION_SETTINGS_NAME, true ); |
| 647 | if ( ! $grace_notification ) { |
| 648 | $grace_notification = 'after-login-notification'; |
| 649 | } |
| 650 | ?> |
| 651 | <h3><?php \esc_html_e( 'How long should the grace period for your users be?', 'wp-2fa' ); ?></h3> |
| 652 | <p class="description"> |
| 653 | <?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.', 'wp-2fa' ); ?> |
| 654 | </p> |
| 655 | |
| 656 | <div class="settings-card"> |
| 657 | <?php |
| 658 | Settings_Builder::build_option( |
| 659 | array( |
| 660 | 'title' => \esc_html__( 'Choose which method you\'d like to use:', 'wp-2fa' ), |
| 661 | 'id' => 'wizard-grace-method-title', |
| 662 | 'type' => 'section-sub-title', |
| 663 | ) |
| 664 | ); |
| 665 | ?> |
| 666 | |
| 667 | <div class="form-group settings-row"> |
| 668 | <div class="settings-control"> |
| 669 | <label class="radio-option"> |
| 670 | <input type="radio" |
| 671 | name="<?php echo \esc_attr( self::NAME_PREFIX ); ?>[grace-policy]" |
| 672 | id="wizard-no-grace-period" |
| 673 | value="no-grace-period" |
| 674 | <?php \checked( $grace_policy, 'no-grace-period' ); ?>> |
| 675 | <span><?php \esc_html_e( 'Users have to configure 2FA straight away.', 'wp-2fa' ); ?></span> |
| 676 | </label> |
| 677 | <label class="radio-option"> |
| 678 | <input type="radio" |
| 679 | name="<?php echo \esc_attr( self::NAME_PREFIX ); ?>[grace-policy]" |
| 680 | id="wizard-use-grace-period" |
| 681 | value="use-grace-period" |
| 682 | <?php \checked( $grace_policy, 'use-grace-period' ); ?> |
| 683 | data-toggle-target="#wizard-grace-period-sub-settings"> |
| 684 | <span><?php \esc_html_e( 'Give users a grace period to configure 2FA', 'wp-2fa' ); ?></span> |
| 685 | </label> |
| 686 | </div> |
| 687 | </div> |
| 688 | |
| 689 | <!-- Grace period sub-settings --> |
| 690 | <div id="wizard-grace-period-sub-settings" class="grace-period-sub-settings"<?php echo ( 'use-grace-period' !== $grace_policy ) ? ' style="display:none;"' : ''; ?>> |
| 691 | <div class="form-group settings-row" style="margin-left: 35px;"> |
| 692 | <div class="settings-control inline-controls"> |
| 693 | <?php |
| 694 | Settings_Builder::build_option( |
| 695 | array( |
| 696 | 'id' => 'wizard-grace-period', |
| 697 | 'type' => 'number', |
| 698 | 'min' => 1, |
| 699 | 'max' => 90, |
| 700 | 'class' => 'small-text', |
| 701 | 'option_name' => self::NAME_PREFIX . '[grace-period]', |
| 702 | 'default' => $grace_period, |
| 703 | ) |
| 704 | ); |
| 705 | Settings_Builder::build_option( |
| 706 | array( |
| 707 | 'id' => 'wizard-grace-period-denominator', |
| 708 | 'type' => 'select', |
| 709 | 'option_name' => self::NAME_PREFIX . '[grace-period-denominator]', |
| 710 | 'default' => $grace_period_denominator, |
| 711 | 'options' => array( |
| 712 | 'hours' => \esc_html__( 'Hours', 'wp-2fa' ), |
| 713 | 'days' => \esc_html__( 'Days', 'wp-2fa' ), |
| 714 | ), |
| 715 | ) |
| 716 | ); |
| 717 | ?> |
| 718 | </div> |
| 719 | </div> |
| 720 | |
| 721 | <!-- What happens after grace period expires --> |
| 722 | <div style="margin-left: 35px;"> |
| 723 | <?php |
| 724 | Settings_Builder::build_option( |
| 725 | array( |
| 726 | 'title' => \esc_html__( 'Users who missed the grace period', 'wp-2fa' ), |
| 727 | 'id' => 'wizard-grace-expire-label', |
| 728 | 'type' => 'section-sub-title', |
| 729 | ) |
| 730 | ); |
| 731 | ?> |
| 732 | <div class="form-group settings-row"> |
| 733 | <?php |
| 734 | Settings_Builder::build_option( |
| 735 | array( |
| 736 | 'id' => 'wizard-grace-policy-after-expire-action', |
| 737 | 'type' => 'radio', |
| 738 | 'option_name' => self::NAME_PREFIX . '[grace-policy-after-expire-action]', |
| 739 | 'default' => $grace_after_expire_action, |
| 740 | 'options' => array( |
| 741 | 'configure-right-away' => \esc_html__( 'Disable user access to the dashboard / user page once they log in, until they configure 2FA', 'wp-2fa' ), |
| 742 | 'manual-block' => \esc_html__( 'Block the user (administrators have to manually unblock them)', 'wp-2fa' ), |
| 743 | ), |
| 744 | ) |
| 745 | ); |
| 746 | ?> |
| 747 | </div> |
| 748 | </div> |
| 749 | |
| 750 | <!-- Notification settings --> |
| 751 | <div style="margin-left: 35px;"> |
| 752 | <?php |
| 753 | Settings_Builder::build_option( |
| 754 | array( |
| 755 | 'title' => \esc_html__( 'Notification settings', 'wp-2fa' ), |
| 756 | 'id' => 'wizard-grace-notification-label', |
| 757 | 'type' => 'section-sub-title', |
| 758 | ) |
| 759 | ); |
| 760 | ?> |
| 761 | <div class="form-group settings-row"> |
| 762 | <?php |
| 763 | Settings_Builder::build_option( |
| 764 | array( |
| 765 | 'id' => 'wizard-grace-notification', |
| 766 | 'type' => 'radio', |
| 767 | 'option_name' => self::NAME_PREFIX . '[' . Grace_Period_Notifications::GRACE_PERIOD_NOTIFICATION_SETTINGS_NAME . ']', |
| 768 | 'default' => $grace_notification, |
| 769 | 'options' => array( |
| 770 | 'dashboard-notification' => \esc_html__( 'Show an admin notice in the dashboard', 'wp-2fa' ), |
| 771 | 'after-login-notification' => \esc_html__( 'Show a notification on a page on its own after the user authenticates and before accessing the dashboard', 'wp-2fa' ), |
| 772 | ), |
| 773 | ) |
| 774 | ); |
| 775 | ?> |
| 776 | </div> |
| 777 | </div> |
| 778 | </div> |
| 779 | </div> |
| 780 | |
| 781 | <input type="hidden" name="<?php echo \esc_attr( self::NAME_PREFIX ); ?>[2fa_settings_last_updated_by]" value="<?php echo \esc_attr( $last_user_to_update_settings ); ?>"> |
| 782 | <?php |
| 783 | } |
| 784 | } |
| 785 | } |
| 786 |