Restrict wp-login.php Behind a Secret Key
Blocks direct access to wp-login.php unless a secret query parameter is present, so automated bots hitting the default login URL get redirected instead of a login form.
- Difficulty
- Intermediate
- Reading time
- ~1 min
- Where to add it
- A small custom plugin
- Last updated
The Problem
Every WordPress site has its login form at the same predictable path, /wp-login.php, which means automated bots don't need to discover anything about your specific site before starting a brute-force run — they already know exactly where to send requests. Renaming or fully hiding wp-login.php isn't realistically possible without a dedicated plugin, since core and many other plugins reference that filename directly. What is possible with a simple snippet is gating access to it: requiring a secret value in the URL before WordPress will even render the login form, so generic bots requesting the well-known path get turned away before authentication is ever attempted, while you access it via a URL only you know.
The Code
add_action( 'init', 'devmubs_guard_login_page' );
function devmubs_guard_login_page() {
$is_login_request = isset( $GLOBALS['pagenow'] ) && 'wp-login.php' === $GLOBALS['pagenow'];
if ( ! $is_login_request ) {
return;
}
$secret_key = 'change-this-to-your-own-secret'; // Set your own value.
if ( ! isset( $_GET['key'] ) || ! hash_equals( $secret_key, (string) $_GET['key'] ) ) {
wp_safe_redirect( home_url( '/' ) );
exit;
}
}How It Works
This runs on the `init` hook, which fires on every request, so the first thing the callback does is check `$GLOBALS['pagenow']` — a global WordPress sets to the current PHP file's basename — to confirm the request is actually for wp-login.php before doing anything else, so every other page on the site loads completely unaffected. If it is a login request, it checks for a `key` query parameter and compares it against your secret value using `hash_equals()`, which is a timing-attack-safe string comparison (a plain `===` comparison can theoretically leak information about how much of the string matched via response-time differences; `hash_equals()` avoids that). If the key is missing or wrong, `wp_safe_redirect()` sends the visitor to your homepage instead of showing a login form — a bot blindly requesting /wp-login.php with no key gets bounced immediately, before WordPress does any password checking at all.
Where To Add This
A small custom plugin. This isn't tied to your theme's presentation at all, and you'll want it to keep working across theme changes, so a small always-active plugin is the right home for it rather than functions.php.
Warnings & Caveats
- This is obscurity, not real access control — it stops generic, script-driven bots that only know the default URL, but does nothing against a targeted attacker who already knows or guesses your key.
- Anywhere your site links to wp-login.php directly (a theme's "Log In" link, a plugin's account menu, etc.) will break unless you update those links to include ?key=your-secret too, or additionally filter `login_url` to append it automatically.
- Bookmark your own login URL with the key included before you save this — locking yourself out of your own site is the most common mistake with this snippet.
- Always back up your site before adding custom code.