# Log Failed Logins

> Keeps a log of the last 200 failed login attempts with username, IP address and time, viewable under Tools > Failed Logins.

- Type: PHP
- Runs: Run everywhere
- Category: [Security](https://wpide.com/library/category/security/)
- Tags: security, login, logging
- Author: WPIDE Team
- Installs: 0
- Updated: 2026-10-28
- Page: https://wpide.com/library/log-failed-logins/

## Code

```php
// How many entries to keep.
$wpide_failed_log_max = 200;

add_action( 'wp_login_failed', function ( $username ) use ( $wpide_failed_log_max ) {
    $log   = get_option( 'wpide_failed_logins', array() );
    $log   = is_array( $log ) ? $log : array();
    $log[] = array(
        'time' => time(),
        'user' => substr( sanitize_user( (string) $username ), 0, 60 ),
        'ip'   => isset( $_SERVER['REMOTE_ADDR'] ) ? sanitize_text_field( wp_unslash( $_SERVER['REMOTE_ADDR'] ) ) : '',
    );

    update_option( 'wpide_failed_logins', array_slice( $log, -$wpide_failed_log_max ), false );
} );

add_action( 'admin_menu', function () {
    add_management_page( 'Failed Logins', 'Failed Logins', 'manage_options', 'wpide-failed-logins', function () {
        if ( isset( $_POST['wpide_clear_failed'] ) && check_admin_referer( 'wpide_clear_failed' ) ) {
            delete_option( 'wpide_failed_logins' );
        }

        $log = array_reverse( (array) get_option( 'wpide_failed_logins', array() ) );
        echo '<div class="wrap"><h1>Failed Logins</h1>';
        echo '<form method="post">';
        wp_nonce_field( 'wpide_clear_failed' );
        echo '<p><button class="button" name="wpide_clear_failed" value="1">Clear log</button></p></form>';
        echo '<table class="widefat striped"><thead><tr><th>Time</th><th>Username tried</th><th>IP address</th></tr></thead><tbody>';
        if ( ! $log ) {
            echo '<tr><td colspan="3">No failed logins recorded.</td></tr>';
        }
        foreach ( $log as $row ) {
            printf(
                '<tr><td>%1$s</td><td>%2$s</td><td><code>%3$s</code></td></tr>',
                esc_html( wp_date( 'Y-m-d H:i:s', (int) $row['time'] ) ),
                esc_html( $row['user'] ),
                esc_html( $row['ip'] )
            );
        }
        echo '</tbody></table></div>';
    } );
} );
```

## Notes

The log is stored in the wpide_failed_logins option (not autoloaded).

## How to use it

Install the free WPIDE plugin (https://wordpress.org/plugins/wpide/), find "Log Failed Logins" in its snippet library and add it in one click; or create a new PHP snippet in WPIDE (or any code snippets plugin) and paste the code above. More snippets: https://wpide.com/library/
