{"id":24769,"date":"2013-08-18T13:26:16","date_gmt":"2013-08-18T13:26:16","guid":{"rendered":"https:\/\/wordpress.org\/plugins-wp\/wp-login-delay\/"},"modified":"2026-03-30T14:44:42","modified_gmt":"2026-03-30T14:44:42","slug":"wp-login-delay","status":"publish","type":"plugin","link":"https:\/\/srd.wordpress.org\/plugins\/wp-login-delay\/","author":12952427,"comment_status":"closed","ping_status":"closed","template":"","meta":{"_crdt_document":"","version":"2.2.3","stable_tag":"2.2.3","tested":"6.9.4","requires":"3.5.1","requires_php":"7.4","requires_plugins":null,"header_name":"Login Delay Shield","header_author":"Mike","header_description":"","assets_banners_color":"010a20","last_updated":"2026-03-30 14:44:42","external_support_url":"","external_repository_url":"","donate_link":"http:\/\/damoiseau.me\/","header_plugin_uri":"https:\/\/damoiseau.me","header_author_uri":"https:\/\/damoiseau.me","rating":4.4,"author_block_rating":0,"active_installs":80,"downloads":4488,"num_ratings":5,"support_threads":0,"support_threads_resolved":0,"author_block_count":0,"sections":["description","installation","faq","changelog"],"tags":{"1.1":{"tag":"1.1","author":"michael.damoiseau","date":"2013-12-15 12:16:37"},"1.3":{"tag":"1.3","author":"michael.damoiseau","date":"2017-10-13 10:37:31"},"1.3.1":{"tag":"1.3.1","author":"michael.damoiseau","date":"2017-10-13 13:10:43"},"1.4":{"tag":"1.4","author":"michael.damoiseau","date":"2017-10-26 06:20:15"},"1.5":{"tag":"1.5","author":"michael.damoiseau","date":"2021-07-20 07:47:38"},"1.5.1":{"tag":"1.5.1","author":"michael.damoiseau","date":"2021-07-21 03:52:06"},"2.0.0":{"tag":"2.0.0","author":"michael.damoiseau","date":"2026-02-01 14:32:32"},"2.1.0":{"tag":"2.1.0","author":"michael.damoiseau","date":"2026-02-14 11:50:52"},"2.1.1":{"tag":"2.1.1","author":"michael.damoiseau","date":"2026-02-23 14:35:33"},"2.1.2":{"tag":"2.1.2","author":"michael.damoiseau","date":"2026-03-01 06:37:38"},"2.1.3":{"tag":"2.1.3","author":"michael.damoiseau","date":"2026-03-02 10:24:31"},"2.1.4":{"tag":"2.1.4","author":"michael.damoiseau","date":"2026-03-10 03:28:07"},"2.1.5":{"tag":"2.1.5","author":"michael.damoiseau","date":"2026-03-16 04:14:50"},"2.1.6":{"tag":"2.1.6","author":"michael.damoiseau","date":"2026-03-24 03:57:27"},"2.2.3":{"tag":"2.2.3","author":"michael.damoiseau","date":"2026-03-30 14:44:42"}},"upgrade_notice":{"2.2.0":"<p>Adds Custom Login URL feature: move the login page to a custom URL and block direct access to <code>wp-login.php<\/code>. Disabled by default \u2014 no behavior change on upgrade.<\/p>","2.1.5":"<p>Hardens default handling for missing REST\/application-password option keys on migrated or legacy installs.<\/p>","2.1.4":"<p>Adds 2FA health check notice on the settings page and extensible provider detection via filter hook.<\/p>","2.1.3":"<p>Adds telemetry log filters, filtered CSV export, and batched streaming for large exports.<\/p>","2.1.2":"<p>Adds CSV export for the failed login log, REST API and application-password auth protection, and fixes lockout recovery clearing failure counters.<\/p>","2.1.1":"<p>Adds emergency lockout recovery tools: admin <strong>Unlock Current IP<\/strong> action and WP-CLI commands to unlock a specific IP or flush all lockouts.<\/p>","2.1.0":"<p>Adds username-aware throttling\/lockout (<code>IP + username<\/code>), login feedback messages (remaining attempts + lockout countdown), and improves failed-attempt tracking for progressive delay mode.<\/p>","2.0.0":"<p>Major update with progressive delays, IP lockout, whitelist, XML-RPC protection, email alerts, failed login logging, and 18 language translations. Fully accessible admin interface.<\/p>","1.3.1":"<p>Code is still the same, only the supported version of WordPress has been updated in the documentation.<\/p>"},"ratings":{"1":0,"2":"1","3":0,"4":0,"5":"4"},"assets_icons":{"icon-128x128.png":{"filename":"icon-128x128.png","revision":3467787,"resolution":"128x128","location":"assets","locale":""},"icon-256x256.png":{"filename":"icon-256x256.png","revision":3467787,"resolution":"256x256","location":"assets","locale":""}},"assets_banners":{"banner-1544x500.png":{"filename":"banner-1544x500.png","revision":3467787,"resolution":"1544x500","location":"assets","locale":""},"banner-772x250.png":{"filename":"banner-772x250.png","revision":3467787,"resolution":"772x250","location":"assets","locale":""}},"assets_blueprints":{},"all_blocks":[],"tagged_versions":["1.1","1.3","1.3.1","1.4","1.5","1.5.1","2.0.0","2.1.0","2.1.1","2.1.2","2.1.3","2.1.4","2.1.5","2.1.6","2.2.3"],"block_files":[],"assets_screenshots":{"screenshot-1.png":{"filename":"screenshot-1.png","revision":3467787,"resolution":"1","location":"assets","locale":""},"screenshot-2.png":{"filename":"screenshot-2.png","revision":3467787,"resolution":"2","location":"assets","locale":""}},"screenshots":{"1":"Settings page with delay configuration options.","2":"Email notification and IP lockout settings.","3":"IP whitelist and XML-RPC protection settings.","4":"Dashboard widget showing recent failed login attempts."},"jetpack_post_was_ever_published":false},"plugin_section":[],"plugin_tags":[2439,13868,602,600,14731],"plugin_category":[38,54],"plugin_contributors":[87106],"plugin_business_model":[],"class_list":["post-24769","plugin","type-plugin","status-publish","hentry","plugin_tags-brute-force","plugin_tags-lockout","plugin_tags-login","plugin_tags-security","plugin_tags-xmlrpc","plugin_category-authentication","plugin_category-security-and-spam-protection","plugin_contributors-michaeldamoiseau","plugin_committers-michaeldamoiseau"],"banners":{"banner":"https:\/\/ps.w.org\/wp-login-delay\/assets\/banner-772x250.png?rev=3467787","banner_2x":"https:\/\/ps.w.org\/wp-login-delay\/assets\/banner-1544x500.png?rev=3467787","banner_rtl":false,"banner_2x_rtl":false},"icons":{"svg":false,"icon":"https:\/\/ps.w.org\/wp-login-delay\/assets\/icon-128x128.png?rev=3467787","icon_2x":"https:\/\/ps.w.org\/wp-login-delay\/assets\/icon-256x256.png?rev=3467787","generated":false},"screenshots":[{"src":"https:\/\/ps.w.org\/wp-login-delay\/assets\/screenshot-1.png?rev=3467787","caption":"Settings page with delay configuration options."},{"src":"https:\/\/ps.w.org\/wp-login-delay\/assets\/screenshot-2.png?rev=3467787","caption":"Email notification and IP lockout settings."}],"raw_content":"<!--section=description-->\n<p>WordPress is one of the most widely used content management systems on the internet, making it a frequent target for bots and hackers attempting brute-force attacks.<\/p>\n\n<p>A brute-force attack works by systematically trying passwords until finding the correct one. Login Delay Shield defends against this by adding a configurable delay after each failed login attempt. Since successful logins are never delayed, legitimate users experience no slowdown. This approach is particularly effective against bots that send thousands of login requests, as each failed attempt forces the attacker to wait before trying the next password.<\/p>\n\n<p><strong>Features:<\/strong><\/p>\n\n<ul>\n<li><strong>Login delay<\/strong> \u2014 Fixed or random delay on failed login attempts (1-10 seconds)<\/li>\n<li><strong>Progressive delay<\/strong> \u2014 Delay increases with each consecutive failed attempt from the same IP<\/li>\n<li><strong>IP lockout<\/strong> \u2014 Temporarily block IP addresses after too many failed attempts<\/li>\n<li><strong>Username-aware lockout strategy<\/strong> \u2014 Choose <code>IP only<\/code> or <code>IP + username<\/code> to reduce false positives on shared networks<\/li>\n<li><strong>Login feedback<\/strong> \u2014 Shows remaining attempts before lockout and a lockout countdown when blocked<\/li>\n<li><strong>IP whitelist<\/strong> \u2014 Bypass all security measures for trusted IPs (supports CIDR notation)<\/li>\n<li><strong>Email notifications<\/strong> \u2014 Receive alerts when failed login thresholds are reached<\/li>\n<li><strong>Failed login log<\/strong> \u2014 Track all failed attempts with a dashboard widget showing recent activity and 7-day trends<\/li>\n<li><strong>XML-RPC protection<\/strong> \u2014 Apply delays to XML-RPC authentication or block it entirely<\/li>\n<li><strong>Custom login URL<\/strong> \u2014 Move the login page to a custom URL to reduce automated bot traffic targeting <code>\/wp-login.php<\/code><\/li>\n<li><strong>Log retention<\/strong> \u2014 Automatic cleanup of old log entries (configurable retention period)<\/li>\n<li><strong>Accessible admin interface<\/strong> \u2014 WCAG 2.1 compliant with keyboard navigation and screen reader support<\/li>\n<li><strong>Multilingual<\/strong> \u2014 Translated into 18 languages including French, German, Spanish, Japanese, Chinese, Arabic, and more<\/li>\n<li>Lightweight and compatible with other security plugins<\/li>\n<\/ul>\n\n<p><em>This plugin is not a complete security solution \u2014 dedicated security plugins offer more comprehensive protection.<\/em> However, Login Delay Shield adds an effective layer of defense that works alongside your existing security measures without conflict.<\/p>\n\n<p><em>Note: This plugin was formerly known as \"WP Login Delay\".<\/em><\/p>\n\n<h3>Contribute<\/h3>\n\n<p>Found a bug or want to suggest an improvement? Open a thread in the <a href=\"https:\/\/wordpress.org\/support\/plugin\/login-delay-shield\/\">support forum<\/a> on WordPress.org.<\/p>\n\n<p>Want to help translate the plugin into your language? Visit <a href=\"https:\/\/translate.wordpress.org\/projects\/wp-plugins\/login-delay-shield\/\">translate.wordpress.org<\/a>.<\/p>\n\n<!--section=installation-->\n<ol>\n<li>Upload the <code>wp-login-delay<\/code> folder to the <code>\/wp-content\/plugins\/<\/code> directory<\/li>\n<li>Activate the plugin through the 'Plugins' menu in WordPress<\/li>\n<li>That's it, Login Delay Shield is installed and working<\/li>\n<\/ol>\n\n<!--section=faq-->\n<dl>\n<dt id=\"how%20does%20this%20plugin%20protect%20my%20site%3F\"><h3>How does this plugin protect my site?<\/h3><\/dt>\n<dd><p>When a bot attempts a brute-force attack, it tries thousands of passwords as fast as possible. By adding a delay (even just 1 second) after each failed attempt, the attack becomes impractical. A one-second delay is barely noticeable to legitimate users but makes a huge difference when multiplied across thousands of attempts.<\/p><\/dd>\n<dt id=\"where%20are%20the%20plugin%20settings%3F\"><h3>Where are the plugin settings?<\/h3><\/dt>\n<dd><p>Go to <code>Settings<\/code> &gt; <code>Login Delay Shield<\/code><\/p><\/dd>\n<dt id=\"what%20is%20progressive%20delay%3F\"><h3>What is progressive delay?<\/h3><\/dt>\n<dd><p>Progressive delay increases the wait time with each consecutive failed attempt from the same IP address. For example, the first failure might delay 1 second, the second failure 2 seconds, and so on. This makes repeated attacks increasingly slow.<\/p><\/dd>\n<dt id=\"how%20does%20ip%20lockout%20work%3F\"><h3>How does IP lockout work?<\/h3><\/dt>\n<dd><p>After a configurable number of failed attempts (default: 10), login attempts are temporarily blocked. You can choose whether attempts are counted by <code>IP only<\/code> or by <code>IP + username<\/code> (recommended for shared office\/mobile IPs). Lockout duration is configurable (default: 60 minutes).<\/p><\/dd>\n<dt id=\"what%20are%20the%20%22attempts%20remaining%22%20and%20countdown%20messages%3F\"><h3>What are the \"attempts remaining\" and countdown messages?<\/h3><\/dt>\n<dd><p>When lockout is enabled, failed logins show how many attempts remain before temporary lockout. If lockout is triggered, the error message includes a countdown (for example, \"try again in 2 minutes\") so users know when to retry.<\/p><\/dd>\n<dt id=\"how%20do%20i%20whitelist%20my%20own%20ip%3F\"><h3>How do I whitelist my own IP?<\/h3><\/dt>\n<dd><p>Enable the IP whitelist feature and add your IP address (or a range using CIDR notation like <code>192.168.1.0\/24<\/code>). Whitelisted IPs bypass all delays and lockouts, ensuring you never lock yourself out.<\/p><\/dd>\n<dt id=\"should%20i%20block%20xml-rpc%3F\"><h3>Should I block XML-RPC?<\/h3><\/dt>\n<dd><p>If you don't use the WordPress mobile app or remote publishing tools like Windows Live Writer, blocking XML-RPC authentication removes a common attack vector. You can also choose to just apply delays without blocking it entirely.<\/p><\/dd>\n<dt id=\"how%20do%20email%20notifications%20work%3F\"><h3>How do email notifications work?<\/h3><\/dt>\n<dd><p>When enabled, the plugin tracks failed login attempts per IP address. Once the threshold is reached (default: 5 attempts), an email is sent to alert you. The counter resets after one hour of no failed attempts from that IP.<\/p><\/dd>\n<dt id=\"where%20can%20i%20see%20failed%20login%20attempts%3F\"><h3>Where can I see failed login attempts?<\/h3><\/dt>\n<dd><p>A dashboard widget shows the 10 most recent failed login attempts, including the time, username attempted, IP address, and source. It also includes a lightweight 7-day trends panel with daily totals, top sources, and top IPs.<\/p><\/dd>\n<dt id=\"is%20the%20admin%20interface%20accessible%3F\"><h3>Is the admin interface accessible?<\/h3><\/dt>\n<dd><p>Yes! Login Delay Shield follows WCAG 2.1 accessibility guidelines. All settings are fully keyboard navigable, screen reader compatible, and include proper ARIA attributes. Collapsible sections can be toggled with Enter or Space keys, tooltips appear on focus (not just hover), and all dynamic changes are announced to assistive technologies.<\/p><\/dd>\n<dt id=\"does%20this%20plugin%20work%20better%20with%20an%20object%20cache%3F\"><h3>Does this plugin work better with an object cache?<\/h3><\/dt>\n<dd><p>For high-traffic sites or sites experiencing frequent attacks, we recommend using a persistent object cache like Redis or Memcached.<\/p>\n\n<p>The plugin uses WordPress transients to track failed login attempts and lockouts per IP address. By default, transients are stored in the database. During a distributed brute-force attack (many IPs), this can create additional database queries.<\/p>\n\n<p>With an object cache installed:<\/p>\n\n<ul>\n<li>Transient reads\/writes go to memory instead of the database<\/li>\n<li>Much faster performance under attack conditions<\/li>\n<li>Reduced database load<\/li>\n<\/ul>\n\n<p>Popular object cache plugins: Redis Object Cache, W3 Total Cache, LiteSpeed Cache.<\/p>\n\n<p>Most managed WordPress hosts (WP Engine, Kinsta, Flywheel) include object caching by default.<\/p><\/dd>\n<dt id=\"what%20languages%20are%20supported%3F\"><h3>What languages are supported?<\/h3><\/dt>\n<dd><p>Login Delay Shield is translated into 18 languages:<\/p>\n\n<ul>\n<li>English (default)<\/li>\n<li>Arabic (\u0627\u0644\u0639\u0631\u0628\u064a\u0629)<\/li>\n<li>Chinese Simplified (\u7b80\u4f53\u4e2d\u6587)<\/li>\n<li>Czech (\u010ce\u0161tina)<\/li>\n<li>Dutch (Nederlands)<\/li>\n<li>French (Fran\u00e7ais)<\/li>\n<li>German (Deutsch)<\/li>\n<li>Indonesian (Bahasa Indonesia)<\/li>\n<li>Italian (Italiano)<\/li>\n<li>Japanese (\u65e5\u672c\u8a9e)<\/li>\n<li>Korean (\ud55c\uad6d\uc5b4)<\/li>\n<li>Polish (Polski)<\/li>\n<li>Portuguese - Brazil (Portugu\u00eas do Brasil)<\/li>\n<li>Russian (\u0420\u0443\u0441\u0441\u043a\u0438\u0439)<\/li>\n<li>Spanish (Espa\u00f1ol)<\/li>\n<li>Swedish (Svenska)<\/li>\n<li>Thai (\u0e44\u0e17\u0e22)<\/li>\n<li>Turkish (T\u00fcrk\u00e7e)<\/li>\n<li>Vietnamese (Ti\u1ebfng Vi\u1ec7t)<\/li>\n<\/ul>\n\n<p>The plugin automatically uses your site's language setting. Want to help translate into another language? Visit <a href=\"https:\/\/translate.wordpress.org\/\">translate.wordpress.org<\/a>.<\/p><\/dd>\n\n<\/dl>\n\n<!--section=changelog-->\n<h4>2.2.3<\/h4>\n\n<p>Complete Custom Login URL runtime, Trend Analytics queries, and bug fixes.<\/p>\n\n<p><strong>New Features:<\/strong>\n* Custom Login URL runtime \u2014 custom slug now fully functional with login, logout, lost password, and password reset all routed through the custom URL.\n* Custom Login URL admin UI \u2014 settings card with enable\/disable toggle, slug input, status badge, and tooltip help.\n* Trend Analytics query functions \u2014 <code>wldelay_get_top_ips()<\/code>, <code>wldelay_get_top_usernames()<\/code>, and <code>wldelay_get_daily_attempts()<\/code> for dashboard trend data.<\/p>\n\n<p><strong>Bug Fixes:<\/strong>\n* Fixed double <code>wp_unslash()<\/code> on login username that could corrupt usernames with literal backslashes.\n* Fixed <code>wp_login_url<\/code> filter name (was <code>wp_login_url<\/code>, should be <code>login_url<\/code>) preventing URL rewriting.\n* Fixed canonical redirect leaking custom login slug via 302 when <code>\/wp-login.php<\/code> is accessed through the front controller.\n* Fixed <code>login_init<\/code> blocking internal WordPress paths (e.g. <code>\/wp\/wp-login.php<\/code>) used for legitimate auth redirects.<\/p>\n\n<p><strong>Improvements:<\/strong>\n* Expanded reserved slug list with <code>wp-json<\/code>, <code>wp-content<\/code>, <code>wp-includes<\/code>, <code>wp-signup<\/code>, <code>wp-activate<\/code>, <code>xmlrpc<\/code>, <code>feed<\/code>, <code>robots<\/code>, <code>sitemap<\/code>.\n* Replaced production <code>wldelay_unlock_current_ip_should_exit<\/code> filter with <code>WP_TESTS_DOMAIN<\/code> constant check \u2014 no longer exposes a testability surface in production.\n* Wrapped Custom Login URL section titles in <code>esc_html__()<\/code> for i18n completeness.\n* Added Custom Login URL to the protection features summary box.\n* Added Playwright end-to-end tests for full Custom Login URL verification.<\/p>\n\n<h4>2.2.2<\/h4>\n\n<p>Micro-hardening \u2014 input sanitization, i18n completeness, and code documentation.<\/p>\n\n<p><strong>Improvements:<\/strong>\n* Added <code>wp_unslash()<\/code> before <code>sanitize_user()<\/code> in login username extraction to correctly handle WordPress magic-quote slashes.\n* Wrapped email notification subject and body in <code>__()<\/code> for full i18n\/l10n support.\n* Added detailed inline comments explaining the IPv6 CIDR binary mask bit-shift logic.<\/p>\n\n<h4>2.2.1<\/h4>\n\n<p>Code housekeeping \u2014 JavaScript extraction and admin UI consistency.<\/p>\n\n<p><strong>Improvements:<\/strong>\n* Extracted all inline JavaScript from the settings page view into a standalone <code>admin.js<\/code> file, loaded via <code>wp_enqueue_script()<\/code>.\n* Used <code>wp_localize_script()<\/code> to pass PHP-side translatable strings to JavaScript (Enabled\/Disabled badge labels).\n* Standardized <code>&lt;label&gt;<\/code> association across all settings field callbacks.\n* Removed unused <code>data-section<\/code> attributes from settings card elements.<\/p>\n\n<h4>2.2.0<\/h4>\n\n<p>Adds Custom Login URL \u2014 the last major unimplemented roadmap feature.<\/p>\n\n<p><strong>New Features:<\/strong>\n* Custom Login URL \u2014 optionally move the WordPress login page to a configurable slug (e.g., <code>\/my-login<\/code>). When enabled, direct access to <code>wp-login.php<\/code> is blocked and all auth flows (login, logout, lost password, password reset) are routed through the custom slug.\n* Emergency recovery bypass \u2014 define <code>WLDELAY_DISABLE_CUSTOM_LOGIN<\/code> in <code>wp-config.php<\/code> to restore access to <code>wp-login.php<\/code> without disabling the plugin.\n* WP-CLI, cron, and REST API contexts are automatically excluded from custom login routing.\n* All WordPress URL generation functions (<code>wp_login_url<\/code>, <code>logout_url<\/code>, <code>lostpassword_url<\/code>) and password-reset emails are transparently updated to use the custom slug.<\/p>\n\n<p><strong>Improvements:<\/strong>\n* New settings card for Custom Login URL in the admin UI, following existing WCAG 2.1 AA accessibility patterns.\n* Custom Login URL feature appears in the protection status summary box.\n* Rewrite rules are automatically flushed when the slug or enabled state changes.<\/p>\n\n<h4>2.1.6<\/h4>\n\n<p>Small release focused on dashboard observability, admin polish, and release metadata improvements.<\/p>\n\n<p><strong>New Features:<\/strong>\n* Added a lightweight failed-login trends panel to the dashboard widget with 7-day activity, top sources, and top IPs.<\/p>\n\n<p><strong>Improvements:<\/strong>\n* Updated the dashboard widget cache to store both recent attempts and trend snapshots while remaining backward-compatible with the previous cache format.\n* Updated the WordPress.org listing metadata, including a more accurate minimum PHP version and refreshed tags.\n* Extracted admin inline JavaScript into a dedicated file for easier maintenance.\n* Standardized settings checkbox rendering for a more consistent admin UI.\n* Added input unslashing before username normalization for safer WordPress-style request handling.<\/p>\n\n<h4>2.1.5<\/h4>\n\n<p>Patch release focused on safer defaults for migrated\/legacy installs.<\/p>\n\n<p><strong>Improvements:<\/strong>\n* Hardened REST and application-password protection toggles when related option keys are missing.\n* Preserves behavior for sites with explicitly saved toggle values while avoiding unintended strict defaults on legacy option states.<\/p>\n\n<h4>2.1.4<\/h4>\n\n<p>Adds 2FA health check notice and code quality improvements.<\/p>\n\n<p><strong>New Features:<\/strong>\n* 2FA health check notice on the settings page \u2014 detects common 2FA plugins (Two-Factor, WP 2FA, miniOrange, Google Authenticator) and reminds administrators to verify coverage.\n* Extensible <code>wldelay_2fa_providers<\/code> filter hook for adding custom 2FA provider detection.<\/p>\n\n<p><strong>Improvements:<\/strong>\n* CSV export now uses the dedicated request filter reader for consistency and safer parameter handling.\n* Renamed 2FA notice CSS class to <code>wldelay-health-notice<\/code> for clearer semantics.\n* Removed <code>1=1<\/code> WHERE sentinel from query builder in favour of conditional clause construction.\n* Hardened <code>wldelay_2fa_providers<\/code> filter callback with type validation to guard against malformed return values.<\/p>\n\n<h4>2.1.3<\/h4>\n\n<p>Adds telemetry log filters and hardens the CSV export.<\/p>\n\n<p><strong>New Features:<\/strong>\n* Telemetry log filters \u2014 filter failed login attempts by source, IP, username, and date range.\n* Filtered CSV export \u2014 export only the subset of log entries matching the active filters.<\/p>\n\n<p><strong>Improvements:<\/strong>\n* CSV export now streams results in batches to prevent memory exhaustion on large log tables.\n* Added database index on the <code>source<\/code> column for faster filtered queries.\n* Hardened query builder to always use <code>$wpdb-&gt;prepare()<\/code> for defense-in-depth.\n* Restricted request parameter reading to expected <code>wldelay_log_*<\/code> keys only.<\/p>\n\n<h4>2.1.2<\/h4>\n\n<p>Feature and bugfix release.<\/p>\n\n<p><strong>New Features:<\/strong>\n* CSV export for the failed login log \u2014 download attempts as a CSV file directly from the dashboard widget.\n* Optional REST API and application-password authentication protection toggles.<\/p>\n\n<p><strong>Bug Fixes:<\/strong>\n* Fixed REST protection staying active even when application passwords are unavailable.\n* Lockout flush recovery now correctly clears failure counters alongside lockout transients.<\/p>\n\n<p><strong>Improvements:<\/strong>\n* Stabilized integration test suite and improved CSV export test reliability.<\/p>\n\n<h4>2.1.1<\/h4>\n\n<p>Patch release focused on lockout recovery tooling.<\/p>\n\n<p><strong>New Features:<\/strong>\n* Added an admin recovery action: <strong>Unlock Current IP<\/strong> button in settings (nonce + capability protected).\n* Added WP-CLI recovery commands:\n  * <code>wp login-delay-shield unlock-ip &lt;ip&gt;<\/code>\n  * <code>wp login-delay-shield flush-lockouts<\/code>\n* Added optional protection toggles for REST API and application-password authentication paths.<\/p>\n\n<p><strong>Improvements:<\/strong>\n* Added integration tests covering lockout recovery helpers and unlock URL generation.\n* Failed-attempt logs now include dedicated source values for REST (<code>rest<\/code>) and application-password (<code>application-password<\/code>) auth failures.<\/p>\n\n<h4>2.1.0<\/h4>\n\n<p>Minor release focused on smarter throttling and lockout behavior.<\/p>\n\n<p><strong>New Security Feature:<\/strong>\n* Username-aware throttling and lockout strategy \u2014 choose between <code>IP only<\/code> and <code>IP + username<\/code> to reduce false positives on shared networks.\n* Login feedback messages \u2014 show remaining attempts before lockout and a lockout countdown when blocked.<\/p>\n\n<p><strong>Improvements:<\/strong>\n* Added lockout strategy control to the admin settings UI.\n* Progressive delay now continues tracking failed attempts when enabled, even if email notifications and lockout are disabled.\n* Expanded test coverage for strategy sanitization and username-isolated lockout behavior.<\/p>\n\n<h4>2.0.0<\/h4>\n\n<p>Major release with comprehensive security features and modern admin interface.<\/p>\n\n<p><strong>New Security Features:<\/strong>\n* Progressive delay \u2014 increases wait time with each consecutive failed attempt from the same IP\n* IP lockout \u2014 temporarily blocks IP addresses after configurable number of failures\n* IP whitelist \u2014 bypass all security for trusted IPs with CIDR notation support (e.g., 192.168.1.0\/24)\n* XML-RPC protection \u2014 apply delays to XML-RPC authentication or block it entirely\n* Email notifications \u2014 alerts when failed login thresholds are reached, with rate limiting to prevent inbox flooding\n* Failed login log \u2014 database-backed logging with dashboard widget showing recent activity\n* Configurable log retention \u2014 automatic cleanup of old entries (1-365 days or keep forever)<\/p>\n\n<p><strong>Improved Delay System:<\/strong>\n* Delays now only apply to failed logins \u2014 successful logins are always instant\n* Configurable random delay range \u2014 set custom min\/max values (1-10 seconds)\n* Smart delay \u2014 successful logins bypass all delays for seamless user experience<\/p>\n\n<p><strong>Admin Interface:<\/strong>\n* Completely redesigned settings page with collapsible sections\n* Real-time status badges showing which features are active\n* Protection summary box for quick security overview\n* WCAG 2.1 Level AA accessible \u2014 full keyboard navigation and screen reader support<\/p>\n\n<p><strong>Internationalization:<\/strong>\n* Translated into 18 languages: Arabic, Chinese (Simplified), Czech, Dutch, French, German, Indonesian, Italian, Japanese, Korean, Polish, Portuguese (Brazil), Russian, Spanish, Swedish, Thai, Turkish, and Vietnamese<\/p>\n\n<p><strong>Performance &amp; Reliability:<\/strong>\n* Batched log cleanup for large tables \u2014 prevents database locks\n* Improved proxy header handling with proper whitespace trimming\n* Options caching for reduced database queries\n* Compatible with object caches (Redis, Memcached) for high-traffic sites<\/p>\n\n<p><strong>Other Improvements:<\/strong>\n* Renamed from \"WP Login Delay\" to \"Login Delay Shield\"\n* WordPress 6.9 compatibility\n* PHP 8.x compatibility\n* Comprehensive test suite<\/p>\n\n<h4>1.5<\/h4>\n\n<ul>\n<li>Added support until WordPress  5.7.2<\/li>\n<li>Remove the word WordPress from the plugin name<\/li>\n<\/ul>\n\n<h4>1.4<\/h4>\n\n<ul>\n<li>Added setting to use a random delay between 1 and 5 seconds<\/li>\n<\/ul>\n\n<h4>1.3.1<\/h4>\n\n<ul>\n<li>Added support until WordPress 4.8.2<\/li>\n<\/ul>\n\n<h4>1.3<\/h4>\n\n<ul>\n<li>Wrong SVN commands to push plugin update to WordPress repository<\/li>\n<\/ul>\n\n<h4>1.2<\/h4>\n\n<ul>\n<li>Fixed the invalid header issue after installation<\/li>\n<\/ul>\n\n<h4>1.1<\/h4>\n\n<ul>\n<li>Updated the readme file for Wordpress 3.8<\/li>\n<li>Renamed a function of the plugin to avoid conflict with WooCommerce plugin<\/li>\n<li>Added a setting under \"Settings &gt; Login Delay Shield\" to set the delay time in seconds (the default value is one second)<\/li>\n<\/ul>\n\n<h4>1.0<\/h4>\n\n<ul>\n<li>First version of the plugin<\/li>\n<\/ul>","raw_excerpt":"Login Delay Shield slows down brute-force attacks by adding a configurable delay to failed login attempts while keeping successful logins instant.","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/srd.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin\/24769","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/srd.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin"}],"about":[{"href":"https:\/\/srd.wordpress.org\/plugins\/wp-json\/wp\/v2\/types\/plugin"}],"replies":[{"embeddable":true,"href":"https:\/\/srd.wordpress.org\/plugins\/wp-json\/wp\/v2\/comments?post=24769"}],"author":[{"embeddable":true,"href":"https:\/\/srd.wordpress.org\/plugins\/wp-json\/wporg\/v1\/users\/michaeldamoiseau"}],"wp:attachment":[{"href":"https:\/\/srd.wordpress.org\/plugins\/wp-json\/wp\/v2\/media?parent=24769"}],"wp:term":[{"taxonomy":"plugin_section","embeddable":true,"href":"https:\/\/srd.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_section?post=24769"},{"taxonomy":"plugin_tags","embeddable":true,"href":"https:\/\/srd.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_tags?post=24769"},{"taxonomy":"plugin_category","embeddable":true,"href":"https:\/\/srd.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_category?post=24769"},{"taxonomy":"plugin_contributors","embeddable":true,"href":"https:\/\/srd.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_contributors?post=24769"},{"taxonomy":"plugin_business_model","embeddable":true,"href":"https:\/\/srd.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_business_model?post=24769"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}