queries)) { return; } // Process each query foreach ($wpdb->queries as $query) { list($sql, $elapsed, $caller) = $query; $query_info = array( 'sql' => $sql, 'elapsed' => $elapsed, 'caller' => $caller, 'timestamp' => microtime(true), ); self::$queries_executed[] = $query_info; // Group by pattern $normalized = self::normalize_query($sql); if (!isset(self::$query_patterns[$normalized])) { self::$query_patterns[$normalized] = array( 'count' => 0, 'total_time' => 0, 'queries' => array(), ); } self::$query_patterns[$normalized]['count']++; self::$query_patterns[$normalized]['total_time'] += floatval($elapsed); self::$query_patterns[$normalized]['queries'][] = $query_info; } // Log statistics $total_queries = count($wpdb->queries); $total_time = array_sum(array_column($wpdb->queries, 1)); $slow_queries = self::get_slow_queries(); $n_plus_one = self::detect_n_plus_one(); if (class_exists('WP_Debug_Logger')) { WP_Debug_Logger::info('Query Analysis Complete', array( 'total_queries' => $total_queries, 'total_time' => round($total_time, 4) . 's', 'slow_queries' => count($slow_queries), 'n_plus_one_patterns' => count($n_plus_one), )); // Log slow queries foreach ($slow_queries as $query) { WP_Debug_Logger::warning('Slow Query Detected', array( 'elapsed' => round($query['elapsed'], 4) . 's', 'sql' => substr($query['sql'], 0, 200), 'caller' => $query['caller'], )); } // Log N+1 patterns foreach ($n_plus_one as $pattern) { WP_Debug_Logger::warning('N+1 Query Pattern Detected', array( 'count' => $pattern['count'], 'total_time' => round($pattern['total_time'], 4) . 's', 'example' => substr($pattern['example'], 0, 200), )); } } // Store for frontend panel set_transient('wp_debug_queries_data', array( 'total_queries' => $total_queries, 'total_time' => $total_time, 'queries' => self::$queries_executed, 'slow_queries' => $slow_queries, 'n_plus_one' => $n_plus_one, 'patterns' => self::$query_patterns, ), 3600); } /** * Normalize query for pattern detection * * @param string $query SQL query * @return string Normalized query */ private static function normalize_query($query) { // Remove numeric literals $query = preg_replace('/\b\d+\b/', '?', $query); // Remove string literals $query = preg_replace("/'[^']*'/", '?', $query); // Remove extra whitespace $query = preg_replace('/\s+/', ' ', $query); return trim($query); } /** * Detect N+1 query patterns * * @return array N+1 patterns */ public static function detect_n_plus_one() { $patterns = array(); // Find patterns executed 5+ times foreach (self::$query_patterns as $normalized => $pattern) { if ($pattern['count'] >= 5) { $patterns[] = array( 'count' => $pattern['count'], 'total_time' => $pattern['total_time'], 'avg_time' => $pattern['total_time'] / $pattern['count'], 'example' => $pattern['queries'][0]['sql'], 'normalized' => $normalized, ); } } // Sort by count descending usort($patterns, function($a, $b) { return $b['count'] - $a['count']; }); return $patterns; } /** * Get slow queries * * @param float $threshold Threshold in seconds * @return array Slow queries */ public static function get_slow_queries($threshold = 0.05) { return array_filter(self::$queries_executed, function($query) use ($threshold) { return floatval($query['elapsed']) > $threshold; }); } /** * Get queries by caller * * @param string $caller Caller filter * @return array Queries */ public static function get_queries_by_caller($caller) { return array_filter(self::$queries_executed, function($query) use ($caller) { return strpos($query['caller'], $caller) !== false; }); } /** * Get query statistics * * @return array Statistics */ public static function get_statistics() { global $wpdb; if (empty($wpdb->queries)) { return array( 'error' => 'SAVEQUERIES not enabled or no queries executed', ); } $total_queries = count($wpdb->queries); $total_time = array_sum(array_column($wpdb->queries, 1)); $avg_time = $total_time / $total_queries; return array( 'total_queries' => $total_queries, 'total_time' => $total_time, 'avg_time' => $avg_time, 'slow_queries' => count(self::get_slow_queries()), 'n_plus_one_patterns' => count(self::detect_n_plus_one()), 'unique_patterns' => count(self::$query_patterns), ); } /** * Get query report * * @return array Query report */ public static function get_query_report() { $stats = self::get_statistics(); $slow_queries = self::get_slow_queries(); $n_plus_one = self::detect_n_plus_one(); $suggestions = array(); // Suggestions based on analysis if (isset($stats['total_queries']) && $stats['total_queries'] > 100) { $suggestions[] = 'High number of queries detected (' . $stats['total_queries'] . '). Consider using object caching.'; } if (isset($stats['total_time']) && $stats['total_time'] > 1) { $suggestions[] = 'Total query time exceeds 1 second. Optimize slow queries.'; } if (!empty($n_plus_one)) { $suggestions[] = 'N+1 query patterns detected. Consider using WP_Query with proper parameters or caching.'; } if (!empty($slow_queries)) { $suggestions[] = count($slow_queries) . ' slow queries detected. Add indexes or optimize WHERE clauses.'; } return array( 'statistics' => $stats, 'slow_queries' => array_slice($slow_queries, 0, 10), 'n_plus_one_patterns' => array_slice($n_plus_one, 0, 5), 'suggestions' => $suggestions, ); } }