prefix . 'arksp_activity_log' ); } /** * Get lockouts table name (escaped for safe use in queries). * * @return string */ public static function get_lockout_table() { global $wpdb; return esc_sql( $wpdb->prefix . 'arksp_lockouts' ); } /** * Plugin activation. */ public static function activate() { self::create_tables(); self::set_default_options(); // Store DB version. update_option( 'arksp_db_version', self::DB_VERSION ); // Clear rewrite rules for custom login URL. flush_rewrite_rules(); } /** * Check if database needs upgrading. */ public static function maybe_upgrade() { $current_version = get_option( 'arksp_db_version', '0' ); if ( version_compare( $current_version, self::DB_VERSION, '<' ) ) { self::create_tables(); update_option( 'arksp_db_version', self::DB_VERSION ); } } /** * Plugin deactivation. */ public static function deactivate() { // Clear scheduled events. wp_clear_scheduled_hook( 'arksp_daily_cleanup' ); // Flush rewrite rules. flush_rewrite_rules(); } /** * Create database tables. */ public static function create_tables() { global $wpdb; $charset_collate = $wpdb->get_charset_collate(); $log_table = self::get_log_table(); $lockout_table = self::get_lockout_table(); // Activity log table. $sql_log = "CREATE TABLE {$log_table} ( id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT, event_type varchar(50) NOT NULL, ip_address varchar(45) NOT NULL, username varchar(60) DEFAULT NULL, user_agent varchar(255) DEFAULT NULL, country_code varchar(2) DEFAULT NULL, details text DEFAULT NULL, created_at datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), KEY event_type (event_type), KEY ip_address (ip_address), KEY created_at (created_at) ) {$charset_collate};"; // Lockouts table. // Note: lockout_until stores Unix timestamp as BIGINT for reliable comparisons. $sql_lockout = "CREATE TABLE {$lockout_table} ( id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT, ip_address varchar(45) NOT NULL, failed_attempts int(11) NOT NULL DEFAULT 0, lockout_until bigint(20) DEFAULT NULL, created_at datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (id), UNIQUE KEY ip_address (ip_address), KEY lockout_until (lockout_until) ) {$charset_collate};"; require_once ABSPATH . 'wp-admin/includes/upgrade.php'; dbDelta( $sql_log ); dbDelta( $sql_lockout ); } /** * Set default options on activation. */ private static function set_default_options() { $existing = get_option( 'arksp_settings', false ); if ( false === $existing ) { $defaults = ARKSP_Plugin::get_default_settings(); update_option( 'arksp_settings', $defaults ); } } /** * Uninstall plugin (called from uninstall.php). */ public static function uninstall() { global $wpdb; // Drop tables. // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.DirectDatabaseQuery.SchemaChange -- Uninstall cleanup. $wpdb->query( "DROP TABLE IF EXISTS {$wpdb->prefix}arksp_activity_log" ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.DirectDatabaseQuery.SchemaChange -- Uninstall cleanup. $wpdb->query( "DROP TABLE IF EXISTS {$wpdb->prefix}arksp_lockouts" ); // Delete options. delete_option( 'arksp_settings' ); delete_option( 'arksp_db_version' ); delete_option( 'arksp_malware_scan_results' ); delete_option( 'arksp_malware_last_scan' ); delete_option( 'arksp_malware_hashes' ); delete_option( 'arksp_malware_hashes_updated' ); delete_option( 'arksp_malware_scan_stats' ); delete_option( 'arksp_quarantined_files' ); delete_option( 'arksp_file_scan_results' ); delete_option( 'arksp_file_last_scan' ); delete_option( 'arksp_file_baseline' ); // Delete transients. delete_transient( 'arksp_geo_cache' ); } }