database = new Almaweb_Database(); $this->kpis = new Almaweb_Business_KPIs(); } /** * Rendre le dashboard ACTION-DRIVEN */ public function render() { // 1. Charger toutes les données en premier (pas de nonce car lecture seule) // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- View-only filter parameter $period = isset($_GET['period']) ? intval($_GET['period']) : 7; $all_kpis = $this->kpis->get_all_kpis($period); // 2. Préparer les données pour les graphiques $chart_data = [ 'familyData' => $this->prepare_family_pie_data($period), 'intentionData' => $all_kpis['intention_breakdown'] ?? [], 'timelineData' => $this->prepare_intention_timeline_data($period), ]; // 3. Enqueue inline script pour les données des graphiques $inline_script = 'document.addEventListener("DOMContentLoaded", function() { var event = new CustomEvent("almawebAIVisitorAnalyticsDataLoaded", { detail: ' . wp_json_encode($chart_data) . ' }); document.dispatchEvent(event); });'; wp_add_inline_script('almaweb-ai-visitor-analytics-admin', $inline_script); ?>
database->get_visits_by_family($period); $labels = []; $data = []; // Palette de couleurs pour toutes les familles de bots $colors = [ // AI Companies 'OpenAI' => '#2271b1', 'Anthropic' => '#764ba2', 'Google' => '#00a32a', 'Meta' => '#0668e1', 'Amazon' => '#ff9900', 'Microsoft' => '#00a4ef', 'Perplexity' => '#8b5cf6', 'ByteDance' => '#ef4444', 'Mistral' => '#f97316', 'xAI' => '#06b6d4', 'DuckDuckGo' => '#de5833', // Search Engines & Crawlers 'Yandex' => '#ff0000', 'Baidu' => '#2319dc', 'Huawei' => '#cf0a2c', // Scrapers & SEO Tools 'Scrapers' => '#ec4899', 'SEO' => '#10b981', 'Data' => '#6366f1', 'Specialized' => '#a855f7', 'Tools' => '#14b8a6', // Social Media 'Apple' => '#555555', 'Discord' => '#5865f2', 'Telegram' => '#0088cc', // Generic & Unknown 'Generic' => '#94a3b8', 'Human' => '#cbd5e1', 'Inconnue' => '#94a3b8' ]; $background_colors = []; foreach ($visits_by_family as $family) { if ($family['visit_count'] > 0) { $labels[] = $family['bot_family']; $data[] = $family['visit_count']; $background_colors[] = $colors[$family['bot_family']] ?? '#646970'; } } return ['labels' => $labels, 'datasets' => [['data' => $data, 'backgroundColor' => $background_colors]]]; } private function prepare_intention_timeline_data($period) { global $wpdb; $table_name = $wpdb->prefix . 'ai_monitor_logs'; $date_limit = gmdate('Y-m-d H:i:s', strtotime("-{$period} days")); // Static SQL CASE statement - safe from injection $intention_case_sql = "CASE WHEN bot_intention IS NOT NULL AND bot_intention != '' THEN bot_intention WHEN bot_type = 'search_engine' THEN 'search' WHEN bot_type = 'scraper' THEN 'scraping' ELSE 'training' END"; // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- $intention_case_sql is a safe static CASE statement, $table_name from $wpdb->prefix $results = $wpdb->get_results($wpdb->prepare( "SELECT DATE(visited_at) as date, {$intention_case_sql} as intention_category, COUNT(*) as visit_count FROM {$table_name} WHERE visited_at >= %s AND is_ai_bot = 1 GROUP BY date, intention_category ORDER BY date ASC", $date_limit ), ARRAY_A); $data_by_date = []; foreach ($results as $row) { $date = $row['date']; if (!isset($data_by_date[$date])) { $data_by_date[$date] = ['inference' => 0, 'search' => 0, 'training' => 0, 'scraping' => 0]; } if (isset($data_by_date[$date][$row['intention_category']])) { $data_by_date[$date][$row['intention_category']] = (int) $row['visit_count']; } } $dates = []; $intentions_data = ['inference' => [], 'search' => [], 'training' => [], 'scraping' => []]; $start_date = new DateTime(gmdate('Y-m-d', strtotime("-{$period} days"))); $end_date = new DateTime(gmdate('Y-m-d')); $interval = new DateInterval('P1D'); $date_range = new DatePeriod($start_date, $interval, $end_date->modify('+1 day')); foreach ($date_range as $date) { $formatted_date = $date->format('Y-m-d'); $dates[] = $date->format('j M'); foreach ($intentions_data as $key => &$value) { $value[] = $data_by_date[$formatted_date][$key] ?? 0; } } return [ 'labels' => $dates, 'datasets' => [ ['label' => __('User responses', 'almaweb-ai-visitor-analytics'), 'data' => $intentions_data['inference'], 'backgroundColor' => 'rgba(16, 185, 129, 0.5)', 'borderColor' => '#10b981', 'fill' => 'origin', 'tension' => 0.4, 'pointRadius' => 0], ['label' => __('Indexing & search', 'almaweb-ai-visitor-analytics'), 'data' => $intentions_data['search'], 'backgroundColor' => 'rgba(59, 130, 246, 0.5)', 'borderColor' => '#3b82f6', 'fill' => '-1', 'tension' => 0.4, 'pointRadius' => 0], ['label' => __('Model training', 'almaweb-ai-visitor-analytics'), 'data' => $intentions_data['training'], 'backgroundColor' => 'rgba(245, 158, 11, 0.5)', 'borderColor' => '#f59e0b', 'fill' => '-1', 'tension' => 0.4, 'pointRadius' => 0], ['label' => __('Data collection', 'almaweb-ai-visitor-analytics'), 'data' => $intentions_data['scraping'], 'backgroundColor' => 'rgba(239, 68, 68, 0.5)', 'borderColor' => '#ef4444', 'fill' => '-1', 'tension' => 0.4, 'pointRadius' => 0], ] ]; } }