@@ -28,6 +28,14 @@ class Two_Factor_Backup_Codes extends Two_Factor_Provider {
2828 */
2929 const NUMBER_OF_CODES = 10 ;
3030
31+ /**
32+ * The default number of remaining codes at or below which the user is
33+ * warned to regenerate, before they run out entirely.
34+ *
35+ * @type int
36+ */
37+ const LOW_CODES_THRESHOLD = 2 ;
38+
3139 /**
3240 * Class constructor.
3341 *
@@ -97,7 +105,7 @@ public function register_rest_routes() {
97105 }
98106
99107 /**
100- * Displays an admin notice when backup codes have run out.
108+ * Displays an admin notice when backup codes have run out, or are running low .
101109 *
102110 * @since 0.1-dev
103111 *
@@ -111,28 +119,70 @@ public function admin_notices() {
111119 return ;
112120 }
113121
114- // Return if we are not out of codes.
115- if ( $ this ->is_available_for_user ( $ user ) ) {
122+ $ count = self ::codes_remaining_for_user ( $ user );
123+ $ regenerate_url = esc_url ( get_edit_user_link ( $ user ->ID ) . '#two-factor-backup-codes ' );
124+
125+ // Out of codes: show an error and bail.
126+ if ( 0 === $ count ) {
127+ ?>
128+ <div class="error">
129+ <p>
130+ <span>
131+ <?php
132+ echo wp_kses (
133+ sprintf (
134+ /* translators: %s: URL for code regeneration */
135+ __ ( 'Two-Factor: You are out of recovery codes and need to <a href="%s">regenerate!</a> ' , 'two-factor ' ),
136+ $ regenerate_url
137+ ),
138+ array ( 'a ' => array ( 'href ' => true ) )
139+ );
140+ ?>
141+ </span>
142+ </p>
143+ </div>
144+ <?php
116145 return ;
117146 }
118- ?>
119- <div class="error">
120- <p>
121- <span>
122- <?php
123- echo wp_kses (
124- sprintf (
125- /* translators: %s: URL for code regeneration */
126- __ ( 'Two-Factor: You are out of recovery codes and need to <a href="%s">regenerate!</a> ' , 'two-factor ' ),
127- esc_url ( get_edit_user_link ( $ user ->ID ) . '#two-factor-backup-codes ' )
128- ),
129- array ( 'a ' => array ( 'href ' => true ) )
130- );
131- ?>
132- </span>
133- </p>
134- </div>
135- <?php
147+
148+ /**
149+ * Filters the number of remaining recovery codes at or below which the
150+ * user is warned to regenerate, before they run out entirely.
151+ *
152+ * @since 0.17.0
153+ *
154+ * @param int $threshold Number of remaining codes that triggers the warning. Default 2.
155+ * @param WP_User $user User object.
156+ */
157+ $ threshold = (int ) apply_filters ( 'two_factor_backup_codes_low_threshold ' , self ::LOW_CODES_THRESHOLD , $ user );
158+
159+ // Running low: warn the user before they hit zero.
160+ if ( $ count <= $ threshold ) {
161+ ?>
162+ <div class="notice notice-warning">
163+ <p>
164+ <span>
165+ <?php
166+ echo wp_kses (
167+ sprintf (
168+ /* translators: 1: number of recovery codes remaining, 2: URL for code regeneration */
169+ _n (
170+ 'Two-Factor: You only have %1$s recovery code left. <a href="%2$s">Regenerate your codes</a> now before you run out. ' ,
171+ 'Two-Factor: You only have %1$s recovery codes left. <a href="%2$s">Regenerate your codes</a> now before you run out. ' ,
172+ $ count ,
173+ 'two-factor '
174+ ),
175+ number_format_i18n ( $ count ),
176+ $ regenerate_url
177+ ),
178+ array ( 'a ' => array ( 'href ' => true ) )
179+ );
180+ ?>
181+ </span>
182+ </p>
183+ </div>
184+ <?php
185+ }
136186 }
137187
138188 /**
0 commit comments