wp_login_failed
Fires when a user's login attempt fails due to incorrect username or password.
add_action( 'wp_login_failed', $callback, 10, 1 );
Description
Fires immediately after a login attempt has failed. This hook is useful for logging failed login attempts, implementing brute-force protection, or sending notifications when a user fails to log in. The `$user` parameter contains the username or user ID that was attempted.
Usage
add_action( 'wp_login_failed', 'your_function_name', 10, 1 );
Parameters
-
$user(mixed) - The `$user` parameter is a mixed type that can contain a `WP_User` object if the login attempt included a valid username, or a string containing the username that was attempted otherwise.
Examples
<?php
/**
* Log failed login attempts to a custom log file or external service.
*
* This function is triggered when a user fails to log in to WordPress.
* It captures the username (or email if that's what was used) and logs
* the event for security auditing or debugging purposes.
*
* @param string $user The username (or email) that was attempted for login.
*/
function my_custom_wp_login_failed_handler( $user ) {
// Ensure the log directory exists.
$upload_dir = wp_upload_dir();
$log_dir = trailingslashit( $upload_dir['basedir'] ) . 'login-attempts/';
if ( ! file_exists( $log_dir ) ) {
wp_mkdir_p( $log_dir );
}
$log_file = trailingslashit( $log_dir ) . 'failed-logins.log';
// Get current timestamp.
$timestamp = current_time( 'mysql' );
// Get the IP address of the user attempting to log in.
$ip_address = '';
if ( ! empty( $_SERVER['REMOTE_ADDR'] ) ) {
$ip_address = sanitize_text_field( wp_unslash( $_SERVER['REMOTE_ADDR'] ) );
}
// Format the log message.
$log_message = sprintf(
"[%s] Failed login attempt for user: '%s' from IP: %sn",
$timestamp,
sanitize_text_field( $user ),
$ip_address
);
// Append the log message to the file.
// Use FILE_APPEND and LOCK_EX for safe writing.
@file_put_contents( $log_file, $log_message, FILE_APPEND | LOCK_EX );
// You could also send an email notification to an administrator for critical events.
// For example:
/*
$admin_email = get_option( 'admin_email' );
if ( $admin_email ) {
wp_mail(
$admin_email,
sprintf( __( '[%s] Failed Login Attempt', 'your-text-domain' ), get_bloginfo( 'name' ) ),
sprintf(
__( 'A failed login attempt occurred for user "%s" from IP address %s at %s.', 'your-text-domain' ),
sanitize_text_field( $user ),
$ip_address,
$timestamp
)
);
}
*/
}
add_action( 'wp_login_failed', 'my_custom_wp_login_failed_handler', 10, 1 );
?>
Placement
This code should be placed in the functions.php file of your active theme, a custom plugin, or using a code snippets plugin.
Source Code
src/includes/two-factor/providers/wp-2fa/legacy/class-frontend-login-plus-2fa-2.6.php:370
src/includes/two-factor/providers/wp-2fa/legacy/class-frontend-login-plus-2fa-2-4.php:333
src/includes/two-factor/providers/wp-2fa/legacy/class-frontend-login-plus-2fa-2-5.php:332
exit;
}
// Backup Codes.
if ( 'backup_codes' === $provider && true !== Backup_Codes::validate_backup_codes( $user ) ) {
do_action( 'wp_login_failed', $user->user_login );
$login_nonce = $this->two_factor::create_login_nonce( $user->ID );
if ( ! $login_nonce ) {
wp_die( esc_html__( 'Failed to create a login nonce.', 'uncanny-learndash-toolkit' ) );
}