{"id":300820,"date":"2026-05-01T00:34:09","date_gmt":"2026-05-01T00:34:09","guid":{"rendered":"https:\/\/wordpress.org\/plugins\/super-duper-2fa-login-security\/"},"modified":"2026-05-13T08:16:57","modified_gmt":"2026-05-13T08:16:57","slug":"super-duper-two-factor-login","status":"publish","type":"plugin","link":"https:\/\/en-za.wordpress.org\/plugins\/super-duper-two-factor-login\/","author":15303434,"comment_status":"closed","ping_status":"closed","template":"","meta":{"_crdt_document":"","version":"2.5.13","stable_tag":"2.5.13","tested":"6.9.4","requires":"6.8","requires_php":"8.0","requires_plugins":null,"header_name":"Super Duper Two-Factor Login","header_author":"Super Duper Plugins","header_description":"Two-factor authentication for WordPress \u2013 TOTP & email, backup codes, recovery keys, trusted devices and role-based enforcement. Completely free.","assets_banners_color":"4c99cb","last_updated":"2026-05-13 08:16:57","external_support_url":"","external_repository_url":"","donate_link":"","header_plugin_uri":"https:\/\/wordpress.org\/plugins\/super-duper-two-factor-login\/","header_author_uri":"https:\/\/superduperplugins.ch","rating":0,"author_block_rating":0,"active_installs":0,"downloads":300,"num_ratings":0,"support_threads":0,"support_threads_resolved":0,"author_block_count":0,"sections":["description","installation","faq","changelog"],"tags":{"2.5.11":{"tag":"2.5.11","author":"rogerruckstuhl","date":"2026-05-05 20:42:57"},"2.5.12":{"tag":"2.5.12","author":"rogerruckstuhl","date":"2026-05-11 21:00:35"},"2.5.13":{"tag":"2.5.13","author":"rogerruckstuhl","date":"2026-05-13 08:16:57"},"2.5.5":{"tag":"2.5.5","author":"rogerruckstuhl","date":"2026-05-01 00:33:49"},"2.5.9":{"tag":"2.5.9","author":"rogerruckstuhl","date":"2026-05-05 20:42:57"}},"upgrade_notice":{"2.5.9":"<p>Larger, more readable fonts on the forced setup screen. All translations now 100% complete in all eight supported locales.<\/p>","2.5.8":"<p>Critical fix continued: forced 2FA setup AJAX returned 403 because of nonce-validation issues for unauthenticated users. Now uses token-based authorization on the login screen.<\/p>","2.5.7":"<p>Critical fix: forced 2FA setup on the login screen was non-functional. The &quot;Set up now&quot; button now properly opens the setup flow.<\/p>","2.5.6":"<p>Important fixes: REST API user data is now protected by a strict whitelist (so future SEO\/page-builder plugins that add user fields are automatically covered), with a <code>sdtfa_rest_user_allowed_keys<\/code> filter for legitimate exceptions. Also fixed the &quot;Set up now&quot; button on the admin notice.<\/p>","2.5.5":"<p>Internal compatibility fix that allows the package to pass the WordPress.org SVN pre-commit linter. No functional changes.<\/p>","2.5.4":"<p>Fixes three strings in the en_US translation that accidentally contained German text. English-locale sites will now show correct English wording on the settings page and notices.<\/p>","2.5.3":"<p>i18n cleanup: removed remaining hardcoded German strings from PHP and JavaScript so the plugin can be fully translated through the standard gettext workflow.<\/p>","2.5.2":"<p>Fix: 2FA email codes were silently dropped on hosts that require an explicit &quot;From&quot; header. The setup email now sends reliably and surfaces the real error if delivery still fails.<\/p>","2.5.1":"<p>New &quot;SDTFA&quot; column on the Users list shows actual 2FA status. Removes duplicate columns added by host mu-plugins or other 2FA plugins.<\/p>","2.5.0":"<p>New optional Privacy &amp; Hardening features: hide REST user data, block author archive enumeration, disable password reset for admins\/roles. Plus a small admin UI fix for the datepicker container.<\/p>","2.4.1":"<p>Bugfix: the \u00d7 button on the admin notice now works correctly.<\/p>","2.4.0":"<p>WordPress.org compliance release: new distinctive name, admin notice instead of auto-popup, proper enqueuing of all assets, corrected menu position.<\/p>","2.3.0":"<p>First public release. Install and activate to add two-factor authentication to your WordPress site.<\/p>"},"ratings":[],"assets_icons":{"icon-128x128.png":{"filename":"icon-128x128.png","revision":3520060,"resolution":"128x128","location":"assets","locale":"","width":128,"height":128},"icon-256x256.png":{"filename":"icon-256x256.png","revision":3520060,"resolution":"256x256","location":"assets","locale":"","width":256,"height":256}},"assets_banners":{"banner-1544x500.png":{"filename":"banner-1544x500.png","revision":3520060,"resolution":"1544x500","location":"assets","locale":"","width":1544,"height":500},"banner-772x250.png":{"filename":"banner-772x250.png","revision":3520060,"resolution":"772x250","location":"assets","locale":"","width":772,"height":250}},"assets_blueprints":{},"all_blocks":[],"tagged_versions":["2.5.11","2.5.12","2.5.13","2.5.5","2.5.9"],"block_files":[],"assets_screenshots":{"screenshot-1.jpg":{"filename":"screenshot-1.jpg","revision":3520060,"resolution":"1","location":"assets","locale":"","width":1560,"height":756},"screenshot-10.jpg":{"filename":"screenshot-10.jpg","revision":3520060,"resolution":"10","location":"assets","locale":"","width":1816,"height":1426},"screenshot-11.jpg":{"filename":"screenshot-11.jpg","revision":3520060,"resolution":"11","location":"assets","locale":"","width":1762,"height":1104},"screenshot-12.jpg":{"filename":"screenshot-12.jpg","revision":3520060,"resolution":"12","location":"assets","locale":"","width":2354,"height":1604},"screenshot-13.jpg":{"filename":"screenshot-13.jpg","revision":3520060,"resolution":"13","location":"assets","locale":"","width":1732,"height":576},"screenshot-14.jpg":{"filename":"screenshot-14.jpg","revision":3520060,"resolution":"14","location":"assets","locale":"","width":2460,"height":1354},"screenshot-2.jpg":{"filename":"screenshot-2.jpg","revision":3520060,"resolution":"2","location":"assets","locale":"","width":1292,"height":1100},"screenshot-3.jpg":{"filename":"screenshot-3.jpg","revision":3520060,"resolution":"3","location":"assets","locale":"","width":1288,"height":1206},"screenshot-4.jpg":{"filename":"screenshot-4.jpg","revision":3520060,"resolution":"4","location":"assets","locale":"","width":1278,"height":1632},"screenshot-5.jpg":{"filename":"screenshot-5.jpg","revision":3520060,"resolution":"5","location":"assets","locale":"","width":1062,"height":1050},"screenshot-6.jpg":{"filename":"screenshot-6.jpg","revision":3520060,"resolution":"6","location":"assets","locale":"","width":1336,"height":1128},"screenshot-7.jpg":{"filename":"screenshot-7.jpg","revision":3520060,"resolution":"7","location":"assets","locale":"","width":2140,"height":1516},"screenshot-8.jpg":{"filename":"screenshot-8.jpg","revision":3520060,"resolution":"8","location":"assets","locale":"","width":1450,"height":966},"screenshot-9.jpg":{"filename":"screenshot-9.jpg","revision":3520060,"resolution":"9","location":"assets","locale":"","width":1860,"height":1414}},"screenshots":{"1":"Admin notice prompting users to set up 2FA","2":"Setup prompt asking the user to start now or later","3":"Choosing the authentication method: email or authenticator app","4":"App-based authentication \u2013 FreeOTP recommended, with download links","5":"Email-based authentication","6":"Email confirmation step","7":"Backup codes \u2013 send by email, download, or print","8":"Shortcode displaying the 2FA status on any page","9":"2FA status on the user's My Account page \u2013 inactive","10":"2FA status on the user's My Account page \u2013 active, with the chosen method","11":"Backend admin view: per-account 2FA status and the method in use","12":"Settings: enforcement reminder, which roles must use 2FA, grace period, enforcement areas, validation strictness (strict \/ normal \/ tolerant), and trusted-device duration","13":"Shortcode for embedding the 2FA status indicator on any page","14":"Privacy &amp; Hardening: hide user data in the REST API and disable password reset per role"},"jetpack_post_was_ever_published":false},"plugin_section":[],"plugin_tags":[9211,602,600,9225,9217],"plugin_category":[38,54],"plugin_contributors":[242870],"plugin_business_model":[],"class_list":["post-300820","plugin","type-plugin","status-publish","hentry","plugin_tags-2fa","plugin_tags-login","plugin_tags-security","plugin_tags-totp","plugin_tags-two-factor","plugin_category-authentication","plugin_category-security-and-spam-protection","plugin_contributors-rogerruckstuhl","plugin_committers-rogerruckstuhl"],"banners":{"banner":"https:\/\/ps.w.org\/super-duper-two-factor-login\/assets\/banner-772x250.png?rev=3520060","banner_2x":"https:\/\/ps.w.org\/super-duper-two-factor-login\/assets\/banner-1544x500.png?rev=3520060","banner_rtl":false,"banner_2x_rtl":false},"icons":{"svg":false,"icon":"https:\/\/ps.w.org\/super-duper-two-factor-login\/assets\/icon-128x128.png?rev=3520060","icon_2x":"https:\/\/ps.w.org\/super-duper-two-factor-login\/assets\/icon-256x256.png?rev=3520060","generated":false},"screenshots":[{"src":"https:\/\/ps.w.org\/super-duper-two-factor-login\/assets\/screenshot-1.jpg?rev=3520060","caption":"Admin notice prompting users to set up 2FA"},{"src":"https:\/\/ps.w.org\/super-duper-two-factor-login\/assets\/screenshot-2.jpg?rev=3520060","caption":"Setup prompt asking the user to start now or later"},{"src":"https:\/\/ps.w.org\/super-duper-two-factor-login\/assets\/screenshot-3.jpg?rev=3520060","caption":"Choosing the authentication method: email or authenticator app"},{"src":"https:\/\/ps.w.org\/super-duper-two-factor-login\/assets\/screenshot-4.jpg?rev=3520060","caption":"App-based authentication \u2013 FreeOTP recommended, with download links"},{"src":"https:\/\/ps.w.org\/super-duper-two-factor-login\/assets\/screenshot-5.jpg?rev=3520060","caption":"Email-based authentication"},{"src":"https:\/\/ps.w.org\/super-duper-two-factor-login\/assets\/screenshot-6.jpg?rev=3520060","caption":"Email confirmation step"},{"src":"https:\/\/ps.w.org\/super-duper-two-factor-login\/assets\/screenshot-7.jpg?rev=3520060","caption":"Backup codes \u2013 send by email, download, or print"},{"src":"https:\/\/ps.w.org\/super-duper-two-factor-login\/assets\/screenshot-8.jpg?rev=3520060","caption":"Shortcode displaying the 2FA status on any page"},{"src":"https:\/\/ps.w.org\/super-duper-two-factor-login\/assets\/screenshot-9.jpg?rev=3520060","caption":"2FA status on the user's My Account page \u2013 inactive"},{"src":"https:\/\/ps.w.org\/super-duper-two-factor-login\/assets\/screenshot-10.jpg?rev=3520060","caption":"2FA status on the user's My Account page \u2013 active, with the chosen method"},{"src":"https:\/\/ps.w.org\/super-duper-two-factor-login\/assets\/screenshot-11.jpg?rev=3520060","caption":"Backend admin view: per-account 2FA status and the method in use"},{"src":"https:\/\/ps.w.org\/super-duper-two-factor-login\/assets\/screenshot-12.jpg?rev=3520060","caption":"Settings: enforcement reminder, which roles must use 2FA, grace period, enforcement areas, validation strictness (strict \/ normal \/ tolerant), and trusted-device duration"},{"src":"https:\/\/ps.w.org\/super-duper-two-factor-login\/assets\/screenshot-13.jpg?rev=3520060","caption":"Shortcode for embedding the 2FA status indicator on any page"},{"src":"https:\/\/ps.w.org\/super-duper-two-factor-login\/assets\/screenshot-14.jpg?rev=3520060","caption":"Privacy &amp; Hardening: hide user data in the REST API and disable password reset per role"}],"raw_content":"<!--section=description-->\n<p><strong>Super Duper Two-Factor Login<\/strong> adds robust two-factor authentication to your WordPress site. Unlike many alternatives, this plugin is completely free \u2013 no hidden costs, no premium tiers, no upsells. Every feature is included from the start.<\/p>\n\n<p>\ud83c\udde8\ud83c\udded\ud83c\udde9\ud83c\uddea\ud83c\udde6\ud83c\uddf9 <em>Hinweis f\u00fcr DACH-Nutzer: Plugin und Support sind auf Deutsch (Schweiz\/Deutschland\/\u00d6sterreich) verf\u00fcgbar. Alle Texte und Einstellungen sind vollst\u00e4ndig auf Deutsch \u00fcbersetzt.<\/em><\/p>\n\n<p><strong>Fully translated out of the box<\/strong> in German (Switzerland, Germany, Austria), English, French, Spanish, Italian and Dutch \u2013 no separate language pack required.<\/p>\n\n<h4>Two Verification Methods<\/h4>\n\n<ul>\n<li><strong>TOTP (Authenticator App)<\/strong> \u2013 Works with Google Authenticator, FreeOTP+, Authy, Microsoft Authenticator, and any TOTP-compatible app. Setup via QR code or manual key entry.<\/li>\n<li><strong>Email<\/strong> \u2013 Receive a 6-digit code via email on every login. No smartphone required.<\/li>\n<\/ul>\n\n<h4>Comprehensive Fallback System<\/h4>\n\n<ul>\n<li><strong>10 Backup Codes<\/strong> \u2013 One-time emergency codes in case you lose your phone. Copy, download, print, or email them to yourself.<\/li>\n<li><strong>Administrator Recovery Key<\/strong> \u2013 Each admin receives a personal 32-character key during setup. Works even when all backup codes are used up.<\/li>\n<li><strong>FTP Emergency Recovery<\/strong> \u2013 As a last resort, create an empty file named <code>.sdtfa-recovery<\/code> in <code>wp-content\/<\/code> via FTP. Temporarily disables 2FA for all administrators. Admins are notified hourly by email.<\/li>\n<\/ul>\n\n<h4>Enforcement &amp; Trust<\/h4>\n\n<ul>\n<li><strong>Role-Based Enforcement<\/strong> \u2013 Require 2FA for administrators, editors, subscribers, or any role.<\/li>\n<li><strong>Grace Period<\/strong> \u2013 Set a deadline so users have time to set up 2FA before enforcement kicks in.<\/li>\n<li><strong>Hard Enforcement<\/strong> \u2013 Without a grace period, users must complete 2FA setup on the login page before gaining any access.<\/li>\n<li><strong>Enforcement Areas<\/strong> \u2013 Choose where to enforce: admin area, WooCommerce account, checkout, or entire site.<\/li>\n<li><strong>Trust This Device<\/strong> \u2013 Users can save their computer so the 2FA code isn't required on every login. Configurable duration (1\u2013365 days).<\/li>\n<\/ul>\n\n<h4>Integration<\/h4>\n\n<ul>\n<li><strong>WooCommerce<\/strong> \u2013 Adds a \"Two-Factor Authentication\" tab to the My Account page. Enforce 2FA for the account area and checkout.<\/li>\n<li><strong>Shortcode<\/strong> \u2013 Display the user's 2FA status anywhere with <code>[sdtfa_status]<\/code>.<\/li>\n<li><strong>Setup Reminder<\/strong> \u2013 A dismissable admin notice with a \"Set up now\" button. No auto-popups; users open the setup flow only by clicking.<\/li>\n<\/ul>\n\n<h4>Security<\/h4>\n\n<ul>\n<li>AES-256-GCM encryption for TOTP secrets at rest<\/li>\n<li>Secure HttpOnly cookies for trusted devices<\/li>\n<li>Hashed token storage (never stored in plain text)<\/li>\n<li>No external dependencies \u2013 everything runs locally in pure PHP<\/li>\n<li>No external API calls, no tracking, no data collection<\/li>\n<\/ul>\n\n<h4>Privacy &amp; Hardening (optional)<\/h4>\n\n<ul>\n<li><p><strong>Hide user data in REST API<\/strong> \u2013 Replace sensitive user fields (name, slug, link, avatar) with neutral values for unauthenticated requests. The REST endpoint stays reachable for SEO and import tools, but anonymous visitors no longer see real display names. Uses a strict whitelist that automatically drops any extra fields injected by SEO, page-builder or e-commerce plugins (Yoast, Rank Math, AIOSEO, Elementor, WooCommerce, \u2026). Example response for an anonymous visitor on <code>\/wp-json\/wp\/v2\/users\/1<\/code>:<\/p>\n\n<p>{\"id\":1,\"name\":\"Author\",\"url\":\"\",\"description\":\"\",\"link\":\"https:\\\/\\\/example.com\\\/\",\"slug\":\"author\",\"avatar_urls\":{}}<\/p><\/li>\n<li><p><strong>Block author archives<\/strong> \u2013 Redirect unauthenticated visitors away from <code>?author=N<\/code> and <code>\/author\/&lt;slug&gt;\/<\/code> to prevent user enumeration.<\/p><\/li>\n<li><strong>Disable password reset<\/strong> \u2013 Disable the \"Lost your password?\" function for administrators and\/or selected roles. Useful when 2FA must be the only authentication path.<\/li>\n<li><strong>Users list column<\/strong> \u2013 A clean \"SDTFA\" column on Users \u2192 All Users that shows the real 2FA status (TOTP, Email, or off) and replaces duplicate columns added by host mu-plugins or other 2FA plugins.<\/li>\n<\/ul>\n\n<!--section=installation-->\n<ol>\n<li>Upload the plugin via <strong>Plugins \u2192 Add New \u2192 Upload Plugin<\/strong>, or install it directly from the WordPress plugin directory.<\/li>\n<li>Activate the plugin.<\/li>\n<li>Configure the main 2FA settings under <strong>Two-Factor Login<\/strong> in the admin menu. Optional <strong>Privacy &amp; Hardening<\/strong> features (REST user-data masking, author-archive blocking, password-reset lock-down, users-list status column) are on the same settings page.<\/li>\n<li>Users can set up 2FA from their WordPress profile page or WooCommerce My Account.<\/li>\n<\/ol>\n\n<!--section=faq-->\n<dl>\n<dt id=\"which%20authenticator%20apps%20are%20supported%3F\"><h3>Which authenticator apps are supported?<\/h3><\/dt>\n<dd><p>Any TOTP-compatible app works, including Google Authenticator, FreeOTP+, Authy, Microsoft Authenticator, and many others. We recommend FreeOTP+ (Android) and FreeOTP (iOS) as free, open-source options.<\/p><\/dd>\n<dt id=\"what%20happens%20if%20i%20lose%20my%20phone%3F\"><h3>What happens if I lose my phone?<\/h3><\/dt>\n<dd><p>You can log in using one of your 10 backup codes. If those are also gone, administrators can use their personal recovery key on the login page. As a last resort, create an empty file named <code>.sdtfa-recovery<\/code> in <code>wp-content\/<\/code> via FTP to temporarily disable 2FA.<\/p><\/dd>\n<dt id=\"can%20i%20enforce%202fa%20for%20all%20users%3F\"><h3>Can I enforce 2FA for all users?<\/h3><\/dt>\n<dd><p>Yes. Go to Two-Factor Login settings and select which roles must use 2FA. You can set a grace period with a deadline, or enforce it immediately \u2013 users will then be required to complete 2FA setup on the login page before gaining any access.<\/p><\/dd>\n<dt id=\"does%20this%20plugin%20work%20with%20woocommerce%3F\"><h3>Does this plugin work with WooCommerce?<\/h3><\/dt>\n<dd><p>Yes. It adds a \"Two-Factor Authentication\" tab to the WooCommerce My Account page. You can also enforce 2FA for the WooCommerce account area and checkout.<\/p><\/dd>\n<dt id=\"what%20is%20the%20%22trust%20this%20device%22%20feature%3F\"><h3>What is the \"Trust this device\" feature?<\/h3><\/dt>\n<dd><p>When enabled by the admin, users can check \"Save this computer\" during login. The 2FA code won't be required again on that device for the configured number of days.<\/p><\/dd>\n<dt id=\"are%20external%20services%20or%20images%20used%3F\"><h3>Are external services or images used?<\/h3><\/dt>\n<dd><p>No. Everything runs locally. QR codes are generated in PHP, TOTP calculations happen on the server, and app store badges use local SVG files. No external images, scripts, or API calls are made.<\/p><\/dd>\n<dt id=\"what%20does%20the%20%22privacy%20%26%20hardening%22%20section%20do%3F\"><h3>What does the \"Privacy &amp; Hardening\" section do?<\/h3><\/dt>\n<dd><p>It bundles four optional, independently toggleable features that close common WordPress information-leak and lock-out paths. Hide user data (REST API) replaces sensitive fields (name, slug, link, avatar) with neutral values for unauthenticated requests, while keeping the endpoint reachable so SEO and import plugins still work. Block author archives redirects unauthenticated visitors away from <code>?author=N<\/code> and <code>\/author\/&lt;slug&gt;\/<\/code> to prevent user enumeration. Disable password reset blocks the \"Lost your password?\" function for administrators and\/or selected roles. The users-list column adds a clean \"SDTFA\" status indicator on Users \u2192 All Users. All four features are off by default except the users-list column, which is on by default to clean up duplicate columns from other plugins.<\/p><\/dd>\n<dt id=\"why%20does%20the%20users%20%E2%86%92%20all%20users%20page%20show%20an%20%22sdtfa%22%20column%20instead%20of%20a%20generic%20%222fa%22%20one%3F\"><h3>Why does the Users \u2192 All Users page show an \"SDTFA\" column instead of a generic \"2FA\" one?<\/h3><\/dt>\n<dd><p>Some hosts and other 2FA plugins inject their own \"2FA\" column on the users list. When Super Duper Two-Factor Login is installed, those columns can show outdated or misleading status (for example a red \u2717 even though 2FA is configured here). The plugin replaces them with a single, accurate \"SDTFA\" column that reads the real status from this plugin's own user meta. If you prefer the original column behavior, you can disable this in the Privacy &amp; Hardening section.<\/p><\/dd>\n<dt id=\"will%20this%20plugin%20conflict%20with%20other%202fa%20plugins%3F\"><h3>Will this plugin conflict with other 2FA plugins?<\/h3><\/dt>\n<dd><p>It is not designed to run side-by-side with another active 2FA plugin \u2013 two plugins both intercepting <code>wp-login.php<\/code> will produce unpredictable results. If you are migrating from another 2FA plugin, deactivate the other one first. The \"SDTFA\" users-list column will hide a leftover column from a deactivated plugin only if that plugin still injects it; in normal cases the foreign column simply disappears with the foreign plugin.<\/p><\/dd>\n<dt id=\"is%20this%20plugin%20really%20free%3F\"><h3>Is this plugin really free?<\/h3><\/dt>\n<dd><p>Yes, completely. There is no premium version, no upsells, and no feature restrictions. All features are available to everyone.<\/p><\/dd>\n\n<\/dl>\n\n<!--section=changelog-->\n<h4>2.5.13 \u2013 13.05.2026<\/h4>\n\n<ul>\n<li>Fix: Datepicker for the enforcement deadline now opens directly below the input field instead of at the bottom of the page.<\/li>\n<\/ul>\n\n<h4>2.5.12 \u2013 11.05.2026<\/h4>\n\n<ul>\n<li>Improvement: All plugin emails (login code, backup codes, recovery notifications) are now sent as properly formatted HTML with clear layout, code highlighting, and per-line backup code display.<\/li>\n<li>Fix: No longer forces a <code>From:<\/code> header on outgoing emails so SMTP plugins can apply their SPF\/DKIM-aligned sender address without conflict.<\/li>\n<li>Debug: Added <code>[SDTFA]<\/code> entries to debug.log (when WP_DEBUG is on) to make email-delivery failures diagnosable.<\/li>\n<li>i18n: 13 new mail-template strings translated to all eight locales (DE_CH, DE_DE, DE_AT, EN_US, FR_FR, ES_ES, IT_IT, NL_NL), including a plural form for the validity-minutes string.<\/li>\n<\/ul>\n\n<h4>2.5.11 \u2013 05.05.2026<\/h4>\n\n<ul>\n<li>Fix: WooCommerce <code>customer-logout<\/code> endpoint is now explicitly excluded from 2FA enforcement so customers can always log out, even when <code>wc_account<\/code> or <code>entire_site<\/code> enforcement is active.<\/li>\n<\/ul>\n\n<h4>2.5.9 \u2013 05.05.2026<\/h4>\n\n<ul>\n<li>Improved: forced 2FA setup screen on wp-login.php now uses larger, more readable fonts (warning text 16px, button 17px, content 15px) and a slightly wider login box.<\/li>\n<li>i18n: translations completed for all eight supported locales (DE_CH, DE_DE, DE_AT, EN_US, FR_FR, ES_ES, IT_IT, NL_NL) \u2013 every string in the plugin is now fully translated. .pot template regenerated from current source.<\/li>\n<\/ul>\n\n<h4>2.5.8 \u2013 05.05.2026<\/h4>\n\n<ul>\n<li>Fixed: forced 2FA setup AJAX calls returned HTTP 403 because the WordPress nonce check failed for unauthenticated users on the login page. The forced-setup token (already present in the request and validated against a server-side transient) is now accepted as the authorization for these AJAX calls, with the standard nonce check still applied for logged-in users.<\/li>\n<\/ul>\n\n<h4>2.5.7 \u2013 05.05.2026<\/h4>\n\n<ul>\n<li>Fixed: forced 2FA setup screen on wp-login.php was unusable \u2013 clicking \"Set up now\" left the button stuck at \"\u2026\". The AJAX endpoints were registered for logged-in users only, but the forced-setup flow runs before the user is authenticated. Endpoints now also accept unauthenticated calls when a valid forced-setup token is supplied, and the JavaScript automatically passes that token along.<\/li>\n<\/ul>\n\n<h4>2.5.6 \u2013 05.05.2026<\/h4>\n\n<ul>\n<li>Improved: REST API user-data hiding now uses a strict whitelist approach instead of a maintained block list. Only structurally-required fields (id, name, slug, link, avatar_urls, description, url) are kept in the response \u2014 everything else is dropped automatically, including fields from Yoast SEO (yoast_head, yoast_head_json), Rank Math, AIOSEO, SEOPress, Elementor, WooCommerce, and any future plugins that inject data into the user REST endpoint.<\/li>\n<li>New: filter hook <code>sdtfa_rest_user_allowed_keys<\/code> to extend the whitelist for plugins or sites that have a legitimate need to expose additional public fields.<\/li>\n<li>Fixed: the filter now runs at priority 999 so it executes after third-party plugins that register their own user REST fields.<\/li>\n<li>Fixed: REST self\/collection links (which expose the numeric user ID) are now removed from the response for unauthenticated requests when user-data hiding is enabled.<\/li>\n<li>Fixed: \"Set up now\" button on the admin notice did not open the popup overlay because the script cached DOM selectors before the popup HTML was rendered. Selectors are now resolved after DOM-ready, with a fallback redirect to the profile page if the overlay is still missing.<\/li>\n<\/ul>\n\n<h4>2.5.5 \u2013 01.05.2026<\/h4>\n\n<ul>\n<li>Fixed: SVN pre-commit hook on WordPress.org rejected the package because the email-sending method used a \"true\" return type (PHP 8.2+ feature). Replaced with the equivalent \"bool\" return type for broader compatibility while keeping identical behavior.<\/li>\n<\/ul>\n\n<h4>2.5.4 \u2013 30.04.2026<\/h4>\n\n<ul>\n<li>Fixed: three strings in the en_US translation file contained German text instead of English (the shortcode description, the deadline notice, and the site-icon warning). Sites running with English locale will now correctly show English text.<\/li>\n<li>Fixed: removed remaining German example text from the docblock of the shortcode class file (no functional impact, source-code cleanup only).<\/li>\n<\/ul>\n\n<h4>2.5.3 \u2013 30.04.2026<\/h4>\n\n<ul>\n<li>Fixed: removed remaining hardcoded German strings from PHP source (3\u00d7 \"Nicht angemeldet.\", backup-codes email body, recovery-key label, backup-codes textarea header)<\/li>\n<li>Fixed: removed hardcoded German \"Best\u00e4tigen\" button label from JavaScript (used after a failed verification attempt) \u2013 now uses the existing translatable string<\/li>\n<li>i18n: all four cleaned-up strings translated for all eight supported locales (DE_CH\/DE\/AT, EN, FR, ES, IT, NL)<\/li>\n<\/ul>\n\n<h4>2.5.2 \u2013 30.04.2026<\/h4>\n\n<ul>\n<li>Fixed: 2FA setup via email failed silently on hosts that reject mails without an explicit \"From\" header \u2013 the email now always carries a same-domain sender address<\/li>\n<li>Improved: when sending the 2FA code fails, the actual underlying mail error (from PHPMailer \/ SMTP) is now surfaced in the setup dialog instead of a generic \"please try again\"<\/li>\n<li>Fixed: send cooldown is now armed only after a successful send, so a failed delivery no longer blocks the next attempt for 60 seconds<\/li>\n<li>Improved: graceful fallback for the email subject when the issuer\/site name option is empty<\/li>\n<\/ul>\n\n<h4>2.5.1 \u2013 30.04.2026<\/h4>\n\n<ul>\n<li>New: \"SDTFA\" column on Users \u2192 All Users showing the actual 2FA status (TOTP \/ Email \/ off) with green check or red \u2717<\/li>\n<li>New: Removes 2FA columns added by foreign 2FA plugins or host mu-plugins to avoid duplicate or misleading status indicators<\/li>\n<li>New: Toggle in Privacy &amp; Hardening section to disable the column behavior if not desired (enabled by default)<\/li>\n<\/ul>\n\n<h4>2.5.0 \u2013 30.04.2026<\/h4>\n\n<ul>\n<li>New: Privacy &amp; Hardening section with three optional features<\/li>\n<li>New: Hide sensitive user data in REST API responses for unauthenticated visitors (REST endpoint stays reachable for SEO\/import tools)<\/li>\n<li>New: Block author archives (?author=N) for unauthenticated visitors to prevent user enumeration<\/li>\n<li>New: Disable WordPress password reset for administrators and\/or selected roles<\/li>\n<li>Fixed: empty jQuery UI datepicker container no longer appears at the bottom of admin pages \u2013 it is now hidden by default and moved next to its input field on open<\/li>\n<\/ul>\n\n<h4>2.4.1 \u2013 22.04.2026<\/h4>\n\n<ul>\n<li>Fixed: dismiss (\u00d7) button on the admin notice now correctly persists via AJAX so the notice doesn't reappear on every page reload<\/li>\n<\/ul>\n\n<h4>2.4.0 \u2013 22.04.2026<\/h4>\n\n<ul>\n<li>Renamed plugin to \"Super Duper Two-Factor Login\" (slug: super-duper-two-factor-login) for improved distinctiveness in the plugin directory<\/li>\n<li>Replaced the setup popup with a WordPress-standard dismissable admin notice and a \"Set up now\" button \u2013 the modal opens only on user action<\/li>\n<li>Moved the admin menu from position 3 to position 71 (after Users) to respect the WordPress admin hierarchy<\/li>\n<li>Extracted all inline <code>&lt;style&gt;<\/code> and <code>&lt;script&gt;<\/code> output into enqueued assets (<code>wp_enqueue_style<\/code>, <code>wp_enqueue_script<\/code>, <code>wp_add_inline_style<\/code>)<\/li>\n<li>Localized datepicker day and month names via <code>wp_localize_script<\/code> (English source, translations via .po)<\/li>\n<li>Updated the plugin header description to English (source strings) with German translations moved to .po\/.mo<\/li>\n<li>Corrected the <code>Contributors<\/code> entry in readme.txt to the actual WordPress.org username<\/li>\n<\/ul>\n\n<h4>2.3.0 \u2013 10.04.2026<\/h4>\n\n<ul>\n<li>First public release on WordPress.org<\/li>\n<li>TOTP and email-based two-factor authentication<\/li>\n<li>10 one-time backup codes with copy, download, print, and email<\/li>\n<li>Personal recovery key for administrators<\/li>\n<li>FTP emergency recovery via .sdtfa-recovery file<\/li>\n<li>Trusted device feature (save this computer)<\/li>\n<li>Role-based enforcement with optional grace period<\/li>\n<li>Hard enforcement: 2FA setup required before login<\/li>\n<li>Enforcement areas: admin, WooCommerce account, checkout, entire site<\/li>\n<li>WooCommerce My Account integration<\/li>\n<li>Setup popup reminder (dismissible)<\/li>\n<li>Shortcode [sdtfa_status]<\/li>\n<li>AES-256-GCM encryption for TOTP secrets<\/li>\n<li>Translations: German (DE\/AT\/CH), English, French, Spanish, Italian, Dutch<\/li>\n<\/ul>\n\n<h4>1.0.0 \u2013 2.2.x<\/h4>\n\n<ul>\n<li>Internal development and testing<\/li>\n<\/ul>","raw_excerpt":"Two-factor authentication for WordPress \u2013 TOTP &amp; email, backup codes, recovery keys, trusted devices, role-based enforcement, privacy hardening.","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/en-za.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin\/300820","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/en-za.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin"}],"about":[{"href":"https:\/\/en-za.wordpress.org\/plugins\/wp-json\/wp\/v2\/types\/plugin"}],"replies":[{"embeddable":true,"href":"https:\/\/en-za.wordpress.org\/plugins\/wp-json\/wp\/v2\/comments?post=300820"}],"author":[{"embeddable":true,"href":"https:\/\/en-za.wordpress.org\/plugins\/wp-json\/wporg\/v1\/users\/rogerruckstuhl"}],"wp:attachment":[{"href":"https:\/\/en-za.wordpress.org\/plugins\/wp-json\/wp\/v2\/media?parent=300820"}],"wp:term":[{"taxonomy":"plugin_section","embeddable":true,"href":"https:\/\/en-za.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_section?post=300820"},{"taxonomy":"plugin_tags","embeddable":true,"href":"https:\/\/en-za.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_tags?post=300820"},{"taxonomy":"plugin_category","embeddable":true,"href":"https:\/\/en-za.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_category?post=300820"},{"taxonomy":"plugin_contributors","embeddable":true,"href":"https:\/\/en-za.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_contributors?post=300820"},{"taxonomy":"plugin_business_model","embeddable":true,"href":"https:\/\/en-za.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_business_model?post=300820"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}