# metasync/2.7.2/admin/class-metasync-otto-debug.php

Search Atlas SEO – OTTO AI SEO Automation for WordPress, version 2.7.2. 1,259 lines.

- Page: https://pluginprobe.com/plugins/metasync/2.7.2/code/admin/class-metasync-otto-debug.php
- Raw: https://pluginprobe.com/plugins/metasync/2.7.2/raw/admin/class-metasync-otto-debug.php
- Modified: 2026-10-07T12:05:24+00:00

Line numbers below start at 1. Link to a line or a range by appending a fragment to the
page URL, for example `https://pluginprobe.com/plugins/metasync/2.7.2/code/admin/class-metasync-otto-debug.php#L10-L20`.

```php
<?php
/**
 * OTTO Debug Page for MetaSync Plugin
 * 
 * This class provides comprehensive diagnostics for OTTO functionality
 * to help developers troubleshoot why OTTO changes are not being applied.
 * 
 * @package MetaSync
 * @subpackage MetaSync/admin
 * @since 1.0.0
 */

// Prevent direct access
if (!defined('ABSPATH')) {
    exit;
}

class Metasync_Otto_Debug {
    
    /**
     * The plugin name
     */
    private $plugin_name;
    
    /**
     * The plugin version
     */
    private $version;
    
    /**
     * Constructor
     */
    public function __construct($plugin_name, $version) {
        $this->plugin_name = $plugin_name;
        $this->version = $version;
        
        // Add admin menu
        add_action('admin_menu', array($this, 'add_debug_menu'));
        
        // Add AJAX handlers
        add_action('wp_ajax_metasync_otto_debug_test_api', array($this, 'ajax_test_otto_api'));
        add_action('wp_ajax_metasync_otto_debug_test_notification', array($this, 'ajax_test_notification_endpoint'));
        add_action('wp_ajax_metasync_otto_debug_clear_cache', array($this, 'ajax_clear_otto_cache'));
        add_action('wp_ajax_metasync_otto_debug_simulate_crawl', array($this, 'ajax_simulate_crawl_notification'));
        add_action('wp_ajax_metasync_otto_debug_test_url', array($this, 'ajax_test_specific_url'));
        add_action('wp_ajax_metasync_otto_debug_emulate_changes', array($this, 'ajax_emulate_otto_changes'));
        add_action('wp_ajax_metasync_otto_debug_simple_test', array($this, 'ajax_simple_test'));
        add_action('wp_ajax_metasync_otto_debug_test_db_permissions', array($this, 'ajax_test_db_permissions'));
    }
    
    
    /**
     * Whether debug tooling is allowed to run at all right now.
     *
     * `manage_options` alone isn't a real restriction — every site admin has
     * it, so this page and its AJAX handlers were reachable by anyone on any
     * site. Hard-disabled: the menu item, the page, and every AJAX handler
     * are unreachable for all users on all sites, no toggle or capability
     * bypasses this. The class and its methods are left in place; only
     * access is blocked.
     */
    private static function is_debug_tools_enabled() {
        return false;
    }

    /**
     * Whether a URL's crawl pipeline has completed, per the bounded
     * Metasync_Otto_Job_Status store. Replaces the legacy unbounded
     * metasync_otto_crawldata option lookup: state history is pruned
     * 48 hours after completion, so a URL finished longer ago reads as
     * "not crawled" here without implying Otto never touched it.
     */
    private static function is_url_crawled($url) {
        if (!class_exists('Metasync_Otto_Job_Status')) {
            return false;
        }
        $entry = Metasync_Otto_Job_Status::get($url);
        return is_array($entry)
            && isset($entry['state'])
            && $entry['state'] === Metasync_Otto_Job_Status::STATE_COMPLETED;
    }

    /**
     * Add debug menu (internal only - hidden on customer production sites)
     */
    public function add_debug_menu() {
        if (!current_user_can('manage_options') || !self::is_debug_tools_enabled()) {
            return;
        }
        
        $menu_slug = Metasync_Admin::$page_slug;
        
        add_submenu_page(
            $menu_slug,
            Metasync::get_whitelabel_otto_name() . ' Debug',
            Metasync::get_whitelabel_otto_name() . ' Debug',
            'manage_options',
            $menu_slug . '-otto-debug',
            array($this, 'create_debug_page')
        );
    }
    
    /**
     * Create the debug page
     */
    public function create_debug_page() {
        if (!current_user_can('manage_options') || !self::is_debug_tools_enabled()) {
            wp_die('Unauthorized');
        }

        $whitelabel_otto_name = Metasync::get_whitelabel_otto_name();
        ?>
        <div class="wrap metasync-otto-debug">
            <h1><?php echo esc_html($whitelabel_otto_name); ?> Debug & Diagnostics</h1>
            <p class="description">Comprehensive diagnostics for <?php echo esc_html($whitelabel_otto_name); ?> functionality. This page helps identify why <?php echo esc_html($whitelabel_otto_name); ?> changes may not be applied.</p>
            
            <div class="metasync-debug-container">
                <?php $this->render_developer_access_status(); ?>
                <?php $this->render_url_testing_section(); ?>
                <?php $this->render_configuration_status(); ?>
                <?php $this->render_notification_endpoint_status(); ?>
                <?php $this->render_api_connectivity_status(); ?>
                <?php $this->render_processing_status(); ?>
                <?php $this->render_debug_tools(); ?>
            </div>
        </div>
        
        <style>
        .metasync-debug-container {
            display: grid;
            grid-template-columns: 1fr 1fr;
            gap: 20px;
            margin-top: 20px;
        }
        
        .debug-section {
            background: #fff;
            border: 1px solid #ccd0d4;
            border-radius: 4px;
            padding: 20px;
            box-shadow: 0 1px 1px rgba(0,0,0,.04);
        }
        
        .debug-section h3 {
            margin-top: 0;
            color: #23282d;
            border-bottom: 1px solid #eee;
            padding-bottom: 10px;
        }
        
        .status-indicator {
            display: inline-block;
            width: 12px;
            height: 12px;
            border-radius: 50%;
            margin-right: 8px;
        }
        
        .status-success { background-color: #46b450; }
        .status-warning { background-color: #ffb900; }
        .status-error { background-color: #dc3232; }
        .status-info { background-color: #00a0d2; }
        
        .debug-item {
            margin: 10px 0;
            padding: 8px;
            background: #f9f9f9;
            border-left: 4px solid #ddd;
        }
        
        .debug-item.success { border-left-color: #46b450; }
        .debug-item.warning { border-left-color: #ffb900; }
        .debug-item.error { border-left-color: #dc3232; }
        .debug-item.info { border-left-color: #00a0d2; }
        
        .debug-value {
            font-family: monospace;
            background: #fff;
            padding: 4px 8px;
            border: 1px solid #ddd;
            border-radius: 3px;
            word-break: break-all;
        }
        
        .debug-tools {
            grid-column: 1 / -1;
        }
        
        .debug-button {
            background: #0073aa;
            color: white;
            border: none;
            padding: 8px 16px;
            border-radius: 3px;
            cursor: pointer;
            margin: 5px;
        }
        
        .debug-button:hover {
            background: #005a87;
        }
        
        .debug-button.danger {
            background: #dc3232;
        }
        
        .debug-button.danger:hover {
            background: #a00;
        }
        
        .debug-results {
            margin-top: 15px;
            padding: 15px;
            background: #f1f1f1;
            border-radius: 3px;
            display: none;
        }
        
        .debug-results.show {
            display: block;
        }
        
        .debug-results .error {
            background: #f8d7da;
            border: 1px solid #f5c6cb;
            color: #721c24;
            padding: 10px;
            border-radius: 4px;
            margin: 10px 0;
        }
        
        .json-output {
            background: #fff;
            border: 1px solid #ddd;
            padding: 10px;
            border-radius: 3px;
            font-family: monospace;
            white-space: pre-wrap;
            max-height: 300px;
            overflow-y: auto;
        }
        </style>
        <?php
    }
    
    /**
     * Render developer access status section
     */
    private function render_developer_access_status() {
        $current_user = wp_get_current_user();
        ?>
        <div class="debug-section">
            <h3><span class="status-indicator status-success"></span>Administrator Access</h3>
            
            <div class="debug-item success">
                <strong>Debug Access:</strong>
                <span class="debug-value">Granted via manage_options</span>
            </div>
            
            <div class="debug-item info">
                <strong>Current User:</strong>
                <span class="debug-value"><?php echo esc_html($current_user->user_login); ?> (ID: <?php echo (int) $current_user->ID; ?>)</span>
            </div>
            
            <div class="debug-item info">
                <strong>User Roles:</strong>
                <span class="debug-value"><?php echo esc_html(implode(', ', $current_user->roles)); ?></span>
            </div>
            
            <div class="debug-item success">
                <strong>Debug Access Active</strong>
                <p>You have access to all <?php echo esc_html(Metasync::get_whitelabel_otto_name()); ?> debug tools and diagnostics.</p>
            </div>
        </div>
        <?php
    }
    
    /**
     * Render URL testing section
     */
    private function render_url_testing_section() {
        $whitelabel_otto_name = Metasync::get_whitelabel_otto_name();
        $site_url = get_site_url();
        ?>
        <div class="debug-section debug-tools">
            <h3><span class="status-indicator status-info"></span>URL Testing & <?php echo esc_html($whitelabel_otto_name); ?> Emulation</h3>

            <div class="debug-item info">
                <strong>Test Specific URL:</strong>
                <p>Enter any URL from your site to test <?php echo esc_html($whitelabel_otto_name); ?> functionality and check all diagnostic points.</p>
            </div>

            <div style="margin-bottom: 20px;">
                <label for="test-url-input"><strong>URL to Test:</strong></label><br>
                <input type="url" id="test-url-input" placeholder="<?php echo esc_attr($site_url); ?>/sample-page/" style="width: 100%; padding: 8px; margin: 5px 0;" />
                <br>
                <button id="test-specific-url" class="debug-button">Test URL & Check All Points</button>
                <button id="emulate-otto-changes" class="debug-button">Emulate <?php echo esc_html($whitelabel_otto_name); ?> Changes</button>
                <button id="simple-ajax-test" class="debug-button">Test AJAX Connection</button>
            </div>
            
            <div id="url-test-results" class="debug-results"></div>
            <div id="emulation-results" class="debug-results"></div>
            
            <div class="debug-item info">
                <strong>What This Tests:</strong>
                <ul style="margin-left: 20px;">
                    <li>URL accessibility and response</li>
                    <li><?php echo esc_html($whitelabel_otto_name); ?> API data for the specific URL</li>
                    <li>Crawl status and processing eligibility</li>
                    <li>Page type detection and exclusions</li>
                    <li><?php echo esc_html($whitelabel_otto_name); ?> recommendations and changes</li>
                    <li>Error simulation and validation</li>
                </ul>
            </div>
            
            <div class="debug-item warning">
                <strong>Database Permissions Check:</strong>
                <p>Testing if Action Scheduler can schedule jobs...</p>
                <button id="test-db-permissions" class="debug-button">Test Database Permissions</button>
                <div id="db-permissions-results" class="debug-results"></div>
            </div>
        </div>
        <?php
    }
    
    /**
     * Render configuration status section
     */
    private function render_configuration_status() {
        $whitelabel_otto_name = Metasync::get_whitelabel_otto_name();
        $general_options = Metasync::get_option('general');
        
        // OTTO SSR is always enabled by default
        $otto_enabled = true;
        $otto_uuid = $general_options['otto_pixel_uuid'] ?? '';
        $otto_disable_loggedin = $general_options['otto_disable_on_loggedin'] ?? false;
        
        ?>
        <div class="debug-section">
            <h3><span class="status-indicator <?php echo !empty($otto_uuid) ? 'status-success' : 'status-error'; ?>"></span>Configuration Status</h3>
            
            <div class="debug-item success">
                <strong><?php echo esc_html($whitelabel_otto_name); ?> SSR Enabled:</strong>
                <span class="debug-value">Yes (Always Active)</span>
            </div>
            
            <div class="debug-item <?php echo !empty($otto_uuid) ? 'success' : 'error'; ?>">
                <strong><?php echo esc_html($whitelabel_otto_name); ?> UUID:</strong>
                <span class="debug-value"><?php echo !empty($otto_uuid) ? esc_html($otto_uuid) : 'Not Set'; ?></span>
            </div>
            
            <div class="debug-item <?php echo $otto_disable_loggedin ? 'warning' : 'info'; ?>">
                <strong>Disable for Logged-in Users:</strong>
                <span class="debug-value"><?php echo $otto_disable_loggedin ? 'Yes' : 'No'; ?></span>
            </div>
            
            <div class="debug-item info">
                <strong>Current User Logged In:</strong>
                <span class="debug-value"><?php echo is_user_logged_in() ? 'Yes' : 'No'; ?></span>
            </div>
            
            <div class="debug-item info">
                <strong>Plugin Version:</strong>
                <span class="debug-value"><?php echo esc_html(defined('METASYNC_VERSION') ? METASYNC_VERSION : 'Unknown'); ?></span>
            </div>
        </div>
        <?php
    }
    
    /**
     * Render notification endpoint status
     */
    private function render_notification_endpoint_status() {
        $rest_url = rest_url('metasync/v1/otto_crawl_notify');
        $site_url = get_site_url();
        
        ?>
        <div class="debug-section">
            <h3><span class="status-indicator status-info"></span>Notification Endpoint Status</h3>
            
            <div class="debug-item info">
                <strong>REST API Base URL:</strong>
                <span class="debug-value"><?php echo esc_html($site_url); ?></span>
            </div>
            
            <div class="debug-item info">
                <strong><?php echo esc_html(Metasync::get_whitelabel_otto_name()); ?> Notification Endpoint:</strong>
                <span class="debug-value"><?php echo esc_html($rest_url); ?></span>
            </div>
            
            <div class="debug-item <?php echo function_exists('rest_url') ? 'success' : 'error'; ?>">
                <strong>REST API Available:</strong>
                <span class="debug-value"><?php echo function_exists('rest_url') ? 'Yes' : 'No'; ?></span>
            </div>
            
            <div class="debug-item <?php echo $this->is_rest_endpoint_registered() ? 'success' : 'error'; ?>">
                <strong>Endpoint Registered:</strong>
                <span class="debug-value"><?php echo $this->is_rest_endpoint_registered() ? 'Yes' : 'No'; ?></span>
            </div>
            
            <div class="debug-item info">
                <strong>Expected Method:</strong>
                <span class="debug-value">POST</span>
            </div>
            
            <div class="debug-item info">
                <strong>Expected JSON Fields:</strong>
                <span class="debug-value">domain, urls</span>
            </div>
        </div>
        <?php
    }
    
    /**
     * Render API connectivity status
     */
    private function render_api_connectivity_status() {
        $general_options = Metasync::get_option('general');
        $otto_uuid = $general_options['otto_pixel_uuid'] ?? '';

        # Use endpoint manager to get the correct API URL
        $api_url = class_exists('Metasync_Endpoint_Manager')
            ? Metasync_Endpoint_Manager::get_endpoint('OTTO_URL_DETAILS')
            : 'https://sa.searchatlas.com/api/v2/otto-url-details';
        $test_url = add_query_arg(array(
            'url' => get_site_url(),
            'uuid' => $otto_uuid
        ), $api_url);
        
        ?>
        <div class="debug-section">
            <h3><span class="status-indicator status-info"></span>API Connectivity Status</h3>
            
            <div class="debug-item info">
                <strong><?php echo esc_html(Metasync::get_whitelabel_otto_name()); ?> API Endpoint:</strong>
                <span class="debug-value"><?php echo esc_html($api_url); ?></span>
            </div>
            
            <div class="debug-item info">
                <strong>Test URL:</strong>
                <span class="debug-value"><?php echo esc_html($test_url); ?></span>
            </div>
            
            <div class="debug-item <?php echo $this->can_reach_otto_api() ? 'success' : 'error'; ?>">
                <strong>API Reachable:</strong>
                <span class="debug-value"><?php echo $this->can_reach_otto_api() ? 'Yes' : 'No'; ?></span>
            </div>
            
            <div class="debug-item info">
                <strong>SSL Verification:</strong>
                <span class="debug-value">Enabled</span>
            </div>
            
            <div class="debug-item info">
                <strong>Timeout:</strong>
                <span class="debug-value">30 seconds</span>
            </div>
            
            <div class="debug-item info">
                <strong>User Agent:</strong>
                <span class="debug-value">MetaSync-WordPress-Plugin/1.0</span>
            </div>
        </div>
        <?php
    }
    
    /**
     * Render processing status
     */
    private function render_processing_status() {
        $current_url = $this->get_current_url();
        $is_crawled = self::is_url_crawled($current_url);
        $render_diagnostics = $this->get_render_strategy_diagnostics();
        
        ?>
        <div class="debug-section">
            <h3><span class="status-indicator <?php echo $is_crawled ? 'status-success' : 'status-warning'; ?>"></span>Processing Status</h3>
            
            <div class="debug-item info">
                <strong>Current URL:</strong>
                <span class="debug-value"><?php echo esc_html($current_url); ?></span>
            </div>
            
            <div class="debug-item <?php echo $is_crawled ? 'success' : 'warning'; ?>">
                <strong>URL Crawled by <?php echo esc_html(Metasync::get_whitelabel_otto_name()); ?>:</strong>
                <span class="debug-value"><?php echo $is_crawled ? 'Yes' : 'No'; ?></span>
            </div>

            <div class="debug-item <?php echo $this->is_otto_excluded() ? 'warning' : 'info'; ?>">
                <strong><?php echo esc_html(Metasync::get_whitelabel_otto_name()); ?> Excluded:</strong>
                <span class="debug-value"><?php echo $this->is_otto_excluded() ? 'Yes' : 'No'; ?></span>
            </div>
            
            <div class="debug-item info">
                <strong>Page Type:</strong>
                <span class="debug-value"><?php echo esc_html($this->get_page_type()); ?></span>
            </div>
            
            <div class="debug-item info">
                <strong>Cache Status:</strong>
                <span class="debug-value"><?php echo esc_html($this->get_cache_status()); ?></span>
            </div>
            
            <div class="debug-item info">
                <strong>Processing Method:</strong>
                <span class="debug-value"><?php echo esc_html($this->get_processing_method()); ?></span>
            </div>
            
            <?php if (!empty($render_diagnostics) && isset($render_diagnostics['available']) === false): ?>
            <div class="debug-item info">
                <strong>Render Strategy:</strong>
                <div class="debug-value">
                    <ul style="margin: 5px 0 0 15px; padding: 0;">
                        <li><strong>PHP:</strong> <?php echo esc_html($render_diagnostics['php_version'] ?? 'Unknown'); ?></li>
                        <li><strong>WP:</strong> <?php echo esc_html($render_diagnostics['wp_version'] ?? 'Unknown'); ?></li>
                        <li><strong>Memory:</strong> <?php echo esc_html($render_diagnostics['memory_limit'] ?? 'Unknown'); ?> (used: <?php echo esc_html($render_diagnostics['memory_used'] ?? 'Unknown'); ?>)</li>
                        <li><strong>Buffer Level:</strong> <?php echo esc_html($render_diagnostics['buffer_level'] ?? 'Unknown'); ?></li>
                        <li><strong>Headers Sent:</strong> <?php echo ($render_diagnostics['headers_sent'] ?? false) ? 'Yes' : 'No'; ?></li>
                    </ul>
                </div>
            </div>
            
            <div class="debug-item info">
                <strong>Detected Plugins:</strong>
                <div class="debug-value">
                    <?php 
                    $plugins = $render_diagnostics['detected_plugins'] ?? [];
                    foreach ($plugins as $plugin => $active):
                    ?>
                        <span style="display: inline-block; margin: 2px 5px; padding: 2px 8px; background: <?php echo $active ? '#d4edda' : '#f8f9fa'; ?>; border-radius: 3px;">
                            <?php echo esc_html($plugin); ?>: <?php echo $active ? '✓' : '✗'; ?>
                        </span>
                    <?php endforeach; ?>
                </div>
            </div>
            
            <div class="debug-item info">
                <strong>Detected Hosts:</strong>
                <div class="debug-value">
                    <?php 
                    $hosts = $render_diagnostics['detected_hosts'] ?? [];
                    foreach ($hosts as $host => $detected):
                    ?>
                        <span style="display: inline-block; margin: 2px 5px; padding: 2px 8px; background: <?php echo $detected ? '#fff3cd' : '#f8f9fa'; ?>; border-radius: 3px;">
                            <?php echo esc_html($host); ?>: <?php echo $detected ? '✓' : '✗'; ?>
                        </span>
                    <?php endforeach; ?>
                </div>
            </div>
            <?php endif; ?>
        </div>
        <?php
    }
    
    /**
     * Render debug tools
     */
    private function render_debug_tools() {
        ?>
        <div class="debug-section debug-tools">
            <h3><span class="status-indicator status-info"></span>Debug Tools</h3>
            
            <div style="margin-bottom: 20px;">
                <button id="test-otto-api" class="debug-button">Test API Connectivity</button>
                <button id="test-notification-endpoint" class="debug-button">Test Notification Endpoint</button>
                <button id="simulate-crawl" class="debug-button">Simulate Crawl Notification</button>
                <button id="clear-otto-cache" class="debug-button danger">Clear <?php echo esc_html(Metasync::get_whitelabel_otto_name()); ?> Cache</button>
            </div>

            <div id="api-test-results" class="debug-results"></div>
            <div id="notification-test-results" class="debug-results"></div>
            <div id="crawl-simulate-results" class="debug-results"></div>
            <div id="cache-clear-results" class="debug-results"></div>

            <div class="debug-item info">
                <strong>Note:</strong> These tools help diagnose <?php echo esc_html(Metasync::get_whitelabel_otto_name()); ?> issues. Use with caution in production environments.
            </div>
        </div>
        <?php
    }
    
    /**
     * Check if REST endpoint is registered
     */
    private function is_rest_endpoint_registered() {
        $routes = rest_get_server()->get_routes();
        return isset($routes['/metasync/v1/otto_crawl_notify']);
    }
    
    /**
     * Check if OTTO API is reachable
     */
    private function can_reach_otto_api() {
        $general_options = Metasync::get_option('general');
        $otto_uuid = $general_options['otto_pixel_uuid'] ?? '';
        
        if (empty($otto_uuid)) {
            return false;
        }

        # Use endpoint manager to get the correct API URL
        $api_endpoint = class_exists('Metasync_Endpoint_Manager')
            ? Metasync_Endpoint_Manager::get_endpoint('OTTO_URL_DETAILS')
            : 'https://sa.searchatlas.com/api/v2/otto-url-details';

        $api_url = add_query_arg(array(
            'url' => get_site_url(),
            'uuid' => $otto_uuid
        ), $api_endpoint);
        
        $response = wp_remote_get($api_url, array(
            'timeout' => 10,
            'sslverify' => true
        ));
        
        return !is_wp_error($response) && wp_remote_retrieve_response_code($response) === 200;
    }
    
    /**
     * Get current URL
     */
    private function get_current_url() {
        $scheme = is_ssl() ? 'https' : 'http';
        $host = $_SERVER['HTTP_HOST'] ?? '';
        $uri = $_SERVER['REQUEST_URI'] ?? '';
        return $scheme . '://' . $host . $uri;
    }
    
    /**
     * Check if OTTO is excluded for current request
     */
    private function is_otto_excluded() {
        // Check AJAX requests
        if (wp_doing_ajax() || defined('DOING_AJAX') && DOING_AJAX) {
            return true;
        }
        
        // Check WooCommerce pages
        if (function_exists('is_woocommerce') && is_woocommerce()) {
            return true;
        }
        
        // Check logged-in user exclusion
        $general_options = Metasync::get_option('general');
        if (!empty($general_options['otto_disable_on_loggedin']) && 
            $general_options['otto_disable_on_loggedin'] === 'true' && 
            is_user_logged_in()) {
            return true;
        }
        
        return false;
    }
    
    /**
     * Get page type
     */
    private function get_page_type() {
        if (is_home()) return 'Home';
        if (is_front_page()) return 'Front Page';
        if (is_single()) return 'Single Post';
        if (is_page()) return 'Page';
        if (is_category()) return 'Category';
        if (is_tag()) return 'Tag';
        if (is_archive()) return 'Archive';
        if (is_search()) return 'Search';
        if (is_404()) return '404';
        return 'Other';
    }
    
    /**
     * Get cache status
     */
    private function get_cache_status() {
        // Cache is disabled in current implementation
        return 'Disabled (SSR Mode)';
    }
    
    /**
     * Get processing method
     */
    private function get_processing_method() {
        // OTTO SSR is always enabled by default
        $otto_enabled = true;
        
        if ($otto_enabled) {
            // Check which render strategy would be used
            if (class_exists('Metasync_Otto_Render_Strategy')) {
                $method = Metasync_Otto_Render_Strategy::determine_method();
                if ($method === Metasync_Otto_Render_Strategy::METHOD_BUFFER) {
                    return 'Server-Side Rendering (SSR) - Output Buffer (Fast)';
                } elseif ($method === Metasync_Otto_Render_Strategy::METHOD_HTTP) {
                    return 'Server-Side Rendering (SSR) - HTTP Request (Fallback)';
                }
            }
            return 'Server-Side Rendering (SSR)';
        } else {
            return 'Client-Side JavaScript';
        }
    }
    
    /**
     * Get render strategy diagnostics
     */
    public function get_render_strategy_diagnostics() {
        if (!class_exists('Metasync_Otto_Render_Strategy')) {
            return array(
                'available' => false,
                'message' => 'Render Strategy class not loaded'
            );
        }
        
        return Metasync_Otto_Render_Strategy::get_diagnostics();
    }
    
    /**
     * AJAX handler for testing OTTO API
     */
    public function ajax_test_otto_api() {
        check_ajax_referer('metasync_otto_debug', 'nonce');
        
        if (!current_user_can('manage_options') || !self::is_debug_tools_enabled()) {
            wp_die('Unauthorized');
        }
        
        $general_options = Metasync::get_option('general');
        $otto_uuid = $general_options['otto_pixel_uuid'] ?? '';
        
        if (empty($otto_uuid)) {
            wp_send_json_error(Metasync::get_whitelabel_otto_name() . ' UUID not configured');
        }
        
        $test_url = get_site_url();

        # Use endpoint manager to get the correct API URL
        $api_endpoint = class_exists('Metasync_Endpoint_Manager')
            ? Metasync_Endpoint_Manager::get_endpoint('OTTO_URL_DETAILS')
            : 'https://sa.searchatlas.com/api/v2/otto-url-details';

        $api_url = add_query_arg(array(
            'url' => $test_url,
            'uuid' => $otto_uuid
        ), $api_endpoint);
        
        $response = wp_remote_get($api_url, array(
            'timeout' => 30,
            'sslverify' => true,
            'headers' => array(
                'User-Agent' => 'MetaSync-WordPress-Plugin/1.0'
            )
        ));
        
        if (is_wp_error($response)) {
            wp_send_json_error(array(
                'error' => $response->get_error_message(),
                'url' => $api_url
            ));
        }
        
        $response_code = wp_remote_retrieve_response_code($response);
        $body = wp_remote_retrieve_body($response);
        
        wp_send_json_success(array(
            'response_code' => $response_code,
            'url' => $api_url,
            'body' => $body,
            'has_data' => !empty($body),
            'data_valid' => json_decode($body, true) !== null
        ));
    }
    
    /**
     * AJAX handler for testing notification endpoint
     */
    public function ajax_test_notification_endpoint() {
        check_ajax_referer('metasync_otto_debug', 'nonce');
        
        if (!current_user_can('manage_options') || !self::is_debug_tools_enabled()) {
            wp_die('Unauthorized');
        }
        
        $endpoint_url = rest_url('metasync/v1/otto_crawl_notify');
        
        $test_data = array(
            'domain' => get_site_url(),
            'urls' => array('/', '/about/', '/contact/')
        );
        
        $response = wp_remote_post($endpoint_url, array(
            'headers' => array(
                'Content-Type' => 'application/json'
            ),
            'body' => json_encode($test_data),
            'timeout' => 30
        ));
        
        if (is_wp_error($response)) {
            wp_send_json_error(array(
                'error' => $response->get_error_message(),
                'url' => $endpoint_url
            ));
        }
        
        $response_code = wp_remote_retrieve_response_code($response);
        $body = wp_remote_retrieve_body($response);
        
        wp_send_json_success(array(
            'response_code' => $response_code,
            'url' => $endpoint_url,
            'body' => $body,
            'test_data' => $test_data
        ));
    }
    
    /**
     * AJAX handler for clearing OTTO cache
     */
    public function ajax_clear_otto_cache() {
        check_ajax_referer('metasync_otto_debug', 'nonce');

        if (!current_user_can('manage_options') || !self::is_debug_tools_enabled()) {
            wp_die('Unauthorized');
        }

        // Clear the retired crawl-data option if an internal debug tool is
        // ever re-enabled. This explicit action is harmless and preserves
        // the old clear-cache contract; production never reaches this
        // handler because debug tools are hard-disabled.
        delete_option('metasync_otto_crawldata');

        // Clear any cached API responses
        $general_options = Metasync::get_option('general');
        $otto_uuid = $general_options['otto_pixel_uuid'] ?? '';

        if (!empty($otto_uuid)) {
            delete_transient(Metasync_Heartbeat_Manager::public_hash_cache_key($otto_uuid));
        }

        delete_transient('metasync_otto_js_detected');

        wp_send_json_success(array(
            'message' => Metasync::get_whitelabel_otto_name() . ' cache cleared successfully',
            'cleared_items' => array(
                'crawl_data' => true,
                'api_cache' => true
            )
        ));
    }
    
    /**
     * AJAX handler for simulating crawl notification
     */
    public function ajax_simulate_crawl_notification() {
        check_ajax_referer('metasync_otto_debug', 'nonce');
        
        if (!current_user_can('manage_options') || !self::is_debug_tools_enabled()) {
            wp_die('Unauthorized');
        }
        
        $general_options = Metasync::get_option('general');
        $otto_uuid = $general_options['otto_pixel_uuid'] ?? '';
        
        if (empty($otto_uuid)) {
            wp_send_json_error(Metasync::get_whitelabel_otto_name() . ' UUID not configured');
        }
        
        // Simulate crawl notification
        $test_data = array(
            'domain' => get_site_url(),
            'urls' => array('/', '/about/', '/contact/', '/blog/')
        );
        
        // Create a mock request object
        $request = new WP_REST_Request('POST', '/metasync/v1/otto_crawl_notify');
        $request->set_body(json_encode($test_data));
        
        // Call the notification handler
        $response = metasync_otto_crawl_notify($request);
        
        wp_send_json_success(array(
            'message' => 'Crawl notification simulated',
            'test_data' => $test_data,
            'response' => $response->get_data(),
            'response_code' => $response->get_status()
        ));
    }
    
    /**
     * AJAX handler for testing specific URL
     */
    public function ajax_test_specific_url() {
        try {
            check_ajax_referer('metasync_otto_debug', 'nonce');

            if (!current_user_can('manage_options') || !self::is_debug_tools_enabled()) {
                wp_die('Unauthorized');
            }

            $test_url = sanitize_url($_POST['test_url'] ?? '');

            if (empty($test_url)) {
                wp_send_json_error('No URL provided');
            }

            $results = array(
                'test_url' => $test_url,
                'timestamp' => current_time('mysql'),
                'tests' => array()
            );

            // Test 1: URL Accessibility
            $results['tests']['url_accessibility'] = $this->test_url_accessibility($test_url);

            // Test 2: OTTO API Data
            $results['tests']['otto_api_data'] = $this->test_otto_api_for_url($test_url);

            // Test 3: Crawl Status
            $results['tests']['crawl_status'] = $this->test_crawl_status($test_url);

            // Test 4: Page Type Detection
            $results['tests']['page_type_detection'] = $this->test_page_type_detection($test_url);

            // Test 5: Processing Eligibility
            $results['tests']['processing_eligibility'] = $this->test_processing_eligibility($test_url);

            wp_send_json_success($results);

        } catch (Exception $e) {
            error_log('MetaSync OTTO Debug: Exception in ajax_test_specific_url: ' . $e->getMessage()); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- unreachable in production
            wp_send_json_error('Exception: ' . $e->getMessage());
        }
    }
    
    /**
     * AJAX handler for emulating OTTO changes
     */
    public function ajax_emulate_otto_changes() {
        check_ajax_referer('metasync_otto_debug', 'nonce');
        
        if (!current_user_can('manage_options') || !self::is_debug_tools_enabled()) {
            wp_die('Unauthorized');
        }
        
        $test_url = sanitize_url($_POST['test_url'] ?? '');
        
        if (empty($test_url)) {
            wp_send_json_error('No URL provided');
        }
        
        $results = array(
            'test_url' => $test_url,
            'timestamp' => current_time('mysql'),
            'emulation' => array()
        );
        
        // Emulate OTTO processing
        $results['emulation'] = $this->emulate_otto_processing($test_url);
        
        wp_send_json_success($results);
    }
    
    /**
     * Test URL accessibility
     */
    private function test_url_accessibility($url) {
        $response = wp_remote_get($url, array(
            'timeout' => 10,
            'user-agent' => 'MetaSync Debug Tool'
        ));
        
        if (is_wp_error($response)) {
            return array(
                'status' => 'error',
                'message' => $response->get_error_message(),
                'accessible' => false
            );
        }
        
        $status_code = wp_remote_retrieve_response_code($response);
        $body = wp_remote_retrieve_body($response);
        
        return array(
            'status' => 'success',
            'status_code' => $status_code,
            'accessible' => $status_code === 200,
            'content_length' => strlen($body),
            'headers' => wp_remote_retrieve_headers($response)->getAll()
        );
    }
    
    /**
     * Test OTTO API data for specific URL
     */
    private function test_otto_api_for_url($url) {
        $general_options = Metasync::get_option('general');
        $otto_uuid = $general_options['otto_pixel_uuid'] ?? '';
        
        if (empty($otto_uuid)) {
            return array(
                'status' => 'error',
                'message' => Metasync::get_whitelabel_otto_name() . ' UUID not configured'
            );
        }
        
        // Use the existing OTTO API function
        if (function_exists('metasync_fetch_otto_seo_data')) {
            $data = metasync_fetch_otto_seo_data($url, $otto_uuid);
            
            if (is_wp_error($data)) {
                return array(
                    'status' => 'error',
                    'message' => $data->get_error_message(),
                    'has_data' => false
                );
            }
            
            return array(
                'status' => 'success',
                'has_data' => !empty($data),
                'data_keys' => array_keys($data ?? array()),
                'recommendations_count' => count($data['recommendations'] ?? array()),
                'sample_data' => array_slice($data ?? array(), 0, 3) // First 3 items for preview
            );
        }
        
        return array(
            'status' => 'error',
            'message' => Metasync::get_whitelabel_otto_name() . ' API function not available'
        );
    }
    
    /**
     * Test crawl status for URL
     */
    private function test_crawl_status($url) {
        if (class_exists('Metasync_Otto_Job_Status')) {
            $entry = Metasync_Otto_Job_Status::get($url);
            $is_crawled = is_array($entry)
                && isset($entry['state'])
                && $entry['state'] === Metasync_Otto_Job_Status::STATE_COMPLETED;

            return array(
                'status' => 'success',
                'is_crawled' => $is_crawled,
                'job_state' => is_array($entry) && isset($entry['state']) ? $entry['state'] : 'unknown',
                'job_stage' => is_array($entry) && isset($entry['stage']) ? $entry['stage'] : '',
                'job_attempts' => is_array($entry) && isset($entry['attempts']) ? (int) $entry['attempts'] : 0,
                'job_updated' => is_array($entry) && isset($entry['updated']) ? $entry['updated'] : null
            );
        }

        return array(
            'status' => 'error',
            'message' => Metasync::get_whitelabel_otto_name() . ' job status class not available'
        );
    }
    
    /**
     * Test page type detection
     */
    private function test_page_type_detection($url) {
        $parsed_url = wp_parse_url($url);
        $path = $parsed_url['path'] ?? '/';
        
        $detection = array(
            'url' => $url,
            'path' => $path,
            'is_ajax' => strpos($path, 'wp-admin/admin-ajax.php') !== false,
            'is_woocommerce' => function_exists('is_woocommerce') ? false : 'WooCommerce not available',
            'is_admin' => strpos($path, '/wp-admin/') !== false,
            'is_login' => strpos($path, '/wp-login.php') !== false,
            'is_cron' => strpos($path, '/wp-cron.php') !== false,
            'is_xmlrpc' => strpos($path, '/xmlrpc.php') !== false
        );
        
        // Check if it's a WooCommerce page
        if (function_exists('is_woocommerce')) {
            // This would need to be tested with actual page context
            $detection['is_woocommerce'] = 'Requires page context to determine';
        }
        
        return $detection;
    }
    
    /**
     * Test processing eligibility
     */
    private function test_processing_eligibility($url) {
        $general_options = Metasync::get_option('general');
        // OTTO SSR is always enabled by default
        $otto_enabled = true;
        $disable_logged_in = $general_options['otto_disable_on_loggedin'] ?? false;
        
        $eligibility = array(
            'otto_enabled' => $otto_enabled,
            'disable_logged_in' => $disable_logged_in,
            'user_logged_in' => is_user_logged_in(),
            'eligible_for_processing' => false,
            'exclusion_reasons' => array()
        );
        
        // OTTO SSR is always enabled, so this check is no longer needed
        
        if ($disable_logged_in && is_user_logged_in()) {
            $eligibility['exclusion_reasons'][] = 'User is logged in and ' . Metasync::get_whitelabel_otto_name() . ' disabled for logged-in users';
        }
        
        $eligibility['eligible_for_processing'] = empty($eligibility['exclusion_reasons']);
        
        return $eligibility;
    }
    
    /**
     * Emulate OTTO processing
     */
    private function emulate_otto_processing($url) {
        $emulation = array(
            'url' => $url,
            'steps' => array(),
            'errors' => array(),
            'changes_applied' => array()
        );
        
        // Step 1: Check if URL is crawled
        $emulation['steps']['check_crawled'] = $this->test_crawl_status($url);
        
        // Step 2: Fetch OTTO data
        $emulation['steps']['fetch_otto_data'] = $this->test_otto_api_for_url($url);
        
        // Step 3: Simulate HTML processing
        if (class_exists('Metasync_otto_html')) {
            try {
                $otto_html = new Metasync_otto_html(false);
                $emulation['steps']['html_processing'] = array(
                    'status' => 'success',
                    'message' => Metasync::get_whitelabel_otto_name() . ' HTML class available'
                );

                // Simulate processing (without actually modifying files)
                $emulation['changes_applied'] = array(
                    'header_changes' => 'Simulated header modifications',
                    'body_changes' => 'Simulated body modifications',
                    'footer_changes' => 'Simulated footer modifications'
                );

            } catch (Exception $e) {
                $emulation['errors'][] = 'HTML processing error: ' . $e->getMessage();
            }
        } else {
            $emulation['errors'][] = Metasync::get_whitelabel_otto_name() . ' HTML class not available';
        }
        
        return $emulation;
    }
    
    /**
     * Simple AJAX test to verify basic functionality
     */
    public function ajax_simple_test() {
        try {
            check_ajax_referer('metasync_otto_debug', 'nonce');

            if (!current_user_can('manage_options') || !self::is_debug_tools_enabled()) {
                wp_send_json_error('Unauthorized');
            }

            wp_send_json_success(array(
                'message' => 'AJAX is working!',
                'timestamp' => current_time('mysql'),
                'user_id' => get_current_user_id(),
                'nonce_verified' => true
            ));

        } catch (Exception $e) {
            error_log('MetaSync OTTO Debug: Exception in ajax_simple_test: ' . $e->getMessage()); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- unreachable in production
            wp_send_json_error('Exception: ' . $e->getMessage());
        }
    }
    
    /**
     * AJAX handler for testing database permissions
     */
    public function ajax_test_db_permissions() {
        try {
            check_ajax_referer('metasync_otto_debug', 'nonce');

            if (!current_user_can('manage_options') || !self::is_debug_tools_enabled()) {
                wp_send_json_error('Unauthorized');
            }

            $results = array(
                'timestamp' => current_time('mysql'),
                'tests' => array()
            );
            
            // Test 1: Try to schedule a simple action
            $test_action = 'metasync_debug_test_action';
            $scheduled = wp_schedule_single_event(time() + 60, $test_action, array('test' => 'data'));
            
            $results['tests']['action_scheduler'] = array(
                'can_schedule' => $scheduled !== false,
                'scheduled' => $scheduled,
                'message' => $scheduled !== false ? 'Action Scheduler working' : 'Action Scheduler failed - likely database permissions issue'
            );
            
            // Test 2: Check if we can access Action Scheduler tables
            global $wpdb;
            $table_name = $wpdb->prefix . 'actionscheduler_actions';
            $table_exists = $wpdb->get_var($wpdb->prepare('SHOW TABLES LIKE %s', $wpdb->esc_like($table_name))) == $table_name; // phpcs:ignore WordPress.DB.DirectDatabaseQuery -- admin debug tool — scratch diagnostics storage outside any WordPress API
            
            $results['tests']['table_access'] = array(
                'table_exists' => $table_exists,
                'table_name' => $table_name,
                'message' => $table_exists ? 'Action Scheduler table exists' : 'Action Scheduler table not found'
            );
            
            // Test 3: Try to insert a test record
            if ($table_exists) {
                $insert_result = $wpdb->insert( // phpcs:ignore WordPress.DB.DirectDatabaseQuery -- admin debug tool — scratch diagnostics storage outside any WordPress API
                    $table_name,
                    array(
                        'hook' => 'metasync_debug_test',
                        'status' => 'pending',
                        'scheduled_date_gmt' => current_time('mysql', 1),
                        'args' => json_encode(array('test' => true)),
                        'schedule' => 'once'
                    ),
                    array('%s', '%s', '%s', '%s', '%s')
                );
                
                $results['tests']['insert_test'] = array(
                    'can_insert' => $insert_result !== false,
                    'insert_id' => $wpdb->insert_id,
                    'last_error' => $wpdb->last_error,
                    'message' => $insert_result !== false ? 'Can insert records' : 'Cannot insert records - ' . $wpdb->last_error
                );
                
                // Clean up test record
                if ($insert_result !== false && $wpdb->insert_id) {
                    $wpdb->delete($table_name, array('ID' => $wpdb->insert_id)); // phpcs:ignore WordPress.DB.DirectDatabaseQuery -- admin debug tool — scratch diagnostics storage outside any WordPress API
                }
            }
            
            // Test 4: Check WordPress cron functionality
            $cron_disabled = defined('DISABLE_WP_CRON') && DISABLE_WP_CRON;
            $results['tests']['wp_cron'] = array(
                'enabled' => !$cron_disabled,
                'message' => $cron_disabled ? 'WordPress cron is disabled' : 'WordPress cron is enabled'
            );
            
            wp_send_json_success($results);

        } catch (Exception $e) {
            error_log('MetaSync OTTO Debug: Exception in ajax_test_db_permissions: ' . $e->getMessage()); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- unreachable in production
            wp_send_json_error('Exception: ' . $e->getMessage());
        }
    }
}

```
