# Log 404 Errors Under Tools

> Records the addresses visitors request that do not exist, with hit counts, last seen time and referring page, and lists them under Tools > 404 Log so you can fix or redirect them.

- Type: PHP
- Runs: Run everywhere
- Category: [Redirects](https://wpide.com/library/category/redirects/)
- Tags: 404, logging, broken-links
- Author: WPIDE Team
- Installs: 0
- Updated: 2026-10-28
- Page: https://wpide.com/library/log-404-errors/

## Code

```php
add_action( 'template_redirect', function () {
    if ( ! is_404() ) {
        return;
    }

    $path = isset( $_SERVER['REQUEST_URI'] ) ? substr( sanitize_text_field( wp_unslash( $_SERVER['REQUEST_URI'] ) ), 0, 255 ) : '';

    if ( '' === $path ) {
        return;
    }

    $referrer = wp_get_raw_referer();
    $log      = get_option( 'wpide_404_log', array() );
    $log      = is_array( $log ) ? $log : array();
    $entry    = isset( $log[ $path ] ) ? $log[ $path ] : array( 'count' => 0, 'last' => 0, 'referrer' => '' );

    $entry['count']++;
    $entry['last'] = time();

    if ( $referrer ) {
        $entry['referrer'] = substr( esc_url_raw( $referrer ), 0, 255 );
    }

    $log[ $path ] = $entry;

    if ( count( $log ) > 200 ) {
        uasort( $log, function ( $a, $b ) {
            return $b['last'] <=> $a['last'];
        } );
        $log = array_slice( $log, 0, 200, true );
    }

    update_option( 'wpide_404_log', $log, false );
} );

add_action( 'admin_menu', function () {
    add_management_page( '404 Log', '404 Log', 'manage_options', 'wpide-404-log', function () {
        if ( isset( $_POST['wpide_clear_404_log'] ) && check_admin_referer( 'wpide_clear_404_log' ) ) {
            delete_option( 'wpide_404_log' );
            echo '<div class="notice notice-success"><p>The 404 log was cleared.</p></div>';
        }

        $log = get_option( 'wpide_404_log', array() );
        $log = is_array( $log ) ? $log : array();

        uasort( $log, function ( $a, $b ) {
            return $b['count'] <=> $a['count'];
        } );

        echo '<div class="wrap"><h1>404 Log</h1>';

        if ( ! $log ) {
            echo '<p>No missing pages recorded yet.</p></div>';
            return;
        }

        echo '<table class="widefat striped"><thead><tr><th>Address</th><th>Hits</th><th>Last seen</th><th>Referrer</th></tr></thead><tbody>';

        foreach ( $log as $path => $entry ) {
            echo '<tr><td><code>' . esc_html( $path ) . '</code></td><td>' . esc_html( number_format_i18n( (int) $entry['count'] ) ) . '</td><td>' . esc_html( human_time_diff( (int) $entry['last'] ) . ' ago' ) . '</td><td>' . ( $entry['referrer'] ? '<a href="' . esc_url( $entry['referrer'] ) . '" target="_blank" rel="noopener noreferrer">' . esc_html( $entry['referrer'] ) . '</a>' : '&mdash;' ) . '</td></tr>';
        }

        echo '</tbody></table><form method="post" style="margin-top:1em;">';
        wp_nonce_field( 'wpide_clear_404_log' );
        echo '<button type="submit" name="wpide_clear_404_log" value="1" class="button">Clear log</button></form></div>';
    } );
} );
```

## Notes

Keeps the 200 most recent distinct addresses in one option. Clear the log from the same screen.

## How to use it

Install the free WPIDE plugin (https://wordpress.org/plugins/wpide/), find "Log 404 Errors Under Tools" 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/
