Tutorials

WordPress Security Logging: Best Practices and Implementation

Implement comprehensive security logging in WordPress to detect threats, investigate incidents, and meet compliance requirements.

S
Sarah Chen
8 min read
2,315 views
Best practices for WordPress security logging implementation

Introduction

Security logging is essential for detecting attacks, investigating breaches, and meeting compliance requirements. Proper logging captures security-relevant events without overwhelming your storage or impacting performance.

What to Log for Security

Focus logging on security-critical events:

  • Authentication - Successful and failed logins, password resets
  • Authorization - Permission changes, role modifications
  • Data access - Sensitive data views and exports
  • Configuration changes - Settings modifications, plugin changes
  • Error conditions - Security-related errors and exceptions
  • Administrative actions - User management, content deletion

Building a Security Logger

Create a comprehensive logging system:

Logger Class

class WPFS_Security_Logger {
    private static $instance = null;
    private $table_name;

    public static function get_instance() {
        if (self::$instance === null) {
            self::$instance = new self();
        }
        return self::$instance;
    }

    private function __construct() {
        global $wpdb;
        $this->table_name = $wpdb->prefix . 'security_logs';
    }

    public function log($event_type, $message, $data = array()) {
        global $wpdb;

        $log_entry = array(
            'event_type' => sanitize_key($event_type),
            'message' => sanitize_text_field($message),
            'user_id' => get_current_user_id(),
            'user_ip' => $this->get_client_ip(),
            'user_agent' => substr($_SERVER['HTTP_USER_AGENT'] ?? '', 0, 255),
            'request_uri' => substr($_SERVER['REQUEST_URI'] ?? '', 0, 255),
            'request_method' => $_SERVER['REQUEST_METHOD'] ?? '',
            'event_data' => wp_json_encode($data),
            'created_at' => current_time('mysql'),
        );

        $wpdb->insert($this->table_name, $log_entry);

        // Alert on critical events
        if ($this->is_critical_event($event_type)) {
            $this->send_alert($log_entry);
        }
    }

    private function get_client_ip() {
        $ip = $_SERVER['REMOTE_ADDR'] ?? 'unknown';
        return filter_var($ip, FILTER_VALIDATE_IP) ? $ip : 'invalid';
    }

    private function is_critical_event($type) {
        $critical = array(
            'brute_force_detected',
            'admin_login_failed',
            'malware_detected',
            'file_modified',
            'settings_changed',
        );
        return in_array($type, $critical);
    }
}

Logging Authentication Events

// Log successful logins
add_action('wp_login', function($user_login, $user) {
    $logger = WPFS_Security_Logger::get_instance();
    $logger->log('login_success', "User logged in: {$user_login}", array(
        'user_id' => $user->ID,
        'roles' => $user->roles,
    ));
}, 10, 2);

// Log failed logins
add_action('wp_login_failed', function($username) {
    $logger = WPFS_Security_Logger::get_instance();
    $logger->log('login_failed', "Failed login attempt: {$username}", array(
        'username_attempted' => $username,
        'username_exists' => username_exists($username) ? true : false,
    ));
});

// Log password resets
add_action('password_reset', function($user, $new_pass) {
    $logger = WPFS_Security_Logger::get_instance();
    $logger->log('password_reset', "Password reset for: {$user->user_login}", array(
        'user_id' => $user->ID,
    ));
}, 10, 2);

Logging Administrative Actions

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

    if (in_array($option, $sensitive_options)) {
        $logger = WPFS_Security_Logger::get_instance();
        $logger->log('option_changed', "Option modified: {$option}", array(
            'option_name' => $option,
            'old_value' => is_string($old_value) ? substr($old_value, 0, 100) : 'complex',
            'new_value' => is_string($value) ? substr($value, 0, 100) : 'complex',
        ));
    }
}, 10, 3);

// Log user role changes
add_action('set_user_role', function($user_id, $role, $old_roles) {
    $logger = WPFS_Security_Logger::get_instance();
    $logger->log('role_changed', "User role modified", array(
        'affected_user' => $user_id,
        'new_role' => $role,
        'old_roles' => $old_roles,
    ));
}, 10, 3);

Log Rotation and Retention

Manage log storage efficiently:

// Daily log cleanup
add_action('wpfs_daily_cleanup', function() {
    global $wpdb;
    $table = $wpdb->prefix . 'security_logs';

    // Keep 90 days of logs
    $retention_days = 90;
    $cutoff = date('Y-m-d', strtotime("-{$retention_days} days"));

    $wpdb->query($wpdb->prepare(
        "DELETE FROM {$table} WHERE created_at < %s",
        $cutoff
    ));

    // Archive critical events longer
    // Export to external storage if needed
});

// Schedule cleanup
if (!wp_next_scheduled('wpfs_daily_cleanup')) {
    wp_schedule_event(time(), 'daily', 'wpfs_daily_cleanup');
}

Log Analysis and Alerting

Extract security insights from logs:

// Detect brute force patterns
function analyze_login_patterns() {
    global $wpdb;
    $table = $wpdb->prefix . 'security_logs';

    // Failed logins per IP in last hour
    $results = $wpdb->get_results("
        SELECT user_ip, COUNT(*) as attempts
        FROM {$table}
        WHERE event_type = 'login_failed'
        AND created_at > DATE_SUB(NOW(), INTERVAL 1 HOUR)
        GROUP BY user_ip
        HAVING attempts > 5
    ");

    foreach ($results as $row) {
        // Block IP or send alert
        $logger = WPFS_Security_Logger::get_instance();
        $logger->log('brute_force_detected', "Potential brute force from {$row->user_ip}", array(
            'attempts' => $row->attempts,
            'ip' => $row->user_ip,
        ));
    }
}

Compliance Considerations

  • GDPR: Anonymize personal data in logs after retention period
  • PCI DSS: Log all access to cardholder data
  • HIPAA: Maintain audit trails for 6 years minimum
  • SOC 2: Demonstrate security monitoring practices

Conclusion

Comprehensive security logging provides visibility into your WordPress security posture. Log authentication, authorization, and administrative events while managing storage through rotation and retention policies.

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