Tutorials

WordPress Security Monitoring Best Practices: Complete Guide

Learn essential WordPress security monitoring practices including log analysis, alerting, real-time detection, and incident response.

S
Sarah Chen
10 min read
2,801 views
Comprehensive WordPress security monitoring guide

Effective security monitoring helps detect threats early, respond quickly to incidents, and maintain ongoing site protection. This guide covers essential monitoring practices for WordPress sites.

Security Monitoring Fundamentals

Comprehensive monitoring covers:

  • Login attempts and authentication
  • File system changes
  • Database modifications
  • User activity tracking
  • Network traffic patterns
  • Error and exception logging

Login Activity Monitoring

Track all authentication events:

// Log successful logins
add_action('wp_login', function($username, $user) {
    log_security_event(array(
        'type' => 'login_success',
        'user_id' => $user->ID,
        'username' => $username,
        'ip' => $_SERVER['REMOTE_ADDR'],
        'user_agent' => $_SERVER['HTTP_USER_AGENT'] ?? 'Unknown',
        'time' => current_time('mysql'),
    ));

    // Check for suspicious patterns
    check_login_anomalies($user->ID, $_SERVER['REMOTE_ADDR']);
}, 10, 2);

// Log failed logins
add_action('wp_login_failed', function($username) {
    log_security_event(array(
        'type' => 'login_failed',
        'username' => $username,
        'ip' => $_SERVER['REMOTE_ADDR'],
        'user_agent' => $_SERVER['HTTP_USER_AGENT'] ?? 'Unknown',
        'time' => current_time('mysql'),
    ));

    // Check for brute force
    check_brute_force($_SERVER['REMOTE_ADDR'], $username);
});

function check_login_anomalies($user_id, $ip) {
    // Check if new location
    $known_ips = get_user_meta($user_id, 'known_login_ips', true) ?: array();

    if (!in_array($ip, $known_ips)) {
        // Alert user about new location
        $user = get_user_by('id', $user_id);
        wp_mail(
            $user->user_email,
            'New login location detected',
            sprintf('Your account was accessed from IP: %s', $ip)
        );

        // Add to known IPs
        $known_ips[] = $ip;
        update_user_meta($user_id, 'known_login_ips', array_slice($known_ips, -10));
    }
}

File Integrity Monitoring

Detect unauthorized file changes with these monitoring steps:

  • Define paths to monitor - Include wp-config.php, .htaccess, wp-includes, wp-admin, plugins, and theme directories
  • Generate file hashes - Create MD5 hashes for all PHP files in monitored directories
  • Compare with baseline - Check current hashes against stored hashes from previous scan
  • Detect changes - Identify added, modified, or deleted files
  • Alert on changes - Send notifications when unauthorized modifications are detected
  • Update baseline - Store new hashes after each scan for future comparison
  • Schedule scans - Run hourly integrity checks using WordPress cron

Database Activity Logging

Track critical database changes:

// Log option changes
add_action('updated_option', function($option, $old_value, $value) {
    $sensitive_options = array(
        'admin_email',
        'users_can_register',
        'default_role',
        'siteurl',
        'home',
    );

    if (in_array($option, $sensitive_options)) {
        log_security_event(array(
            'type' => 'option_changed',
            'option' => $option,
            'old_value' => maybe_serialize($old_value),
            'new_value' => maybe_serialize($value),
            'user_id' => get_current_user_id(),
            'time' => current_time('mysql'),
        ));
    }
}, 10, 3);

// Log user role changes
add_action('set_user_role', function($user_id, $role, $old_roles) {
    log_security_event(array(
        'type' => 'role_changed',
        'user_id' => $user_id,
        'old_roles' => implode(', ', $old_roles),
        'new_role' => $role,
        'changed_by' => get_current_user_id(),
        'time' => current_time('mysql'),
    ));

    // Alert on admin role assignment
    if ($role === 'administrator') {
        wp_mail(
            get_option('admin_email'),
            'New administrator created',
            sprintf('User ID %d was granted administrator role', $user_id)
        );
    }
}, 10, 3);

Real-Time Alert System

Implement immediate alerting:

function send_security_alert($event_type, $details) {
    $alert_config = get_option('security_alert_config', array(
        'email' => get_option('admin_email'),
        'slack_webhook' => '',
        'severity_threshold' => 'medium',
    ));

    $severity_levels = array(
        'login_failed' => 'low',
        'login_success' => 'low',
        'file_modified' => 'high',
        'admin_created' => 'critical',
        'option_changed' => 'medium',
        'plugin_activated' => 'medium',
    );

    $event_severity = $severity_levels[$event_type] ?? 'low';

    // Check threshold
    $threshold_order = array('low' => 1, 'medium' => 2, 'high' => 3, 'critical' => 4);

    if ($threshold_order[$event_severity] < $threshold_order[$alert_config['severity_threshold']]) {
        return;
    }

    // Send email alert
    $subject = sprintf('[%s] Security Alert: %s', strtoupper($event_severity), $event_type);
    $message = format_alert_message($event_type, $details);

    wp_mail($alert_config['email'], $subject, $message);

    // Send Slack notification
    if (!empty($alert_config['slack_webhook'])) {
        wp_remote_post($alert_config['slack_webhook'], array(
            'body' => json_encode(array(
                'text' => $subject,
                'attachments' => array(
                    array(
                        'color' => get_severity_color($event_severity),
                        'text' => $message,
                    ),
                ),
            )),
            'headers' => array('Content-Type' => 'application/json'),
        ));
    }
}

Traffic Pattern Analysis

Detect unusual traffic patterns:

function analyze_traffic_patterns() {
    global $wpdb;

    // Get request counts by IP for last hour
    $ip_counts = $wpdb->get_results("
        SELECT ip_address, COUNT(*) as request_count
        FROM security_logs
        WHERE created_at > DATE_SUB(NOW(), INTERVAL 1 HOUR)
        GROUP BY ip_address
        HAVING request_count > 100
    ");

    foreach ($ip_counts as $ip_data) {
        send_security_alert('high_traffic', array(
            'ip' => $ip_data->ip_address,
            'requests' => $ip_data->request_count,
            'period' => '1 hour',
        ));

        // Auto-block if threshold exceeded
        if ($ip_data->request_count > 500) {
            block_ip($ip_data->ip_address, 'Automated block: excessive requests');
        }
    }

    // Check for 404 scanning
    $scan_attempts = $wpdb->get_results("
        SELECT ip_address, COUNT(*) as attempts
        FROM security_logs
        WHERE response_code = 404
        AND created_at > DATE_SUB(NOW(), INTERVAL 10 MINUTE)
        GROUP BY ip_address
        HAVING attempts > 20
    ");

    foreach ($scan_attempts as $scan) {
        send_security_alert('vulnerability_scan', array(
            'ip' => $scan->ip_address,
            '404_count' => $scan->attempts,
        ));
    }
}

Dashboard and Reporting

Create security overview dashboard:

function get_security_dashboard_data() {
    global $wpdb;

    $data = array(
        'failed_logins_24h' => $wpdb->get_var("
            SELECT COUNT(*) FROM security_logs
            WHERE type = 'login_failed'
            AND created_at > DATE_SUB(NOW(), INTERVAL 24 HOUR)
        "),

        'blocked_ips' => count(get_option('blocked_ips', array())),

        'file_changes_7d' => $wpdb->get_var("
            SELECT COUNT(*) FROM security_logs
            WHERE type = 'file_modified'
            AND created_at > DATE_SUB(NOW(), INTERVAL 7 DAY)
        "),

        'active_sessions' => count(wp_get_all_sessions(get_current_user_id())),

        'last_backup' => get_option('last_backup_time'),

        'security_score' => calculate_security_score(),
    );

    return $data;
}

function calculate_security_score() {
    $score = 100;

    // Deduct for issues
    if (!is_ssl()) {
        $score -= 20;
    }

    if (get_option('users_can_register')) {
        $score -= 10;
    }

    $failed_logins = get_failed_login_count_24h();
    if ($failed_logins > 50) {
        $score -= 15;
    }

    $outdated_plugins = count(get_outdated_plugins());
    $score -= min($outdated_plugins * 5, 25);

    return max(0, $score);
}

Log Retention and Cleanup

Manage log storage efficiently:

function cleanup_old_security_logs() {
    global $wpdb;

    // Keep detailed logs for 30 days
    $wpdb->query("
        DELETE FROM security_logs
        WHERE created_at < DATE_SUB(NOW(), INTERVAL 30 DAY)
        AND type NOT IN ('admin_created', 'file_modified', 'option_changed')
    ");

    // Keep critical logs for 1 year
    $wpdb->query("
        DELETE FROM security_logs
        WHERE created_at < DATE_SUB(NOW(), INTERVAL 1 YEAR)
    ");

    // Archive monthly summaries
    archive_monthly_stats();
}
add_action('wpfs_daily_cleanup', 'cleanup_old_security_logs');

Conclusion

Effective WordPress security monitoring combines login tracking, file integrity checks, database monitoring, real-time alerting, and traffic analysis. Regular review of security dashboards helps identify trends and potential threats early.

Share:
S
Written by Sarah Chen

WP Folder Shield Team

Related Articles

The Ultimate Guide to WordPress Security in 2026
The Ultimate Guide to WordPress Security in 2026

Learn how to protect your WordPress website from hackers, malware, and security threats with this...

January 15, 2026
How to Scan Your WordPress Site for SEO Spam and Hidden Malicious Content
How to Scan Your WordPress Site for SEO Spam and Hidden Malicious Content

Learn effective methods to scan your WordPress site for hidden SEO spam, malicious links, and...

January 13, 2026
How to Protect Your WordPress Uploads Folder from Malware
How to Protect Your WordPress Uploads Folder from Malware

The wp-content/uploads folder is one of the most vulnerable directories in WordPress. Learn how to...

January 13, 2026

Ready to Secure Your WordPress Site?

Get complete protection with WP Folder Shield.

Get Started