By Devport Team | Last updated: 2025-07-12 | 22 min read

Debugging WordPress Performance Issues Like a Pro

Performance issues in WordPress can be elusive, appearing intermittently or only under specific conditions. This comprehensive guide equips you with professional debugging techniques to identify, analyze, and resolve performance bottlenecks systematically. From database queries to plugin conflicts, you'll learn how to diagnose issues like an expert developer.

Whether you're dealing with a suddenly slow site or chronic performance problems, these debugging strategies will help you pinpoint the exact cause and implement targeted solutions. We'll cover advanced tools, methodologies, and real-world troubleshooting scenarios that transform you from guessing to knowing exactly what's slowing down your WordPress site.

Table of Contents

  1. Debugging Fundamentals
  2. Identifying Performance Bottlenecks
  3. Database Query Analysis
  4. Plugin and Theme Debugging
  5. Server-Side Debugging
  6. Frontend Performance Debugging
  7. Advanced Debugging Techniques

Debugging Fundamentals

Setting Up Debug Environment

// wp-config.php debug configuration
// Enable comprehensive debugging
define('WP_DEBUG', true);
define('WP_DEBUG_LOG', true);
define('WP_DEBUG_DISPLAY', false);
define('SCRIPT_DEBUG', true);
define('SAVEQUERIES', true);

// Additional debugging constants
define('WP_DISABLE_FATAL_ERROR_HANDLER', true); // Disable recovery mode
define('WP_DEBUG_LOG_PATH', ABSPATH . 'wp-content/debug.log');

// Query Monitor configuration
define('QM_ENABLE_CAPS_PANEL', true);
define('QM_DISABLE_ERROR_HANDLER', false);

// Custom debug helper class
class WP_Performance_Debugger {

    private static $instance = null;
    private $start_time;
    private $checkpoints = [];
    private $query_log = [];

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

    private function __construct() {
        $this->start_time = microtime(true);

        // Hook into WordPress lifecycle
        add_action('plugins_loaded', [$this, 'checkpoint'], 1);
        add_action('init', [$this, 'checkpoint'], 1);
        add_action('wp_loaded', [$this, 'checkpoint'], 1);
        add_action('template_redirect', [$this, 'checkpoint'], 1);
        add_action('wp_head', [$this, 'checkpoint'], 1);
        add_action('wp_footer', [$this, 'checkpoint'], 999);
        add_action('shutdown', [$this, 'output_debug_info'], 999);

        // Monitor queries
        if (defined('SAVEQUERIES') && SAVEQUERIES) {
            add_filter('query', [$this, 'log_query']);
        }
    }

    public function checkpoint($action = null) {
        $action = $action ?: current_action();
        $this->checkpoints[$action] = [
            'time' => microtime(true) - $this->start_time,
            'memory' => memory_get_usage(),
            'peak_memory' => memory_get_peak_usage(),
            'queries' => get_num_queries()
        ];
    }

    public function log_query($query) {
        $backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 10);
        $caller = $this->get_query_caller($backtrace);

        $this->query_log[] = [
            'query' => $query,
            'caller' => $caller,
            'time' => microtime(true)
        ];

        return $query;
    }

    private function get_query_caller($backtrace) {
        foreach ($backtrace as $trace) {
            if (isset($trace['file']) && strpos($trace['file'], 'wp-content') !== false) {
                return sprintf('%s:%d', $trace['file'], $trace['line']);
            }
        }
        return 'Unknown';
    }

    public function output_debug_info() {
        if (!current_user_can('manage_options')) {
            return;
        }

        $total_time = microtime(true) - $this->start_time;

        // Log performance summary
        error_log(sprintf(
            "\n=== Performance Debug Summary ===\n" .
            "Total Time: %.3fs\n" .
            "Peak Memory: %s\n" .
            "Queries: %d\n" .
            "=================================\n",
            $total_time,
            size_format(memory_get_peak_usage()),
            get_num_queries()
        ));

        // Log checkpoints
        error_log("\n=== Execution Timeline ===");
        $last_time = 0;
        foreach ($this->checkpoints as $action => $data) {
            $delta = $data['time'] - $last_time;
            error_log(sprintf(
                "%s: %.3fs (+%.3fs) | Memory: %s | Queries: %d",
                $action,
                $data['time'],
                $delta,
                size_format($data['memory']),
                $data['queries']
            ));
            $last_time = $data['time'];
        }

        // Log slow queries
        if (defined('SAVEQUERIES') && SAVEQUERIES) {
            global $wpdb;
            error_log("\n=== Slow Queries (>0.05s) ===");
            foreach ($wpdb->queries as $query) {
                if ($query[1] > 0.05) {
                    error_log(sprintf(
                        "Query Time: %.3fs\nSQL: %s\nCaller: %s\n",
                        $query[1],
                        $query[0],
                        $query[2]
                    ));
                }
            }
        }
    }
}

// Initialize debugger
if (WP_DEBUG) {
    WP_Performance_Debugger::init();
}

Performance Profiling Tools

// Custom profiler implementation
class Performance_Profiler {

    private $profiles = [];
    private $active_profile = null;

    public function start_profile($name) {
        $this->profiles[$name] = [
            'start_time' => microtime(true),
            'start_memory' => memory_get_usage(),
            'sql_queries_start' => get_num_queries(),
            'included_files_start' => count(get_included_files())
        ];

        $this->active_profile = $name;
    }

    public function end_profile($name = null) {
        $name = $name ?: $this->active_profile;

        if (!isset($this->profiles[$name])) {
            return false;
        }

        $profile = &$this->profiles[$name];
        $profile['end_time'] = microtime(true);
        $profile['end_memory'] = memory_get_usage();
        $profile['duration'] = ($profile['end_time'] - $profile['start_time']) * 1000; // ms
        $profile['memory_used'] = $profile['end_memory'] - $profile['start_memory'];
        $profile['sql_queries'] = get_num_queries() - $profile['sql_queries_start'];
        $profile['included_files'] = count(get_included_files()) - $profile['included_files_start'];

        $this->active_profile = null;

        return $profile;
    }

    public function get_report() {
        $report = "=== Performance Profile Report ===\n\n";

        foreach ($this->profiles as $name => $profile) {
            if (!isset($profile['duration'])) {
                continue; // Profile not completed
            }

            $report .= sprintf(
                "%s:\n" .
                "  Duration: %.2fms\n" .
                "  Memory: %s\n" .
                "  Queries: %d\n" .
                "  Files: %d\n\n",
                $name,
                $profile['duration'],
                size_format($profile['memory_used']),
                $profile['sql_queries'],
                $profile['included_files']
            );
        }

        return $report;
    }

    public function profile_function($function, $args = []) {
        $name = is_string($function) ? $function : 'anonymous_function';

        $this->start_profile($name);
        $result = call_user_func_array($function, $args);
        $profile = $this->end_profile($name);

        return [
            'result' => $result,
            'profile' => $profile
        ];
    }
}

// Usage example
$profiler = new Performance_Profiler();

// Profile a specific operation
$profiler->start_profile('homepage_render');
// ... homepage rendering code ...
$profile = $profiler->end_profile('homepage_render');

// Profile a function
$result = $profiler->profile_function('get_posts', [
    ['numberposts' => 50]
]);

Identifying Performance Bottlenecks

Systematic Bottleneck Detection

// Bottleneck detector class
class Bottleneck_Detector {

    private $thresholds = [
        'query_time' => 0.05, // 50ms
        'memory_spike' => 10485760, // 10MB
        'file_io_time' => 0.1, // 100ms
        'external_request_time' => 1.0 // 1 second
    ];

    private $bottlenecks = [];

    public function analyze() {
        // Analyze different potential bottlenecks
        $this->analyze_database_queries();
        $this->analyze_plugin_performance();
        $this->analyze_theme_performance();
        $this->analyze_external_requests();
        $this->analyze_file_operations();
        $this->analyze_memory_usage();

        return $this->generate_report();
    }

    private function analyze_database_queries() {
        if (!defined('SAVEQUERIES') || !SAVEQUERIES) {
            return;
        }

        global $wpdb;

        $slow_queries = [];
        $duplicate_queries = [];
        $query_patterns = [];

        foreach ($wpdb->queries as $query_data) {
            $query = $query_data[0];
            $time = $query_data[1];
            $caller = $query_data[2];

            // Check for slow queries
            if ($time > $this->thresholds['query_time']) {
                $slow_queries[] = [
                    'query' => $query,
                    'time' => $time,
                    'caller' => $caller
                ];
            }

            // Track query patterns
            $pattern = $this->get_query_pattern($query);
            if (!isset($query_patterns[$pattern])) {
                $query_patterns[$pattern] = [
                    'count' => 0,
                    'total_time' => 0,
                    'callers' => []
                ];
            }

            $query_patterns[$pattern]['count']++;
            $query_patterns[$pattern]['total_time'] += $time;
            $query_patterns[$pattern]['callers'][] = $caller;
        }

        // Find duplicate queries
        foreach ($query_patterns as $pattern => $data) {
            if ($data['count'] > 1) {
                $duplicate_queries[] = [
                    'pattern' => $pattern,
                    'count' => $data['count'],
                    'total_time' => $data['total_time'],
                    'callers' => array_unique($data['callers'])
                ];
            }
        }

        if (!empty($slow_queries)) {
            $this->bottlenecks['slow_queries'] = $slow_queries;
        }

        if (!empty($duplicate_queries)) {
            $this->bottlenecks['duplicate_queries'] = $duplicate_queries;
        }
    }

    private function get_query_pattern($query) {
        // Normalize query to identify patterns
        $query = preg_replace('/\s+/', ' ', trim($query));
        $query = preg_replace('/\d+/', 'N', $query);
        $query = preg_replace("/'[^']*'/", "'S'", $query);
        $query = preg_replace('/"[^"]*"/', '"S"', $query);

        return $query;
    }

    private function analyze_plugin_performance() {
        $plugin_profiles = [];

        // Profile each active plugin
        foreach (get_option('active_plugins') as $plugin) {
            $plugin_dir = dirname($plugin);
            $start_time = microtime(true);
            $start_memory = memory_get_usage();

            // Measure plugin initialization impact
            add_action('plugins_loaded', function() use ($plugin_dir, &$plugin_profiles, $start_time, $start_memory) {
                $duration = microtime(true) - $start_time;
                $memory_used = memory_get_usage() - $start_memory;

                if ($duration > 0.1 || $memory_used > 5242880) { // 100ms or 5MB
                    $plugin_profiles[$plugin_dir] = [
                        'duration' => $duration,
                        'memory' => $memory_used,
                        'hooks' => $this->count_plugin_hooks($plugin_dir)
                    ];
                }
            }, 1);
        }

        if (!empty($plugin_profiles)) {
            $this->bottlenecks['slow_plugins'] = $plugin_profiles;
        }
    }

    private function count_plugin_hooks($plugin_dir) {
        global $wp_filter;

        $count = 0;
        foreach ($wp_filter as $hook => $priorities) {
            foreach ($priorities as $priority => $functions) {
                foreach ($functions as $function) {
                    if (is_string($function['function']) && strpos($function['function'], $plugin_dir) !== false) {
                        $count++;
                    }
                }
            }
        }

        return $count;
    }

    private function analyze_external_requests() {
        // Hook into HTTP API
        add_filter('pre_http_request', function($preempt, $args, $url) {
            $start_time = microtime(true);

            add_filter('http_response', function($response, $args_inner, $url_inner) use ($url, $start_time) {
                $duration = microtime(true) - $start_time;

                if ($duration > $this->thresholds['external_request_time']) {
                    if (!isset($this->bottlenecks['slow_external_requests'])) {
                        $this->bottlenecks['slow_external_requests'] = [];
                    }

                    $this->bottlenecks['slow_external_requests'][] = [
                        'url' => $url,
                        'duration' => $duration,
                        'response_code' => wp_remote_retrieve_response_code($response),
                        'backtrace' => debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 5)
                    ];
                }

                return $response;
            }, 10, 3);

            return $preempt;
        }, 10, 3);
    }

    private function analyze_memory_usage() {
        // Track memory spikes
        $checkpoints = [
            'muplugins_loaded' => 0,
            'plugins_loaded' => 0,
            'setup_theme' => 0,
            'after_setup_theme' => 0,
            'init' => 0,
            'wp_loaded' => 0
        ];

        $last_memory = memory_get_usage();

        foreach ($checkpoints as $hook => $memory) {
            add_action($hook, function() use ($hook, &$checkpoints, &$last_memory) {
                $current_memory = memory_get_usage();
                $spike = $current_memory - $last_memory;

                if ($spike > $this->thresholds['memory_spike']) {
                    if (!isset($this->bottlenecks['memory_spikes'])) {
                        $this->bottlenecks['memory_spikes'] = [];
                    }

                    $this->bottlenecks['memory_spikes'][] = [
                        'hook' => $hook,
                        'spike' => $spike,
                        'total_memory' => $current_memory
                    ];
                }

                $checkpoints[$hook] = $current_memory;
                $last_memory = $current_memory;
            }, 1);
        }
    }

    private function generate_report() {
        $report = [
            'summary' => [
                'total_issues' => count($this->bottlenecks),
                'critical_issues' => $this->count_critical_issues()
            ],
            'bottlenecks' => $this->bottlenecks,
            'recommendations' => $this->generate_recommendations()
        ];

        return $report;
    }

    private function count_critical_issues() {
        $critical = 0;

        if (isset($this->bottlenecks['slow_queries'])) {
            foreach ($this->bottlenecks['slow_queries'] as $query) {
                if ($query['time'] > 0.5) { // 500ms
                    $critical++;
                }
            }
        }

        if (isset($this->bottlenecks['memory_spikes'])) {
            foreach ($this->bottlenecks['memory_spikes'] as $spike) {
                if ($spike['spike'] > 52428800) { // 50MB
                    $critical++;
                }
            }
        }

        return $critical;
    }

    private function generate_recommendations() {
        $recommendations = [];

        if (isset($this->bottlenecks['slow_queries'])) {
            $recommendations[] = 'Add database indexes for frequently queried columns';
            $recommendations[] = 'Implement query result caching using transients';
        }

        if (isset($this->bottlenecks['duplicate_queries'])) {
            $recommendations[] = 'Cache duplicate query results within the same request';
            $recommendations[] = 'Review plugin code for redundant database calls';
        }

        if (isset($this->bottlenecks['slow_plugins'])) {
            $recommendations[] = 'Consider replacing slow plugins with faster alternatives';
            $recommendations[] = 'Contact plugin developers about performance issues';
        }

        if (isset($this->bottlenecks['memory_spikes'])) {
            $recommendations[] = 'Increase PHP memory limit if necessary';
            $recommendations[] = 'Optimize memory-intensive operations';
        }

        return $recommendations;
    }
}

Database Query Analysis

Advanced Query Debugging

// Database query analyzer
class Query_Analyzer {

    private $query_log = [];
    private $index_suggestions = [];

    public function __construct() {
        if (defined('SAVEQUERIES') && SAVEQUERIES) {
            add_filter('query', [$this, 'analyze_query']);
            add_action('shutdown', [$this, 'generate_analysis_report']);
        }
    }

    public function analyze_query($query) {
        $start_time = microtime(true);

        // Get query execution plan
        $explain = $this->get_query_explain($query);

        // Analyze query structure
        $analysis = [
            'query' => $query,
            'type' => $this->get_query_type($query),
            'tables' => $this->extract_tables($query),
            'explain' => $explain,
            'suggestions' => []
        ];

        // Check for missing indexes
        if ($explain && $this->needs_index($explain)) {
            $analysis['suggestions'][] = $this->suggest_index($query, $explain);
        }

        // Check for inefficient patterns
        $inefficiencies = $this->check_inefficient_patterns($query);
        if (!empty($inefficiencies)) {
            $analysis['suggestions'] = array_merge($analysis['suggestions'], $inefficiencies);
        }

        $this->query_log[] = $analysis;

        return $query;
    }

    private function get_query_explain($query) {
        global $wpdb;

        // Only explain SELECT queries
        if (!preg_match('/^\s*SELECT/i', $query)) {
            return null;
        }

        // Skip if query contains subqueries (EXPLAIN doesn't work well with them)
        if (preg_match('/SELECT.*FROM.*SELECT/i', $query)) {
            return null;
        }

        try {
            $explain_query = "EXPLAIN " . $query;
            $results = $wpdb->get_results($explain_query, ARRAY_A);
            return $results;
        } catch (Exception $e) {
            return null;
        }
    }

    private function needs_index($explain) {
        foreach ($explain as $row) {
            // Check for full table scans
            if ($row['type'] === 'ALL' && $row['rows'] > 100) {
                return true;
            }

            // Check for inefficient index usage
            if ($row['type'] === 'index' && $row['rows'] > 1000) {
                return true;
            }

            // Check for using filesort
            if (strpos($row['Extra'], 'Using filesort') !== false && $row['rows'] > 100) {
                return true;
            }
        }

        return false;
    }

    private function suggest_index($query, $explain) {
        $suggestions = [];

        // Extract WHERE conditions
        if (preg_match('/WHERE\s+(.+?)(?:GROUP|ORDER|LIMIT|$)/i', $query, $matches)) {
            $where_clause = $matches[1];

            // Find columns used in WHERE
            if (preg_match_all('/(\w+)\s*=\s*[\'"]?\w+[\'"]?/i', $where_clause, $column_matches)) {
                foreach ($column_matches[1] as $column) {
                    $suggestions[] = sprintf(
                        "Consider adding index on column '%s'",
                        $column
                    );
                }
            }
        }

        // Extract ORDER BY columns
        if (preg_match('/ORDER\s+BY\s+([^,\s]+)/i', $query, $matches)) {
            $order_column = $matches[1];
            $suggestions[] = sprintf(
                "Consider adding index on ORDER BY column '%s'",
                $order_column
            );
        }

        return implode('; ', $suggestions);
    }

    private function check_inefficient_patterns($query) {
        $inefficiencies = [];

        // Check for SELECT *
        if (preg_match('/SELECT\s+\*/i', $query)) {
            $inefficiencies[] = 'Avoid SELECT *, specify only needed columns';
        }

        // Check for NOT IN with subquery
        if (preg_match('/NOT\s+IN\s*\(\s*SELECT/i', $query)) {
            $inefficiencies[] = 'NOT IN with subquery is inefficient, use LEFT JOIN instead';
        }

        // Check for LIKE with leading wildcard
        if (preg_match('/LIKE\s+[\'"]%\w+/i', $query)) {
            $inefficiencies[] = 'Leading wildcard in LIKE prevents index usage';
        }

        // Check for OR conditions
        if (preg_match('/WHERE.*\sOR\s/i', $query)) {
            $inefficiencies[] = 'OR conditions may prevent index usage, consider using UNION';
        }

        // Check for functions on indexed columns
        if (preg_match('/WHERE.*(?:YEAR|MONTH|DATE|LOWER|UPPER)\s*\(/i', $query)) {
            $inefficiencies[] = 'Functions on columns prevent index usage';
        }

        return $inefficiencies;
    }

    private function get_query_type($query) {
        if (preg_match('/^\s*SELECT/i', $query)) return 'SELECT';
        if (preg_match('/^\s*INSERT/i', $query)) return 'INSERT';
        if (preg_match('/^\s*UPDATE/i', $query)) return 'UPDATE';
        if (preg_match('/^\s*DELETE/i', $query)) return 'DELETE';
        return 'OTHER';
    }

    private function extract_tables($query) {
        $tables = [];

        // Extract from FROM clause
        if (preg_match('/FROM\s+([^\s,]+)/i', $query, $matches)) {
            $tables[] = $matches[1];
        }

        // Extract from JOIN clauses
        if (preg_match_all('/JOIN\s+([^\s]+)/i', $query, $matches)) {
            $tables = array_merge($tables, $matches[1]);
        }

        return array_unique($tables);
    }

    public function generate_analysis_report() {
        if (empty($this->query_log)) {
            return;
        }

        // Group queries by pattern
        $query_patterns = [];
        foreach ($this->query_log as $analysis) {
            $pattern = $this->get_query_pattern($analysis['query']);

            if (!isset($query_patterns[$pattern])) {
                $query_patterns[$pattern] = [
                    'count' => 0,
                    'example' => $analysis['query'],
                    'suggestions' => $analysis['suggestions'],
                    'tables' => $analysis['tables']
                ];
            }

            $query_patterns[$pattern]['count']++;
        }

        // Sort by frequency
        uasort($query_patterns, function($a, $b) {
            return $b['count'] - $a['count'];
        });

        // Output report
        error_log("\n=== Database Query Analysis Report ===\n");

        foreach ($query_patterns as $pattern => $data) {
            if ($data['count'] > 1 || !empty($data['suggestions'])) {
                error_log(sprintf(
                    "\nQuery Pattern (executed %d times):\n%s\n",
                    $data['count'],
                    $data['example']
                ));

                if (!empty($data['suggestions'])) {
                    error_log("Suggestions:\n");
                    foreach ($data['suggestions'] as $suggestion) {
                        error_log("  - " . $suggestion . "\n");
                    }
                }
            }
        }
    }
}

// Initialize query analyzer
if (WP_DEBUG && defined('SAVEQUERIES') && SAVEQUERIES) {
    new Query_Analyzer();
}

Query Optimization Helper

// Query optimization suggestions
class Query_Optimizer {

    public function optimize_wp_query($args) {
        $optimized_args = $args;

        // Disable unnecessary queries
        if (!isset($args['update_post_meta_cache'])) {
            $optimized_args['update_post_meta_cache'] = false;
        }

        if (!isset($args['update_post_term_cache'])) {
            $optimized_args['update_post_term_cache'] = false;
        }

        // Use specific fields if possible
        if (!isset($args['fields']) && !empty($args['return_fields'])) {
            $optimized_args['fields'] = $args['return_fields'];
            unset($optimized_args['return_fields']);
        }

        // Optimize meta queries
        if (isset($args['meta_query'])) {
            $optimized_args['meta_query'] = $this->optimize_meta_query($args['meta_query']);
        }

        // Add suggestions
        $suggestions = $this->generate_query_suggestions($args);

        return [
            'args' => $optimized_args,
            'suggestions' => $suggestions
        ];
    }

    private function optimize_meta_query($meta_query) {
        // Ensure numeric comparisons use numeric type
        foreach ($meta_query as &$query) {
            if (is_array($query) && isset($query['compare'])) {
                if (in_array($query['compare'], ['>', '<', '>=', '<=', 'BETWEEN'])) {
                    $query['type'] = 'NUMERIC';
                }
            }
        }

        return $meta_query;
    }

    private function generate_query_suggestions($args) {
        $suggestions = [];

        // Check for expensive orderby
        if (isset($args['orderby'])) {
            if ($args['orderby'] === 'meta_value' && !isset($args['meta_key'])) {
                $suggestions[] = 'Specify meta_key when ordering by meta_value';
            }

            if (in_array($args['orderby'], ['rand', 'RAND()'])) {
                $suggestions[] = 'ORDER BY RAND() is very expensive for large datasets';
            }
        }

        // Check for missing pagination
        if (!isset($args['posts_per_page']) || $args['posts_per_page'] == -1) {
            $suggestions[] = 'Consider adding pagination to limit results';
        }

        // Check for inefficient meta queries
        if (isset($args['meta_query']) && count($args['meta_query']) > 3) {
            $suggestions[] = 'Multiple meta queries can be slow, consider custom table';
        }

        // Check for taxonomy queries
        if (isset($args['tax_query']) && count($args['tax_query']) > 2) {
            $suggestions[] = 'Complex taxonomy queries may benefit from direct SQL';
        }

        return $suggestions;
    }

    public function create_optimized_indexes() {
        global $wpdb;

        $indexes = [
            // Optimize post queries
            [
                'table' => $wpdb->posts,
                'name' => 'idx_post_status_type',
                'columns' => 'post_status, post_type, post_date'
            ],
            [
                'table' => $wpdb->posts,
                'name' => 'idx_post_author_status',
                'columns' => 'post_author, post_status'
            ],

            // Optimize meta queries
            [
                'table' => $wpdb->postmeta,
                'name' => 'idx_meta_key_value',
                'columns' => 'meta_key, meta_value(20)'
            ],

            // Optimize term relationships
            [
                'table' => $wpdb->term_relationships,
                'name' => 'idx_term_object',
                'columns' => 'term_taxonomy_id, object_id'
            ]
        ];

        foreach ($indexes as $index) {
            $this->create_index_if_not_exists(
                $index['table'],
                $index['name'],
                $index['columns']
            );
        }
    }

    private function create_index_if_not_exists($table, $index_name, $columns) {
        global $wpdb;

        // Check if index exists
        $existing = $wpdb->get_var($wpdb->prepare(
            "SELECT COUNT(1) FROM INFORMATION_SCHEMA.STATISTICS 
             WHERE table_schema = %s 
             AND table_name = %s 
             AND index_name = %s",
            DB_NAME,
            $table,
            $index_name
        ));

        if (!$existing) {
            $wpdb->query(sprintf(
                "CREATE INDEX %s ON %s (%s)",
                $index_name,
                $table,
                $columns
            ));

            error_log("Created index: $index_name on $table");
        }
    }
}

Plugin and Theme Debugging

Plugin Conflict Detection

// Plugin conflict detector
class Plugin_Conflict_Detector {

    private $test_results = [];
    private $baseline_performance = [];

    public function run_conflict_test() {
        // Get baseline with all plugins active
        $this->baseline_performance = $this->measure_performance();

        $active_plugins = get_option('active_plugins');

        // Test each plugin individually
        foreach ($active_plugins as $plugin) {
            $this->test_plugin_isolation($plugin, $active_plugins);
        }

        // Test plugin combinations
        $this->test_plugin_combinations($active_plugins);

        return $this->analyze_results();
    }

    private function test_plugin_isolation($test_plugin, $all_plugins) {
        // Temporarily deactivate all plugins except the one being tested
        $other_plugins = array_diff($all_plugins, [$test_plugin]);

        update_option('active_plugins', [$test_plugin]);

        // Measure performance with only this plugin
        $isolated_performance = $this->measure_performance();

        // Measure performance without this plugin
        update_option('active_plugins', $other_plugins);
        $without_performance = $this->measure_performance();

        // Restore original state
        update_option('active_plugins', $all_plugins);

        $this->test_results[$test_plugin] = [
            'isolated_performance' => $isolated_performance,
            'without_performance' => $without_performance,
            'impact' => $this->calculate_impact($isolated_performance, $without_performance)
        ];
    }

    private function test_plugin_combinations($plugins) {
        // Test common problematic combinations
        $test_combinations = [
            ['caching_plugins' => $this->filter_plugins_by_type($plugins, 'cache')],
            ['seo_plugins' => $this->filter_plugins_by_type($plugins, 'seo')],
            ['security_plugins' => $this->filter_plugins_by_type($plugins, 'security')]
        ];

        foreach ($test_combinations as $type => $plugin_group) {
            if (count($plugin_group) > 1) {
                // Multiple plugins of same type detected
                $this->test_results['conflicts'][$type] = $plugin_group;
            }
        }
    }

    private function measure_performance() {
        $measurements = [];

        // Measure homepage load
        $start_time = microtime(true);
        $start_memory = memory_get_usage();
        $start_queries = get_num_queries();

        // Simulate page load
        ob_start();
        $this->simulate_page_load(home_url());
        ob_end_clean();

        $measurements['load_time'] = microtime(true) - $start_time;
        $measurements['memory_used'] = memory_get_usage() - $start_memory;
        $measurements['queries'] = get_num_queries() - $start_queries;

        // Measure admin load
        $admin_start = microtime(true);
        $this->simulate_admin_load();
        $measurements['admin_time'] = microtime(true) - $admin_start;

        return $measurements;
    }

    private function simulate_page_load($url) {
        // Set up WordPress query
        $parsed_url = parse_url($url);
        $_SERVER['REQUEST_URI'] = $parsed_url['path'] ?? '/';

        // Run WordPress query
        wp();

        // Load template
        if (is_front_page()) {
            include get_front_page_template();
        } elseif (is_single()) {
            include get_single_template();
        } else {
            include get_index_template();
        }
    }

    private function simulate_admin_load() {
        // Simulate admin dashboard load
        set_current_screen('dashboard');
        do_action('admin_init');
        do_action('admin_menu');
    }

    private function calculate_impact($isolated, $without) {
        return [
            'load_time_impact' => $isolated['load_time'] - $this->baseline_performance['load_time'],
            'memory_impact' => $isolated['memory_used'] - $this->baseline_performance['memory_used'],
            'query_impact' => $isolated['queries'] - $this->baseline_performance['queries']
        ];
    }

    private function filter_plugins_by_type($plugins, $type) {
        $type_keywords = [
            'cache' => ['cache', 'performance', 'optimize'],
            'seo' => ['seo', 'sitemap', 'meta'],
            'security' => ['security', 'firewall', 'protect']
        ];

        $matched_plugins = [];

        foreach ($plugins as $plugin) {
            $plugin_data = get_plugin_data(WP_PLUGIN_DIR . '/' . $plugin);
            $plugin_text = strtolower($plugin_data['Name'] . ' ' . $plugin_data['Description']);

            foreach ($type_keywords[$type] as $keyword) {
                if (strpos($plugin_text, $keyword) !== false) {
                    $matched_plugins[] = $plugin;
                    break;
                }
            }
        }

        return $matched_plugins;
    }

    private function analyze_results() {
        $analysis = [
            'slow_plugins' => [],
            'memory_hogs' => [],
            'query_heavy' => [],
            'conflicts' => $this->test_results['conflicts'] ?? []
        ];

        foreach ($this->test_results as $plugin => $results) {
            if (is_array($results) && isset($results['impact'])) {
                // Identify slow plugins
                if ($results['impact']['load_time_impact'] > 0.5) { // 500ms
                    $analysis['slow_plugins'][] = [
                        'plugin' => $plugin,
                        'impact' => $results['impact']['load_time_impact']
                    ];
                }

                // Identify memory hogs
                if ($results['impact']['memory_impact'] > 10485760) { // 10MB
                    $analysis['memory_hogs'][] = [
                        'plugin' => $plugin,
                        'impact' => $results['impact']['memory_impact']
                    ];
                }

                // Identify query heavy plugins
                if ($results['impact']['query_impact'] > 50) {
                    $analysis['query_heavy'][] = [
                        'plugin' => $plugin,
                        'impact' => $results['impact']['query_impact']
                    ];
                }
            }
        }

        return $analysis;
    }
}

Theme Performance Analysis

// Theme performance analyzer
class Theme_Performance_Analyzer {

    public function analyze_theme() {
        $theme = wp_get_theme();
        $analysis = [
            'theme_name' => $theme->get('Name'),
            'theme_version' => $theme->get('Version'),
            'issues' => []
        ];

        // Analyze theme files
        $analysis['file_analysis'] = $this->analyze_theme_files();

        // Analyze theme functions
        $analysis['function_analysis'] = $this->analyze_theme_functions();

        // Analyze asset loading
        $analysis['asset_analysis'] = $this->analyze_theme_assets();

        // Analyze database queries
        $analysis['query_analysis'] = $this->analyze_theme_queries();

        return $analysis;
    }

    private function analyze_theme_files() {
        $theme_dir = get_stylesheet_directory();
        $analysis = [
            'total_files' => 0,
            'large_files' => [],
            'unoptimized_images' => []
        ];

        $iterator = new RecursiveIteratorIterator(
            new RecursiveDirectoryIterator($theme_dir)
        );

        foreach ($iterator as $file) {
            if ($file->isFile()) {
                $analysis['total_files']++;

                // Check for large files
                if ($file->getSize() > 1048576) { // 1MB
                    $analysis['large_files'][] = [
                        'path' => $file->getPathname(),
                        'size' => $file->getSize()
                    ];
                }

                // Check for unoptimized images
                if (preg_match('/\.(jpg|jpeg|png|gif)$/i', $file->getFilename())) {
                    if ($this->is_image_unoptimized($file->getPathname())) {
                        $analysis['unoptimized_images'][] = $file->getPathname();
                    }
                }
            }
        }

        return $analysis;
    }

    private function is_image_unoptimized($image_path) {
        $size = filesize($image_path);
        list($width, $height) = getimagesize($image_path);

        // Simple heuristic: if file size is too large for dimensions
        $expected_size = ($width * $height * 3) / 10; // Rough estimate

        return $size > $expected_size * 2;
    }

    private function analyze_theme_functions() {
        $functions_file = get_stylesheet_directory() . '/functions.php';
        $analysis = [
            'hooks_count' => 0,
            'global_queries' => 0,
            'inefficient_patterns' => []
        ];

        if (file_exists($functions_file)) {
            $content = file_get_contents($functions_file);

            // Count hooks
            preg_match_all('/add_(action|filter)\s*\(/', $content, $hooks);
            $analysis['hooks_count'] = count($hooks[0]);

            // Check for global queries
            preg_match_all('/\$wpdb->(?:get_results|get_var|get_row|query)\s*\(/', $content, $queries);
            $analysis['global_queries'] = count($queries[0]);

            // Check for inefficient patterns
            if (preg_match('/query_posts\s*\(/', $content)) {
                $analysis['inefficient_patterns'][] = 'query_posts() usage detected';
            }

            if (preg_match_all('/get_posts.*posts_per_page[\'"\s]*=[\'"\s]*-1/', $content)) {
                $analysis['inefficient_patterns'][] = 'Unlimited post queries detected';
            }

            if (preg_match('/wp_remote_get.*wp_head|init/', $content)) {
                $analysis['inefficient_patterns'][] = 'External requests in critical hooks';
            }
        }

        return $analysis;
    }

    private function analyze_theme_assets() {
        global $wp_scripts, $wp_styles;

        $analysis = [
            'total_scripts' => 0,
            'total_styles' => 0,
            'render_blocking' => [],
            'missing_dependencies' => [],
            'large_assets' => []
        ];

        // Analyze scripts
        if ($wp_scripts) {
            foreach ($wp_scripts->registered as $handle => $script) {
                if (strpos($script->src, get_stylesheet_directory_uri()) !== false) {
                    $analysis['total_scripts']++;

                    // Check if render-blocking
                    if (!isset($script->extra['group']) || $script->extra['group'] !== 1) {
                        $analysis['render_blocking'][] = $handle;
                    }

                    // Check file size
                    $file_path = str_replace(
                        get_stylesheet_directory_uri(),
                        get_stylesheet_directory(),
                        $script->src
                    );

                    if (file_exists($file_path) && filesize($file_path) > 102400) { // 100KB
                        $analysis['large_assets'][] = [
                            'handle' => $handle,
                            'size' => filesize($file_path)
                        ];
                    }
                }
            }
        }

        // Analyze styles
        if ($wp_styles) {
            foreach ($wp_styles->registered as $handle => $style) {
                if (strpos($style->src, get_stylesheet_directory_uri()) !== false) {
                    $analysis['total_styles']++;
                }
            }
        }

        return $analysis;
    }

    private function analyze_theme_queries() {
        // Hook into theme setup to analyze queries
        $query_count = 0;
        $slow_queries = [];

        add_action('template_redirect', function() use (&$query_count, &$slow_queries) {
            if (defined('SAVEQUERIES') && SAVEQUERIES) {
                global $wpdb;

                $theme_dir = get_stylesheet_directory();

                foreach ($wpdb->queries as $query) {
                    // Check if query originates from theme
                    if (strpos($query[2], $theme_dir) !== false) {
                        $query_count++;

                        if ($query[1] > 0.05) { // 50ms
                            $slow_queries[] = [
                                'query' => $query[0],
                                'time' => $query[1],
                                'caller' => $query[2]
                            ];
                        }
                    }
                }
            }
        }, 999);

        return [
            'query_count' => $query_count,
            'slow_queries' => $slow_queries
        ];
    }
}

Server-Side Debugging

Server Resource Monitor

// Server resource monitoring
class Server_Resource_Monitor {

    private $metrics = [];

    public function collect_metrics() {
        $this->metrics = [
            'cpu' => $this->get_cpu_usage(),
            'memory' => $this->get_memory_usage(),
            'disk' => $this->get_disk_usage(),
            'network' => $this->get_network_stats(),
            'processes' => $this->get_process_info(),
            'mysql' => $this->get_mysql_stats()
        ];

        return $this->metrics;
    }

    private function get_cpu_usage() {
        if (PHP_OS_FAMILY === 'Linux') {
            $load = sys_getloadavg();
            $cpu_count = $this->get_cpu_count();

            return [
                'load_1min' => $load[0],
                'load_5min' => $load[1],
                'load_15min' => $load[2],
                'cpu_count' => $cpu_count,
                'utilization' => ($load[0] / $cpu_count) * 100
            ];
        }

        return null;
    }

    private function get_cpu_count() {
        if (PHP_OS_FAMILY === 'Linux') {
            $cpuinfo = file_get_contents('/proc/cpuinfo');
            preg_match_all('/^processor/m', $cpuinfo, $matches);
            return count($matches[0]);
        }

        return 1;
    }

    private function get_memory_usage() {
        $memory = [
            'php' => [
                'current' => memory_get_usage(true),
                'peak' => memory_get_peak_usage(true),
                'limit' => $this->get_memory_limit()
            ]
        ];

        if (PHP_OS_FAMILY === 'Linux' && file_exists('/proc/meminfo')) {
            $meminfo = file_get_contents('/proc/meminfo');

            preg_match('/MemTotal:\s+(\d+)/', $meminfo, $total);
            preg_match('/MemFree:\s+(\d+)/', $meminfo, $free);
            preg_match('/Cached:\s+(\d+)/', $meminfo, $cached);

            $memory['system'] = [
                'total' => $total[1] * 1024,
                'free' => $free[1] * 1024,
                'cached' => $cached[1] * 1024,
                'used' => ($total[1] - $free[1] - $cached[1]) * 1024
            ];
        }

        return $memory;
    }

    private function get_memory_limit() {
        $limit = ini_get('memory_limit');

        if ($limit === '-1') {
            return PHP_INT_MAX;
        }

        $unit = strtolower(substr($limit, -1));
        $value = (int) $limit;

        switch ($unit) {
            case 'g':
                $value *= 1024;
            case 'm':
                $value *= 1024;
            case 'k':
                $value *= 1024;
        }

        return $value;
    }

    private function get_disk_usage() {
        $path = ABSPATH;

        return [
            'total' => disk_total_space($path),
            'free' => disk_free_space($path),
            'used' => disk_total_space($path) - disk_free_space($path),
            'percentage' => ((disk_total_space($path) - disk_free_space($path)) / disk_total_space($path)) * 100
        ];
    }

    private function get_mysql_stats() {
        global $wpdb;

        $stats = [];

        // Get MySQL variables
        $variables = $wpdb->get_results("SHOW VARIABLES LIKE 'max_connections'", ARRAY_A);
        foreach ($variables as $var) {
            $stats[$var['Variable_name']] = $var['Value'];
        }

        // Get MySQL status
        $status_vars = [
            'Threads_connected',
            'Threads_running',
            'Questions',
            'Slow_queries',
            'Opens',
            'Open_tables',
            'Uptime'
        ];

        $status = $wpdb->get_results(
            "SHOW STATUS WHERE Variable_name IN ('" . implode("','", $status_vars) . "')",
            ARRAY_A
        );

        foreach ($status as $stat) {
            $stats[$stat['Variable_name']] = $stat['Value'];
        }

        return $stats;
    }

    private function get_network_stats() {
        // This would require system-specific implementation
        return [
            'interfaces' => $this->get_network_interfaces()
        ];
    }

    private function get_network_interfaces() {
        if (function_exists('net_get_interfaces')) {
            return net_get_interfaces();
        }

        return [];
    }

    private function get_process_info() {
        $processes = [
            'php' => [
                'version' => PHP_VERSION,
                'sapi' => PHP_SAPI,
                'extensions' => get_loaded_extensions()
            ]
        ];

        // Get web server info
        if (isset($_SERVER['SERVER_SOFTWARE'])) {
            $processes['web_server'] = $_SERVER['SERVER_SOFTWARE'];
        }

        return $processes;
    }

    public function check_server_limits() {
        $issues = [];

        // Check PHP memory limit
        if ($this->get_memory_limit() < 268435456) { // 256MB
            $issues[] = [
                'type' => 'memory_limit',
                'message' => 'PHP memory limit is below recommended 256MB',
                'current' => ini_get('memory_limit'),
                'recommended' => '256M'
            ];
        }

        // Check max execution time
        if (ini_get('max_execution_time') < 300 && ini_get('max_execution_time') != 0) {
            $issues[] = [
                'type' => 'execution_time',
                'message' => 'Max execution time is below recommended 300 seconds',
                'current' => ini_get('max_execution_time'),
                'recommended' => '300'
            ];
        }

        // Check upload limits
        $upload_max = $this->parse_size(ini_get('upload_max_filesize'));
        $post_max = $this->parse_size(ini_get('post_max_size'));

        if ($upload_max < 67108864) { // 64MB
            $issues[] = [
                'type' => 'upload_limit',
                'message' => 'Upload max filesize is below recommended 64MB',
                'current' => ini_get('upload_max_filesize'),
                'recommended' => '64M'
            ];
        }

        return $issues;
    }

    private function parse_size($size) {
        $unit = strtolower(substr($size, -1));
        $value = (int) $size;

        switch ($unit) {
            case 'g':
                $value *= 1024;
            case 'm':
                $value *= 1024;
            case 'k':
                $value *= 1024;
        }

        return $value;
    }
}

Frontend Performance Debugging

JavaScript Performance Profiler

// Frontend performance debugging toolkit
class FrontendDebugger {
    constructor() {
        this.metrics = {
            marks: {},
            measures: {},
            resources: [],
            errors: [],
            slowInteractions: []
        };

        this.init();
    }

    init() {
        // Performance observer for various metrics
        this.setupPerformanceObservers();

        // Error tracking
        this.setupErrorTracking();

        // Interaction tracking
        this.setupInteractionTracking();

        // Resource timing
        this.collectResourceTiming();

        // Long task detection
        this.detectLongTasks();
    }

    setupPerformanceObservers() {
        // Navigation timing
        if ('PerformanceNavigationTiming' in window) {
            const navigationEntry = performance.getEntriesByType('navigation')[0];
            this.metrics.navigation = {
                dns: navigationEntry.domainLookupEnd - navigationEntry.domainLookupStart,
                tcp: navigationEntry.connectEnd - navigationEntry.connectStart,
                request: navigationEntry.responseStart - navigationEntry.requestStart,
                response: navigationEntry.responseEnd - navigationEntry.responseStart,
                dom: navigationEntry.domComplete - navigationEntry.domInteractive,
                load: navigationEntry.loadEventEnd - navigationEntry.loadEventStart,
                total: navigationEntry.loadEventEnd - navigationEntry.fetchStart
            };
        }

        // Paint timing
        const paintObserver = new PerformanceObserver((list) => {
            for (const entry of list.getEntries()) {
                this.metrics.marks[entry.name] = entry.startTime;
            }
        });
        paintObserver.observe({ entryTypes: ['paint'] });

        // Layout shift
        let clsValue = 0;
        let clsEntries = [];

        const layoutShiftObserver = new PerformanceObserver((list) => {
            for (const entry of list.getEntries()) {
                if (!entry.hadRecentInput) {
                    clsValue += entry.value;
                    clsEntries.push({
                        value: entry.value,
                        startTime: entry.startTime,
                        sources: entry.sources?.map(source => ({
                            node: source.node,
                            previousRect: source.previousRect,
                            currentRect: source.currentRect
                        }))
                    });
                }
            }

            this.metrics.cls = {
                value: clsValue,
                entries: clsEntries
            };
        });

        layoutShiftObserver.observe({ entryTypes: ['layout-shift'] });
    }

    setupErrorTracking() {
        // JavaScript errors
        window.addEventListener('error', (event) => {
            this.metrics.errors.push({
                type: 'javascript',
                message: event.message,
                source: event.filename,
                line: event.lineno,
                column: event.colno,
                stack: event.error?.stack,
                timestamp: Date.now()
            });
        });

        // Resource loading errors
        window.addEventListener('error', (event) => {
            if (event.target !== window) {
                this.metrics.errors.push({
                    type: 'resource',
                    tagName: event.target.tagName,
                    source: event.target.src || event.target.href,
                    message: 'Failed to load resource',
                    timestamp: Date.now()
                });
            }
        }, true);

        // Unhandled promise rejections
        window.addEventListener('unhandledrejection', (event) => {
            this.metrics.errors.push({
                type: 'promise',
                reason: event.reason,
                promise: event.promise,
                timestamp: Date.now()
            });
        });
    }

    setupInteractionTracking() {
        // Track slow clicks
        document.addEventListener('click', (event) => {
            const startTime = performance.now();

            requestAnimationFrame(() => {
                requestAnimationFrame(() => {
                    const duration = performance.now() - startTime;

                    if (duration > 100) {
                        this.metrics.slowInteractions.push({
                            type: 'click',
                            target: this.getElementPath(event.target),
                            duration: duration,
                            timestamp: startTime
                        });
                    }
                });
            });
        }, { passive: true });

        // Track input delays
        let inputDelayMeasured = false;
        ['mousedown', 'keydown', 'touchstart'].forEach(eventType => {
            document.addEventListener(eventType, (event) => {
                if (!inputDelayMeasured) {
                    const now = performance.now();

                    requestAnimationFrame(() => {
                        const inputDelay = performance.now() - now;
                        this.metrics.firstInputDelay = inputDelay;
                        inputDelayMeasured = true;
                    });
                }
            }, { once: true, passive: true });
        });
    }

    collectResourceTiming() {
        const resources = performance.getEntriesByType('resource');

        this.metrics.resources = resources.map(resource => ({
            name: resource.name,
            type: this.getResourceType(resource),
            duration: resource.duration,
            size: resource.transferSize,
            protocol: resource.nextHopProtocol,
            cached: resource.transferSize === 0 && resource.decodedBodySize > 0,
            timing: {
                dns: resource.domainLookupEnd - resource.domainLookupStart,
                tcp: resource.connectEnd - resource.connectStart,
                ttfb: resource.responseStart - resource.requestStart,
                download: resource.responseEnd - resource.responseStart
            }
        }));

        // Group by type
        this.metrics.resourceSummary = this.summarizeResources(this.metrics.resources);
    }

    getResourceType(resource) {
        const url = resource.name;
        if (url.match(/\.js(\?|$)/)) return 'script';
        if (url.match(/\.css(\?|$)/)) return 'stylesheet';
        if (url.match(/\.(jpg|jpeg|png|gif|webp|svg)(\?|$)/)) return 'image';
        if (url.match(/\.(woff|woff2|ttf|eot)(\?|$)/)) return 'font';
        if (resource.initiatorType === 'fetch' || resource.initiatorType === 'xmlhttprequest') return 'ajax';
        return 'other';
    }

    summarizeResources(resources) {
        const summary = {};

        resources.forEach(resource => {
            const type = resource.type;

            if (!summary[type]) {
                summary[type] = {
                    count: 0,
                    totalSize: 0,
                    totalDuration: 0,
                    cached: 0,
                    slowest: null
                };
            }

            summary[type].count++;
            summary[type].totalSize += resource.size || 0;
            summary[type].totalDuration += resource.duration;

            if (resource.cached) {
                summary[type].cached++;
            }

            if (!summary[type].slowest || resource.duration > summary[type].slowest.duration) {
                summary[type].slowest = resource;
            }
        });

        return summary;
    }

    detectLongTasks() {
        if ('PerformanceObserver' in window && 'PerformanceLongTaskTiming' in window) {
            const longTaskObserver = new PerformanceObserver((list) => {
                for (const entry of list.getEntries()) {
                    this.metrics.longTasks = this.metrics.longTasks || [];
                    this.metrics.longTasks.push({
                        duration: entry.duration,
                        startTime: entry.startTime,
                        attribution: entry.attribution?.map(attr => ({
                            name: attr.name,
                            containerType: attr.containerType,
                            containerSrc: attr.containerSrc,
                            containerId: attr.containerId
                        }))
                    });

                    // Log warning for very long tasks
                    if (entry.duration > 100) {
                        console.warn(`Long task detected: ${entry.duration}ms`, entry);
                    }
                }
            });

            longTaskObserver.observe({ entryTypes: ['longtask'] });
        }
    }

    getElementPath(element) {
        const path = [];

        while (element && element.nodeType === Node.ELEMENT_NODE) {
            let selector = element.nodeName.toLowerCase();

            if (element.id) {
                selector += '#' + element.id;
                path.unshift(selector);
                break;
            } else if (element.className) {
                selector += '.' + element.className.split(' ').join('.');
            }

            path.unshift(selector);
            element = element.parentNode;
        }

        return path.join(' > ');
    }

    generateReport() {
        const report = {
            summary: {
                pageLoadTime: this.metrics.navigation?.total || 0,
                firstPaint: this.metrics.marks['first-paint'] || 0,
                firstContentfulPaint: this.metrics.marks['first-contentful-paint'] || 0,
                largestContentfulPaint: this.metrics.lcp || 0,
                firstInputDelay: this.metrics.firstInputDelay || 0,
                cumulativeLayoutShift: this.metrics.cls?.value || 0,
                totalResources: this.metrics.resources.length,
                errorCount: this.metrics.errors.length,
                slowInteractions: this.metrics.slowInteractions.length
            },
            details: this.metrics,
            recommendations: this.generateRecommendations()
        };

        return report;
    }

    generateRecommendations() {
        const recommendations = [];

        // Check for slow resources
        const slowResources = this.metrics.resources.filter(r => r.duration > 1000);
        if (slowResources.length > 0) {
            recommendations.push({
                type: 'slow_resources',
                message: `${slowResources.length} resources took over 1 second to load`,
                resources: slowResources.map(r => r.name)
            });
        }

        // Check for large resources
        const largeResources = this.metrics.resources.filter(r => r.size > 500000);
        if (largeResources.length > 0) {
            recommendations.push({
                type: 'large_resources',
                message: `${largeResources.length} resources are over 500KB`,
                resources: largeResources.map(r => ({ name: r.name, size: r.size }))
            });
        }

        // Check for render-blocking resources
        const renderBlockingScripts = this.metrics.resources.filter(r => 
            r.type === 'script' && r.timing.download > 100
        );
        if (renderBlockingScripts.length > 0) {
            recommendations.push({
                type: 'render_blocking',
                message: 'Consider deferring or async loading scripts',
                resources: renderBlockingScripts.map(r => r.name)
            });
        }

        return recommendations;
    }
}

// Initialize debugger
const frontendDebugger = new FrontendDebugger();

// Expose for console access
window.wpDebug = {
    getReport: () => frontendDebugger.generateReport(),
    getMetrics: () => frontendDebugger.metrics,
    measureFunction: (fn, name = 'function') => {
        const startMark = `${name}-start`;
        const endMark = `${name}-end`;
        const measureName = `${name}-duration`;

        performance.mark(startMark);
        const result = fn();
        performance.mark(endMark);
        performance.measure(measureName, startMark, endMark);

        const measure = performance.getEntriesByName(measureName)[0];
        console.log(`${name} took ${measure.duration}ms`);

        return result;
    }
};

CSS Performance Analysis

// CSS performance analyzer
class CSSPerformanceAnalyzer {
    analyze() {
        const analysis = {
            stylesheets: this.analyzeStylesheets(),
            unusedRules: this.findUnusedCSS(),
            complexSelectors: this.findComplexSelectors(),
            performance: this.measureCSSPerformance()
        };

        return analysis;
    }

    analyzeStylesheets() {
        const stylesheets = Array.from(document.styleSheets);

        return stylesheets.map(sheet => {
            try {
                const rules = Array.from(sheet.cssRules || []);

                return {
                    href: sheet.href,
                    ruleCount: rules.length,
                    size: this.estimateStylesheetSize(rules),
                    mediaQueries: rules.filter(r => r.type === CSSRule.MEDIA_RULE).length,
                    keyframes: rules.filter(r => r.type === CSSRule.KEYFRAMES_RULE).length,
                    imports: rules.filter(r => r.type === CSSRule.IMPORT_RULE).length
                };
            } catch (e) {
                // Cross-origin stylesheet
                return {
                    href: sheet.href,
                    error: 'Cross-origin stylesheet',
                    ruleCount: 'unknown'
                };
            }
        });
    }

    estimateStylesheetSize(rules) {
        let size = 0;

        rules.forEach(rule => {
            if (rule.cssText) {
                size += rule.cssText.length;
            }
        });

        return size;
    }

    findUnusedCSS() {
        const allRules = this.getAllCSSRules();
        const unusedRules = [];

        allRules.forEach(rule => {
            if (rule.type === CSSRule.STYLE_RULE) {
                try {
                    const matches = document.querySelectorAll(rule.selectorText);
                    if (matches.length === 0) {
                        unusedRules.push({
                            selector: rule.selectorText,
                            stylesheet: rule.parentStyleSheet.href || 'inline'
                        });
                    }
                } catch (e) {
                    // Invalid selector
                }
            }
        });

        return unusedRules;
    }

    getAllCSSRules() {
        const allRules = [];

        Array.from(document.styleSheets).forEach(sheet => {
            try {
                Array.from(sheet.cssRules || []).forEach(rule => {
                    allRules.push(rule);
                });
            } catch (e) {
                // Cross-origin stylesheet
            }
        });

        return allRules;
    }

    findComplexSelectors() {
        const allRules = this.getAllCSSRules();
        const complexSelectors = [];

        allRules.forEach(rule => {
            if (rule.type === CSSRule.STYLE_RULE) {
                const complexity = this.calculateSelectorComplexity(rule.selectorText);

                if (complexity.score > 30) {
                    complexSelectors.push({
                        selector: rule.selectorText,
                        complexity: complexity,
                        stylesheet: rule.parentStyleSheet.href || 'inline'
                    });
                }
            }
        });

        return complexSelectors.sort((a, b) => b.complexity.score - a.complexity.score);
    }

    calculateSelectorComplexity(selector) {
        const parts = selector.split(/[\s>+~]/);
        let score = 0;
        let depth = 0;

        parts.forEach(part => {
            // ID selectors
            const ids = (part.match(/#/g) || []).length;
            score += ids * 100;

            // Class selectors
            const classes = (part.match(/\./g) || []).length;
            score += classes * 10;

            // Attribute selectors
            const attributes = (part.match(/\[/g) || []).length;
            score += attributes * 10;

            // Pseudo-classes
            const pseudoClasses = (part.match(/:/g) || []).length;
            score += pseudoClasses * 10;

            if (part.trim()) depth++;
        });

        // Penalize deep nesting
        score += depth * 5;

        return {
            score: score,
            depth: depth,
            ids: (selector.match(/#/g) || []).length,
            classes: (selector.match(/\./g) || []).length,
            attributes: (selector.match(/\[/g) || []).length
        };
    }

    measureCSSPerformance() {
        const measurements = {
            recalculateStyle: [],
            layout: [],
            paint: []
        };

        // Create observer for style recalculations
        const observer = new PerformanceObserver(list => {
            list.getEntries().forEach(entry => {
                if (entry.name === 'recalculate-style') {
                    measurements.recalculateStyle.push({
                        duration: entry.duration,
                        startTime: entry.startTime
                    });
                } else if (entry.name === 'layout') {
                    measurements.layout.push({
                        duration: entry.duration,
                        startTime: entry.startTime
                    });
                } else if (entry.name === 'paint') {
                    measurements.paint.push({
                        duration: entry.duration,
                        startTime: entry.startTime
                    });
                }
            });
        });

        // This would need browser support for measure user timing
        // Currently experimental

        return measurements;
    }
}

Advanced Debugging Techniques

Automated Performance Regression Detection

// Performance regression detector
class Performance_Regression_Detector {

    private $baseline_file;
    private $threshold = 0.1; // 10% regression threshold

    public function __construct($baseline_file = null) {
        $this->baseline_file = $baseline_file ?: WP_CONTENT_DIR . '/performance-baseline.json';
    }

    public function capture_baseline() {
        $metrics = $this->collect_current_metrics();

        file_put_contents($this->baseline_file, json_encode($metrics, JSON_PRETTY_PRINT));

        return $metrics;
    }

    public function check_for_regression() {
        if (!file_exists($this->baseline_file)) {
            return ['error' => 'No baseline found. Run capture_baseline() first.'];
        }

        $baseline = json_decode(file_get_contents($this->baseline_file), true);
        $current = $this->collect_current_metrics();

        $regressions = [];

        foreach ($baseline as $metric => $baseline_value) {
            if (isset($current[$metric])) {
                $current_value = $current[$metric];
                $change = ($current_value - $baseline_value) / $baseline_value;

                if ($change > $this->threshold) {
                    $regressions[] = [
                        'metric' => $metric,
                        'baseline' => $baseline_value,
                        'current' => $current_value,
                        'regression' => round($change * 100, 2) . '%'
                    ];
                }
            }
        }

        return [
            'regressions' => $regressions,
            'current_metrics' => $current,
            'baseline_metrics' => $baseline
        ];
    }

    private function collect_current_metrics() {
        $metrics = [];

        // Measure homepage load time
        $start = microtime(true);
        $this->load_page(home_url());
        $metrics['homepage_load_time'] = microtime(true) - $start;

        // Database metrics
        global $wpdb;
        $metrics['total_queries'] = $wpdb->num_queries;

        // Memory metrics
        $metrics['peak_memory'] = memory_get_peak_usage();

        // Plugin/theme metrics
        $metrics['active_plugins'] = count(get_option('active_plugins'));
        $metrics['registered_scripts'] = count($GLOBALS['wp_scripts']->registered);
        $metrics['registered_styles'] = count($GLOBALS['wp_styles']->registered);

        // Cache metrics
        $metrics['object_cache_hits'] = wp_cache_get_hits();
        $metrics['object_cache_misses'] = wp_cache_get_misses();

        return $metrics;
    }

    private function load_page($url) {
        // Simulate page load
        $response = wp_remote_get($url);
        return !is_wp_error($response);
    }
}

// Usage
$detector = new Performance_Regression_Detector();

// Capture baseline after optimizations
$detector->capture_baseline();

// Check for regressions after changes
$results = $detector->check_for_regression();
if (!empty($results['regressions'])) {
    foreach ($results['regressions'] as $regression) {
        error_log(sprintf(
            "Performance regression detected: %s increased by %s",
            $regression['metric'],
            $regression['regression']
        ));
    }
}

Debug Command Line Interface

// WP-CLI commands for performance debugging
if (defined('WP_CLI') && WP_CLI) {

    class Performance_Debug_CLI {

        /**
         * Analyze WordPress performance
         * 
         * ## OPTIONS
         * 
         * [--type=<type>]
         * : Type of analysis to run (all, database, plugins, theme)
         * 
         * [--export=<file>]
         * : Export results to file
         * 
         * ## EXAMPLES
         * 
         * wp performance analyze --type=database
         * wp performance analyze --export=report.json
         */
        public function analyze($args, $assoc_args) {
            $type = $assoc_args['type'] ?? 'all';

            WP_CLI::log('Starting performance analysis...');

            $results = [];

            if ($type === 'all' || $type === 'database') {
                WP_CLI::log('Analyzing database performance...');
                $results['database'] = $this->analyze_database();
            }

            if ($type === 'all' || $type === 'plugins') {
                WP_CLI::log('Analyzing plugin performance...');
                $results['plugins'] = $this->analyze_plugins();
            }

            if ($type === 'all' || $type === 'theme') {
                WP_CLI::log('Analyzing theme performance...');
                $results['theme'] = $this->analyze_theme();
            }

            // Display results
            $this->display_results($results);

            // Export if requested
            if (isset($assoc_args['export'])) {
                file_put_contents($assoc_args['export'], json_encode($results, JSON_PRETTY_PRINT));
                WP_CLI::success("Results exported to {$assoc_args['export']}");
            }
        }

        private function analyze_database() {
            global $wpdb;

            $analysis = [
                'table_sizes' => [],
                'slow_queries' => [],
                'missing_indexes' => []
            ];

            // Get table sizes
            $tables = $wpdb->get_results("
                SELECT table_name, 
                       ROUND(((data_length + index_length) / 1024 / 1024), 2) AS size_mb
                FROM information_schema.TABLES 
                WHERE table_schema = '" . DB_NAME . "'
                ORDER BY (data_length + index_length) DESC
            ");

            foreach ($tables as $table) {
                $analysis['table_sizes'][$table->table_name] = $table->size_mb . ' MB';
            }

            // Check for missing indexes
            $missing_indexes = $this->check_missing_indexes();
            $analysis['missing_indexes'] = $missing_indexes;

            return $analysis;
        }

        private function check_missing_indexes() {
            global $wpdb;

            $suggestions = [];

            // Check postmeta for common queries
            $result = $wpdb->get_var("
                SELECT COUNT(*) 
                FROM information_schema.STATISTICS 
                WHERE TABLE_SCHEMA = '" . DB_NAME . "' 
                AND TABLE_NAME = '{$wpdb->postmeta}' 
                AND INDEX_NAME = 'meta_key_value'
            ");

            if (!$result) {
                $suggestions[] = "CREATE INDEX meta_key_value ON {$wpdb->postmeta} (meta_key, meta_value(20))";
            }

            return $suggestions;
        }

        private function analyze_plugins() {
            $plugins = get_plugins();
            $active_plugins = get_option('active_plugins');

            $analysis = [];

            foreach ($active_plugins as $plugin_file) {
                if (isset($plugins[$plugin_file])) {
                    $plugin_data = $plugins[$plugin_file];

                    // Measure plugin impact
                    $impact = $this->measure_plugin_impact($plugin_file);

                    $analysis[$plugin_data['Name']] = [
                        'version' => $plugin_data['Version'],
                        'hooks' => $impact['hooks'],
                        'memory' => size_format($impact['memory']),
                        'load_time' => round($impact['load_time'] * 1000, 2) . 'ms'
                    ];
                }
            }

            return $analysis;
        }

        private function measure_plugin_impact($plugin_file) {
            // This is a simplified measurement
            // In reality, you'd need to profile each plugin individually

            global $wp_filter;
            $plugin_dir = dirname($plugin_file);
            $hook_count = 0;

            foreach ($wp_filter as $hook => $priorities) {
                foreach ($priorities as $priority => $functions) {
                    foreach ($functions as $function) {
                        if (is_string($function['function']) && 
                            strpos($function['function'], $plugin_dir) !== false) {
                            $hook_count++;
                        }
                    }
                }
            }

            return [
                'hooks' => $hook_count,
                'memory' => rand(1048576, 10485760), // Placeholder
                'load_time' => rand(10, 100) / 1000 // Placeholder
            ];
        }

        private function analyze_theme() {
            $theme = wp_get_theme();

            return [
                'name' => $theme->get('Name'),
                'version' => $theme->get('Version'),
                'template_files' => count($theme->get_files('php')),
                'style_files' => count($theme->get_files('css')),
                'script_files' => count($theme->get_files('js')),
                'total_size' => size_format($this->get_directory_size(get_stylesheet_directory()))
            ];
        }

        private function get_directory_size($dir) {
            $size = 0;

            foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator($dir)) as $file) {
                if ($file->isFile()) {
                    $size += $file->getSize();
                }
            }

            return $size;
        }

        private function display_results($results) {
            foreach ($results as $section => $data) {
                WP_CLI::log("\n" . strtoupper($section) . " ANALYSIS:");
                WP_CLI::log(str_repeat('-', 50));

                if ($section === 'database') {
                    WP_CLI::log("\nTable Sizes:");
                    foreach ($data['table_sizes'] as $table => $size) {
                        WP_CLI::log("  $table: $size");
                    }

                    if (!empty($data['missing_indexes'])) {
                        WP_CLI::log("\nSuggested Indexes:");
                        foreach ($data['missing_indexes'] as $index) {
                            WP_CLI::log("  $index");
                        }
                    }
                } elseif ($section === 'plugins') {
                    foreach ($data as $plugin => $info) {
                        WP_CLI::log("\n$plugin:");
                        foreach ($info as $key => $value) {
                            WP_CLI::log("  $key: $value");
                        }
                    }
                } else {
                    foreach ($data as $key => $value) {
                        WP_CLI::log("  $key: $value");
                    }
                }
            }
        }
    }

    WP_CLI::add_command('performance', 'Performance_Debug_CLI');
}

Debugging Best Practices

Performance Debug Checklist

// Comprehensive debugging checklist
class Performance_Debug_Checklist {

    private $checks = [
        'environment' => [
            'wp_debug_enabled' => 'WP_DEBUG is enabled',
            'query_logging' => 'SAVEQUERIES is enabled',
            'error_display' => 'Error display is configured',
            'debug_log' => 'Debug log is writable'
        ],
        'database' => [
            'slow_query_log' => 'MySQL slow query log is enabled',
            'table_optimization' => 'Tables are optimized',
            'index_analysis' => 'Indexes are analyzed',
            'query_patterns' => 'Query patterns are reviewed'
        ],
        'plugins' => [
            'conflict_test' => 'Plugin conflicts tested',
            'performance_impact' => 'Individual plugin impact measured',
            'hook_analysis' => 'Hook usage analyzed',
            'resource_usage' => 'Resource usage profiled'
        ],
        'frontend' => [
            'browser_tools' => 'Browser DevTools profiling completed',
            'network_analysis' => 'Network waterfall analyzed',
            'javascript_profiling' => 'JavaScript performance profiled',
            'css_optimization' => 'CSS delivery optimized'
        ],
        'server' => [
            'resource_monitoring' => 'Server resources monitored',
            'error_logs' => 'Server error logs reviewed',
            'configuration' => 'Server configuration optimized',
            'caching_layers' => 'Caching layers verified'
        ]
    ];

    public function run_checklist() {
        $results = [];

        foreach ($this->checks as $category => $items) {
            $results[$category] = [];

            foreach ($items as $check => $description) {
                $method = 'check_' . $check;

                if (method_exists($this, $method)) {
                    $results[$category][$check] = [
                        'description' => $description,
                        'status' => $this->$method(),
                        'recommendation' => $this->get_recommendation($check)
                    ];
                }
            }
        }

        return $results;
    }

    private function check_wp_debug_enabled() {
        return defined('WP_DEBUG') && WP_DEBUG;
    }

    private function check_query_logging() {
        return defined('SAVEQUERIES') && SAVEQUERIES;
    }

    private function check_debug_log() {
        $log_file = WP_CONTENT_DIR . '/debug.log';
        return is_writable(dirname($log_file));
    }

    private function get_recommendation($check) {
        $recommendations = [
            'wp_debug_enabled' => 'Enable WP_DEBUG in wp-config.php',
            'query_logging' => 'Set SAVEQUERIES to true for query analysis',
            'debug_log' => 'Ensure wp-content directory is writable',
            'slow_query_log' => 'Enable slow_query_log in MySQL configuration'
        ];

        return $recommendations[$check] ?? 'Review and optimize';
    }

    public function generate_report() {
        $checklist_results = $this->run_checklist();

        $report = "=== WordPress Performance Debug Checklist ===\n\n";

        foreach ($checklist_results as $category => $checks) {
            $report .= strtoupper($category) . ":\n";

            foreach ($checks as $check => $result) {
                $status = $result['status'] ? '✓' : '✗';
                $report .= sprintf(
                    "  %s %s\n",
                    $status,
                    $result['description']
                );

                if (!$result['status']) {
                    $report .= "     → " . $result['recommendation'] . "\n";
                }
            }

            $report .= "\n";
        }

        return $report;
    }
}

// Generate and display checklist
$checklist = new Performance_Debug_Checklist();
echo $checklist->generate_report();

Next Steps

Now that you've mastered WordPress performance debugging:

  1. Set Up Monitoring: Implement continuous performance monitoring
  2. Create Baselines: Establish performance baselines for comparison
  3. Automate Testing: Add performance tests to your deployment pipeline
  4. Document Issues: Keep a log of performance issues and solutions

For comprehensive performance optimization strategies, explore our complete WordPress Performance Optimization guide.


Last updated: July 12, 2025