← Login Delay Shield Docs

Developer Reference

Hooks, public functions, database schema, transient keys, and internals for Login Delay Shield v2.2.3.

Architecture

Login Delay Shield is a single-plugin WordPress security plugin with four files:

FilePurpose
wp-login-delay.phpMain plugin file — all security logic, hooks, database management, dashboard widget
wldelay-settings.phpSettings registration via WordPress Settings API, sanitization, validation
wldelay-settings-view.phpLDS_Settings_View class — admin UI rendering (collapsible sections, status badges, summary box)
admin.jsAdmin JavaScript — collapsible sections, tooltips, and UI interactions
admin.cssAdmin styles for the settings page and dashboard widget

The plugin uses WordPress transients for tracking failed attempts and lockout state, and a custom database table for the failed login log. Custom Login URL uses WordPress rewrite rules. No custom REST API endpoints or post types are registered.

Constants

ConstantValueDescription
WLDELAY_VERSION'2.2.3'Plugin version
WLDELAY_PLUGIN_FILE__FILE__Main plugin file path
WLDELAY_OPTION_NAME'wldelay_options'WordPress option name for all settings

Filter Hooks

wp_authenticate_user

filter · priority 1

Main authentication filter. Applies delays and lockouts to login attempts. Parameters: $user (WP_User|WP_Error), $password. Returns WP_Error if locked out, otherwise applies sleep() delay on failure and returns $user.

rest_authentication_errors

filter · priority 20

REST API authentication protection. Applies delays and lockout to failed REST API authentication when wldelay_rest_enabled is on. Returns a 403 WP_Error if the IP is locked out. Respects the IP whitelist and skips application-password attempts (handled separately). Since v2.1.2.

authenticate

filter · priority 25

Application-password authentication protection. Applies delays and lockout to failed Basic Auth attempts when wldelay_application_password_enabled is on. Detects app-password attempts via PHP_AUTH_USER/PHP_AUTH_PW server headers. Parameters: $user, $username, $password. Since v2.1.2.

authenticate

filter · priority 99

Blocks XML-RPC authentication when the “block XML-RPC” setting is enabled. Parameters: $user, $username, $password. Returns WP_Error('wldelay_xmlrpc_blocked') for XML-RPC requests.

wldelay_2fa_providers

filter

Customize the list of recognized 2FA plugins for the settings-page health check. Receives an associative array of slug => [ plugin_basename, … ]. Return the modified array to add or remove providers. The default map includes two-factor, wp-2fa, mini-orange, and google-authenticator. Since v2.1.4.

wldelay_export_login_log_should_exit

filter

Controls whether the CSV export handler calls exit() after streaming. Default true. Set to false in test environments. Since v2.1.2.

plugin_action_links_{basename}

filter

Adds a “Settings” link to the plugin’s entry on the Plugins page.

Action Hooks

wp_login_failed

action

Hooked to log failed login attempts to the database. Parameters: $username. Records the IP address, username, timestamp, and source (wp-login, xmlrpc, rest, or application-password).

wldelay_cleanup_logs

action · custom

Custom cron hook that runs daily. Deletes log entries older than the configured retention period. Processes in batches of 1,000 rows.

wp_dashboard_setup

action

Registers the “Recent Failed Login Attempts” dashboard widget.

admin_post_wldelay_unlock_current_ip

action

Handles the “Unlock Current IP” button on the settings page. Removes the lockout and failure counters for the requesting admin’s IP address. Nonce-protected and requires manage_options capability.

admin_post_wldelay_export_login_log

action

Handles CSV export of the failed login log. Streams results in 1,000-row batches with formula-injection protection. Reads optional filters from $_GET (source, IP, username, date range). Nonce-protected and requires manage_options capability. Since v2.1.2.

Error Codes

Error CodeContextDescription
wldelay_ip_lockedLogin formIP or IP+username is locked out. Message includes a countdown.
wldelay_xmlrpc_blockedXML-RPCXML-RPC authentication is disabled on this site.
wldelay_attempts_remainingLogin formShows remaining attempts before lockout (appended to existing error).

Core Functions

FunctionReturnsDescription
wldelay_get_options()arrayGet cached plugin options. Uses a global cache to avoid repeated get_option() calls.
wldelay_clear_options_cache()voidClear the in-memory options cache. Called automatically when settings are updated.
wldelay_get_delay_value( $failure_count )intCalculate the delay in seconds based on current settings (fixed, random, or progressive) and the number of failures.
wldelay_get_client_ip()stringGet the client IP address. Checks proxy headers only if wldelay_trust_proxy_headers is enabled.
wldelay_get_lockout_attempt_strategy( $options )stringReturns 'ip' or 'ip_username'.
wldelay_normalize_username( $username )stringLowercases and sanitizes a username for consistent tracking.
wldelay_get_attempt_identifier( $ip, $username, $options )stringReturns $ip or $ip|$username based on strategy.
wldelay_get_requested_login_username()stringGets the normalized username from $_POST['log'].
wldelay_is_xmlrpc_request()boolChecks XMLRPC_REQUEST constant and REQUEST_URI.
wldelay_is_rest_request()boolChecks if the current request is a WordPress REST API request. Since v2.1.2.
wldelay_is_application_password_attempt()boolChecks for PHP_AUTH_USER and PHP_AUTH_PW server headers (Basic Auth). Since v2.1.2.
wldelay_get_login_source()stringReturns 'xmlrpc', 'rest', 'application-password', or 'wp-login'.
wldelay_custom_login_is_active()boolWhether the Custom Login URL feature is enabled and the slug is valid. Since v2.2.3.
wldelay_get_custom_login_slug()stringReturns the configured custom login slug (default 'my-login'). Since v2.2.3.

Lockout Functions

FunctionReturnsDescription
wldelay_is_ip_locked( $ip, $username )boolCheck if an IP (or IP+username) is currently locked out.
wldelay_lock_ip( $ip, $username )voidLock an IP/username. Sets a transient with the lockout duration.
wldelay_get_failure_count( $ip, $username )intGet the current failure count for an IP/username.
wldelay_get_lockout_remaining_seconds( $ip, $username )intSeconds remaining on a lockout (0 if not locked).
wldelay_get_lockout_duration_seconds( $options )intGet the configured lockout duration in seconds.
wldelay_get_lockout_error_message( $ip, $username )stringBuild the lockout error message with human-readable countdown.
wldelay_track_failed_attempt( $username )intIncrement failure counter, trigger lockout and/or email if thresholds are met.
wldelay_send_notification_email( $ip, $username, $attempts )voidSend email alert (respects site-wide cooldown).

Whitelist Functions

FunctionReturnsDescription
wldelay_is_ip_whitelisted( $ip )boolCheck if an IP is in the whitelist. Returns false if whitelist is disabled.
wldelay_ip_in_range( $ip, $range )boolCheck if an IP matches a single address or CIDR range. Supports both IPv4 and IPv6.

Recovery Functions

FunctionReturnsDescription
wldelay_delete_lockout_for_ip( $ip )intRemove all lockout and failure transients for a specific IP. Returns the count of removed entries. Cleans up both ip and ip_username strategy keys.
wldelay_flush_lockout_transients()intClear all lockout and failure transients site-wide. Uses the transient registry and falls back to a database scan. Returns total entries removed.
wldelay_register_transient_key( $key )voidAdd a transient key to the registry (wldelay_transient_registry option). Called automatically when failure/lockout transients are created.
wldelay_unregister_transient_key( $key )voidRemove a transient key from the registry. Called automatically during cleanup.

Database Functions

FunctionReturnsDescription
wldelay_get_log_table_name()stringReturns the full table name: {$wpdb->prefix}wldelay_login_log.
wldelay_create_log_table()voidCreates or upgrades the log table using dbDelta(). Called on activation and version upgrades.
wldelay_log_failed_attempt( $ip, $username, $source )voidInserts a row into the log table and invalidates the dashboard cache.
wldelay_get_recent_failed_attempts( $limit )arrayReturns recent failed attempts ordered by time (used by the dashboard widget).
wldelay_cleanup_old_logs()voidDeletes entries older than the retention period in batches of 1,000.

Export & Log Query Functions

Added in v2.1.2–2.2.3 for CSV export, filtered log queries, and trend analytics.

FunctionReturnsDescription
wldelay_get_login_log_attempts( $limit, $offset, $filters )arrayQuery log entries with optional filters (source, IP, username, date range) and pagination. All filters are applied at the SQL level.
wldelay_get_export_login_log_url( $filters )stringBuild a nonce-protected URL for the CSV export endpoint. Accepts optional filter array.
wldelay_handle_export_login_log()voidMain CSV export handler. Streams results in 1,000-row batches with flush() after each batch. Sets Content-Type: text/csv and Content-Disposition: attachment headers.
wldelay_sanitize_login_log_filters( $filters )arrayValidate and sanitize filter input. Checks IP format, date format (Y-m-d), and auto-swaps reversed date ranges.
wldelay_get_login_log_filters_from_request()arrayExtract filters from $_GET using expected keys only (wldelay_log_source, wldelay_log_ip, wldelay_log_username, wldelay_log_from, wldelay_log_to).
wldelay_csv_sanitize_cell( $value )stringMitigate CSV formula injection by prepending a single quote to values starting with =, +, -, @, or whitespace.
wldelay_get_top_ips( $days, $limit )arrayReturns the top attacking IP addresses over the last $days days (default 7), limited to $limit results (default 10). Each row has ip_address and attempt_count. Since v2.2.3.
wldelay_get_top_usernames( $days, $limit )arrayReturns the most targeted usernames over the last $days days (default 7), limited to $limit results (default 10). Each row has username and attempt_count. Since v2.2.3.
wldelay_get_daily_attempts( $days )arrayReturns daily failed attempt totals for the last $days days (default 7). Each row has day (Y-m-d) and attempt_count. Since v2.2.3.

Database Schema

{$wpdb->prefix}wldelay_login_log

ColumnTypeKeyDescription
idbigint(20) unsignedPRIMARYAuto-increment ID
ip_addressvarchar(45)INDEXIP address (supports IPv4 and IPv6)
usernamevarchar(60)Username attempted
attempted_atdatetimeINDEXTimestamp of the attempt
sourcevarchar(20)INDEXwp-login, xmlrpc, rest, or application-password

Created on plugin activation via dbDelta(). Schema version is tracked in the wldelay_db_version option.

Transient Keys

All transient keys use MD5 hashing of the attempt identifier for security (prevents enumeration).

Key PatternTTLValueDescription
wldelay_fails_{md5(id)}1 hourint (count)Failed attempt counter per IP or IP+username
wldelay_lockout_{md5(id)}Lockout durationint (timestamp)Lockout start time per IP or IP+username
wldelay_email_cooldownCooldown minutesint (timestamp)Site-wide email rate limiter
wldelay_dashboard_attempts2 minutesarrayCached dashboard widget data

The id in failure and lockout keys is the attempt identifier: either the IP address (ip strategy) or IP|username (ip_username strategy).

Options Reference

All settings are stored in a single serialized array under the wldelay_options WordPress option.

KeyTypeDefaultDescription
wldelay_delayint1Fixed delay in seconds (0–10)
wldelay_delay_randomboolfalseUse random delay
wldelay_delay_random_minint1Min random delay (1–10)
wldelay_delay_random_maxint5Max random delay (1–10)
wldelay_progressive_enabledboolfalseEnable progressive delay
wldelay_progressive_incrementint1Increment per attempt (1–10)
wldelay_progressive_maxint30Max progressive delay (5–60)
wldelay_email_enabledboolfalseEnable email notifications
wldelay_email_thresholdint5Failures before email (1–100)
wldelay_email_addressstring''Notification email (fallback: admin_email)
wldelay_email_cooldownint5Minutes between emails (0–60)
wldelay_lockout_enabledboolfalseEnable IP lockout
wldelay_lockout_thresholdint10Failures before lockout (1–100)
wldelay_lockout_durationint60Lockout duration in minutes (1–1440)
wldelay_lockout_attempt_strategystring'ip''ip' or 'ip_username'
wldelay_trust_proxy_headersboolfalseTrust X-Forwarded-For headers
wldelay_whitelist_enabledboolfalseEnable IP whitelist
wldelay_whitelist_ipsstring''Newline-separated IPs/CIDR ranges
wldelay_log_retention_daysint30Log retention in days (0–365, 0 = forever)
wldelay_xmlrpc_enabledboolfalseEnable XML-RPC protection
wldelay_xmlrpc_blockboolfalseBlock all XML-RPC auth
wldelay_rest_enabledbooltrueEnable REST API protection (v2.1.2+)
wldelay_application_password_enabledbooltrueEnable application-password protection (v2.1.2+)
wldelay_custom_login_enabledboolfalseEnable custom login URL (v2.2.3+)
wldelay_custom_login_slugstring'my-login'Custom login URL slug (lowercase, numbers, hyphens only) (v2.2.3+)

Other WordPress Options

Option NameDescription
wldelay_db_versionDatabase schema version (tracks WLDELAY_VERSION)
wldelay_plugin_versionCurrent plugin version
wldelay_previous_versionPrevious version (for upgrade detection)
wldelay_name_change_notice_dismissedWhether the rename notice was dismissed
wldelay_transient_registryArray of active transient keys (used by flush-lockouts for cleanup)

Cron Jobs

HookScheduleFunctionDescription
wldelay_cleanup_logsDailywldelay_cleanup_old_logs()Deletes log entries older than the retention period. Processes in batches of 1,000 to avoid table locks. Scheduled on wp hook, unscheduled on deactivation.

WP-CLI

Login Delay Shield registers commands under the login-delay-shield namespace. Available when WP-CLI is installed.

CommandArgumentsDescription
wp login-delay-shield unlock-ip <ip><ip> — IPv4 or IPv6 addressRemoves lockout and failure transients for the specified IP. Validates IP format. Returns count of removed entries.
wp login-delay-shield flush-lockoutsClears all lockout and failure transients site-wide. Uses the transient registry and falls back to a database scan. Also clears the registry itself.