404 Not Found Tracking (plugin)

404 Not Found Tracking (plugin)

The idea of tracking 404 errors started from here (first posted by WP Mix). The problem is that the result of those tutorials is that you will receive an email for each 404 error, and that can be quite annoying.

So I created a plugin that saves the errors into a mySQL table and sends daily (hourly, twicedaily) email alerts using WordPress’ cron system. Save the code snippet below as nftracking.php and place it in your plugins folder:

/*
  Plugin Name: 404 Not Found Tracking
  Plugin URI: https://wpcrumbs.com/404-not-found-tracking-plugin/
  Description: Track every 404 not found page
  Version: 1.0
  Author: George Jipa
  Author URI: https://wpcrumbs.com
 */

class NFTracking {

    public $notification = 'daily'; // you can change with hourly or twicedaily
    public $tracking_table;
    public $wpdb;

    public function __construct() {
        global $wpdb;
        $this->wpdb = $wpdb;
        $this->tracking_table = $wpdb->prefix . 'nftracking';

        // activate / deactivate plugin
        register_activation_hook(__FILE__, array($this, 'activate_plugin'));
        register_deactivation_hook(__FILE__, array($this, 'deactivate_plugin'));

        // add tracking
        add_action('wp', array($this, 'tracking'));

        // add cron
        add_action('my_send_notifications', array($this, 'send_notifications'));
    }

    /**
     * Tracking
    */
    public function tracking() {
        if (!is_404()) {
            return;
        }

        // insert 404 information
        $insert = array(
            'data' => serialize(array(
                'referer' => isset($_SERVER['HTTP_REFERER']) ? sanitize_text_field($_SERVER['HTTP_REFERER']) : 'undefined',
                'request' => isset($_SERVER['REQUEST_URI']) && isset($_SERVER['HTTP_HOST']) ? sanitize_text_field('http://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']) : 'undefined',
                'query_string' => isset($_SERVER['QUERY_STRING']) ? sanitize_text_field($_SERVER['QUERY_STRING']) : 'undefined',
                'ip_address' => isset($_SERVER['REMOTE_ADDR']) ? sanitize_text_field($_SERVER['REMOTE_ADDR']) : 'undefined',
                'user_agent' => isset($_SERVER['HTTP_USER_AGENT']) ? sanitize_text_field($_SERVER['HTTP_USER_AGENT']) : 'undefined',
                'remote' => isset($_SERVER['REMOTE_IDENT']) ? sanitize_text_field($_SERVER['REMOTE_IDENT']) : 'undefined'
            )),
            'insert_date' => date('Y-m-d H:i:s')
        );

        $this->wpdb->insert($this->tracking_table, $insert, array('%s', '%s'));
    }

    /**
     * Triggered when plugin is activated
    */
    public function activate_plugin() {
        // create table
        $sql = "CREATE TABLE IF NOT EXISTS `{$this->tracking_table}` (
            `id` bigint(20) NOT NULL AUTO_INCREMENT,
            `data` text NOT NULL,
            `insert_date` datetime NOT NULL,
            PRIMARY KEY (`id`),
            KEY `insert_date` (`insert_date`)
        );";

        require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
        dbDelta($sql);

        // set cronjob event
        if (!wp_next_scheduled('my_send_notifications')) {
            wp_schedule_event(current_time('timestamp'), $this->notification, 'my_send_notifications');
        }
    }

    /**
     * Triggered when plugin is deactivated
    */
    public function deactivate_plugin() {
        // clear cronjob event
        wp_clear_scheduled_hook('my_send_notifications');

        // delete plugin options
        delete_option('nftracking_last_notification');
    }

    /**
     * Send email notifications
    */
    public function send_notifications() {
        // get last check time
        $last_notification = get_option('nftracking_last_notification', 0);

        // check if there are any errors in the database
        $errors = $this->wpdb->get_results($this->wpdb->prepare("SELECT * FROM {$this->tracking_table} WHERE insert_date >= %s", $last_notification), ARRAY_A);

        if (!empty($errors)) {
            ob_start();
            ?>
            <html>
                <body>
                    <table border='1'>
                        <tr>
                            <td>Time</td>
                            <td>404</td>
                            <td>Referrer</td>
                            <td>Query string</td>
                            <td>Remote address</td>
                            <td>Remote identity</td>
                            <td>User agent</td>
                        </tr>
                        <?php
                        foreach ($errors as $item) {
                        $data = unserialize($item['data']);
                        ?>
                        <tr>
                            <td><?php echo esc_html($item['insert_date']); ?></td>
                            <td><?php echo esc_html($data['request']); ?></td>
                            <td><?php echo esc_html($data['referer']); ?></td>
                            <td><?php echo esc_html($data['query_string']); ?></td>
                            <td><?php echo esc_html($data['ip_address']); ?></td>
                            <td><?php echo esc_html($data['remote']); ?></td>
                            <td><?php echo esc_html($data['user_agent']); ?></td>
                        </tr>
                        <?php
                        }
                        ?>
                    </table>
                </body>
            </html>
            <?php
            $message = ob_get_clean();
            $email = get_bloginfo('admin_email');
            $headers = array('From: ' . $email, 'Content-Type: text/html');

            // send message
            wp_mail($email, esc_html('404 Alerts: ' . get_bloginfo('name')), $message, $headers);
        }

        // update last check time
        update_option('nftracking_last_notification', date('Y-m-d H:i:s'));
    }
}

new NFTracking();

TO DO's:

1. Show the 404 errors in WordPress admin area too.
2. Clean the 404 errors table periodically.
2. Any ideas ?

Leave a Reply

Get our Wordpress
freebies to your inbox