diff --git a/class-two-factor-core.php b/class-two-factor-core.php index 7311339a..7b57b868 100644 --- a/class-two-factor-core.php +++ b/class-two-factor-core.php @@ -85,6 +85,13 @@ class Two_Factor_Core { */ private static $password_auth_tokens = array(); + /** + * Keep track of any errors related to setting updates. + * + * @var array + */ + private static $profile_errors = array(); + /** * Set up filters and actions. * @@ -114,6 +121,7 @@ public static function add_hooks( $compat ) { // 2. Render two-factor UI after WP core has validated username/password during `wp_signon()`. add_action( 'wp_login', array( __CLASS__, 'wp_login' ), PHP_INT_MAX, 2 ); + add_action( 'user_profile_update_errors', array( __CLASS__, 'action_user_profile_update_errors' ) ); /** * Keep track of all the user sessions for which we need to invalidate the @@ -296,7 +304,7 @@ private static function get_providers_classes( $providers ) { * * @since 0.2.0 * - * @return array + * @return Two_Factor_Provider[] */ public static function get_providers() { $providers = self::get_default_providers(); @@ -338,7 +346,8 @@ public static function get_providers() { * @see Two_Factor_Core::get_available_providers_for_user() * * @param WP_User|int|null $user User ID. - * @return array List of provider instances indexed by provider key. + * + * @return Two_Factor_Provider[] List of provider instances indexed by provider key. */ public static function get_supported_providers_for_user( $user = null ) { $user = self::fetch_user( $user ); @@ -403,6 +412,36 @@ public static function add_settings_action_link( $links ) { return $links; } + /** + * Register an error associated with the current request. + * + * @param WP_Error $error Error instance. + + * @return void + */ + private static function add_error( WP_Error $error ) { + self::$profile_errors[ $error->get_error_code() ] = $error; + } + + /** + * Attach Two-Factor profile errors to WordPress core profile update errors. + * + * @since NEXT + * + * @param WP_Error $errors WP_Error object passed by core. + * + * @return void + */ + public static function action_user_profile_update_errors( WP_Error $errors ) { + foreach ( self::$profile_errors as $profile_error ) { + foreach ( $profile_error->get_error_codes() as $code ) { + foreach ( $profile_error->get_error_messages( $code ) as $message ) { + $errors->add( $code, $message ); + } + } + } + } + /** * Check if the debug mode is enabled. * @@ -599,7 +638,8 @@ public static function fetch_user( $user = null ) { * @see Two_Factor_Core::get_available_providers_for_user() * * @param int|WP_User $user Optional. User ID, or WP_User object of the the user. Defaults to current user. - * @return array + * + * @return string[] List of keys of enabled providers for the user. */ public static function get_enabled_providers_for_user( $user = null ) { $user = self::fetch_user( $user ); @@ -635,7 +675,7 @@ public static function get_enabled_providers_for_user( $user = null ) { * @see Two_Factor_Core::get_enabled_providers_for_user() * * @param int|WP_User $user Optional. User ID, or WP_User object of the the user. Defaults to current user. - * @return array|WP_Error List of provider instances, or a WP_Error if all configured providers are unavailable. + * @return Two_Factor_Provider[]|WP_Error List of provider instances, or a WP_Error if all configured providers are unavailable. */ public static function get_available_providers_for_user( $user = null ) { $user = self::fetch_user( $user ); @@ -2044,8 +2084,6 @@ public static function manage_users_custom_column( $output, $column_name, $user_ * @param WP_User $user WP_User object of the logged-in user. */ public static function user_two_factor_options( $user ) { - $notices = array(); - $providers = self::get_supported_providers_for_user( $user ); wp_enqueue_style( 'user-edit-2fa', plugins_url( 'user-edit.css', __FILE__ ), array(), TWO_FACTOR_VERSION ); @@ -2062,29 +2100,58 @@ public static function user_two_factor_options( $user ) { self::get_user_two_factor_revalidate_url() ); - $notices['warning two-factor-warning-revalidate-session'] = sprintf( - /* translators: %s: URL to revalidate the session */ - __( 'To update your Two-Factor options, you must first revalidate your session. Revalidate now', 'two-factor' ), - esc_url( $url ) + self::add_error( + new WP_Error( + 'two_factor_revalidate_session', + sprintf( + __( 'To update your Two-Factor options, you must first revalidate your session.', 'two-factor' ) . + ' ' . esc_html__( 'Revalidate now', 'two-factor' ) . '', + esc_url( $url ) + ), + array( + 'type' => 'warning', + ) + ) ); } if ( empty( $providers ) ) { - $notices['notice two-factor-notice-no-providers-supported'] = esc_html__( 'No providers are available for your account.', 'two-factor' ); + self::add_error( + new WP_Error( + 'two_factor_no_providers_supported', + __( 'No providers are available for your account.', 'two-factor' ), + array( + 'type' => 'notice', + ) + ) + ); } // Suggest enabling a backup method if only one method is enabled and there are more available. if ( count( $providers ) > 1 && 1 === count( $enabled_providers ) ) { - $notices['warning two-factor-warning-suggest-backup'] = esc_html__( 'To prevent being locked out of your account, consider enabling a backup method like Recovery Codes in case you lose access to your primary authentication method.', 'two-factor' ); + self::add_error( + new WP_Error( + 'two_factor_suggest_backup', + __( 'To prevent being locked out of your account, consider enabling a backup method like Recovery Codes in case you lose access to your primary authentication method.', 'two-factor' ), + array( + 'type' => 'warning', + ) + ) + ); } + + $generic_errors = array_filter( + self::$profile_errors, + static function ( WP_Error $error ) { + $error_data = $error->get_error_data(); + return empty( $error_data['provider'] ); // Where the associated provider is not set. + } + ); + ?>
- $notice ) : ?> -