Skip to content

Early-bird lifetime licence: $199 once, for the first 200 buyers only. See the offer

Limit login attempts

After 5 failed logins from the same IP address in 15 minutes, that address has to wait 15 minutes before trying again. Slows down password guessing.

  • Type PHP
  • Runs Everywhere (runs as WordPress loads)
  • Category Login
  • Tested with WordPress 7.1
PHP
<?php

// Change these three numbers to suit your site.
$snipfire_limit  = 5;                        // Failed attempts allowed…
$snipfire_window = 15 * MINUTE_IN_SECONDS;   // …within this time…
$snipfire_key    = static function () {
	// REMOTE_ADDR: behind Cloudflare or a proxy, make sure your host passes the visitor's real IP.
	$ip = isset( $_SERVER['REMOTE_ADDR'] ) ? sanitize_text_field( wp_unslash( $_SERVER['REMOTE_ADDR'] ) ) : '';
	return 'snipfire_login_' . md5( $ip );
};

add_action(
	'wp_login_failed',
	static function () use ( $snipfire_key, $snipfire_window ) {
		$key = $snipfire_key();
		set_transient( $key, (int) get_transient( $key ) + 1, $snipfire_window );
	}
);

add_filter(
	'authenticate',
	static function ( $user ) use ( $snipfire_key, $snipfire_limit ) {
		if ( (int) get_transient( $snipfire_key() ) >= $snipfire_limit ) {
			return new WP_Error( 'snipfire_locked', __( '<strong>Error:</strong> Too many failed login attempts. Please try again in 15 minutes.' ) );
		}
		return $user;
	},
	99
);

add_action(
	'wp_login',
	static function () use ( $snipfire_key ) {
		delete_transient( $snipfire_key() );
	}
);

Good to know

The wait starts over with each new failed attempt. A security plugin or your host’s firewall does this more thoroughly; this is a light, no-plugin version.

In these packs

Move your snippets over this afternoon.

Importing changes nothing until you switch over, and your old shortcodes keep working.