diff --git a/changelog.txt b/changelog.txt index 1e0e2bf..67c38b2 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,45 @@ == Changelog == += 1.6.7 = + +_Release date: 2026-09-17_ + +**Fixed** + +* The forced-setup wizard felt like a broken redirect loop: the wizard redirect bounced users to the profile with no explanation (it now carries a flag that renders a clear "activate at least one verification method, then save" warning), and saving with an expired form nonce silently did nothing (it now raises a visible "form session expired" error so users know to try again). + +**Compatibility** + +* WordPress: 5.6 – 7.1 +* PHP: 8.0 – 8.5 + +**Tests** + +* PHP Coding Standards: PHP_CodeSniffer 3.13.6 / WPCS 3.4.1 — 0 errors +* PHPStan: level 9 — 0 errors +* PHPCompatibility: 8.0–8.5 — 0 issues +* PHPUnit: 9.6.36 — 98 tests, 197 assertions + += 1.6.6 = + +_Release date: 2026-09-17_ + +**Added** + +* Forced-enrollment warning on the profile 2FA section: when a user's role enforces 2FA but they have no verification method configured yet, the 2FA section of their profile (wp-admin and the frontend shortcode) opens with a warning notice asking them to activate at least one method. While a grace period is active, the notice appends the remaining days. + +**Compatibility** + +* WordPress: 5.6 – 7.1 +* PHP: 8.0 – 8.5 + +**Tests** + +* PHP Coding Standards: PHP_CodeSniffer 3.13.6 / WPCS 3.4.1 — 0 errors +* PHPStan: level 9 — 0 errors +* PHPCompatibility: 8.0–8.5 — 0 issues +* PHPUnit: 9.6.36 — 93 tests, 189 assertions + = 1.6.5 = _Release date: 2026-09-17_ diff --git a/includes/user/class-grace-period.php b/includes/user/class-grace-period.php index b074a79..31399d6 100644 --- a/includes/user/class-grace-period.php +++ b/includes/user/class-grace-period.php @@ -41,6 +41,7 @@ class Grace_Period { public function register_hooks(): void { add_action( 'admin_init', array( $this, 'maybe_redirect_to_setup_wizard' ) ); add_action( 'robotstxt_2fa_method_enabled', array( $this, 'clear_pending_setup' ), 10, 2 ); + add_action( 'admin_notices', array( $this, 'maybe_show_setup_required_notice' ) ); } /** @@ -167,10 +168,45 @@ class Grace_Period { return; } - wp_safe_redirect( admin_url( 'profile.php#robotstxt-2fa-settings' ) ); + // The query flag lets the profile show WHY the user was redirected, + // so the mandatory setup does not feel like a silent loop. + $profile_url = add_query_arg( 'robotstxt-2fa-setup-required', '1', admin_url( 'profile.php' ) ); + + wp_safe_redirect( $profile_url . '#robotstxt-2fa-settings' ); exit; } + /** + * Explain the setup wizard redirect on the profile screen. + * + * Rendered after {@see self::maybe_redirect_to_setup_wizard()} bounced the + * user back to their profile. Without it, users land on a regular profile + * page with no hint that 2FA enrollment is mandatory before they can + * continue to the dashboard — which reads as a broken redirect loop. + * + * @since 1.6.7 + * + * @return void + */ + public function maybe_show_setup_required_notice(): void { + if ( ! $this->is_pending_setup() ) { + return; + } + + // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Display-only flag; no state change. + if ( ! isset( $_GET['robotstxt-2fa-setup-required'] ) ) { + return; + } + ?> +
+ + +
++ + + + + +
+