PluginProbe
Search Atlas SEO – OTTO AI SEO Automation for WordPress / trunk
Search Atlas SEO – OTTO AI SEO Automation for WordPress vtrunk
2.6.26 2.6.25 2.6.24 2.6.23 2.6.22 2.6.21 2.6.20 2.6.19 2.6.18 2.6.17 2.6.16 2.6.15 2.6.14 2.6.13 2.6.12 2.6.11 2.6.10 2.6.9 2.6.8 2.6.7 2.6.6 2.6.5 2.6.4 2.6.3 2.5.23 All 138 releases
metasync / admin / class-metasync-otto-debug.php

class-metasync-otto-debug.php in Search Atlas SEO – OTTO AI SEO Automation for WordPress trunk, at admin/class-metasync-otto-debug.php

1,312 lines 48.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * OTTO Debug Page for MetaSync Plugin
4 *
5 * This class provides comprehensive diagnostics for OTTO functionality
6 * to help developers troubleshoot why OTTO changes are not being applied.
7 *
8 * @package MetaSync
9 * @subpackage MetaSync/admin
10 * @since 1.0.0
11 */
12
13 // Prevent direct access
14 if (!defined('ABSPATH')) {
15 exit;
16 }
17
18 class Metasync_Otto_Debug {
19
20 /**
21 * The plugin name
22 */
23 private $plugin_name;
24
25 /**
26 * The plugin version
27 */
28 private $version;
29
30 /**
31 * Constructor
32 */
33 public function __construct($plugin_name, $version) {
34 $this->plugin_name = $plugin_name;
35 $this->version = $version;
36
37 // Add admin menu
38 add_action('admin_menu', array($this, 'add_debug_menu'));
39
40 // Add AJAX handlers
41 add_action('wp_ajax_metasync_otto_debug_test_api', array($this, 'ajax_test_otto_api'));
42 add_action('wp_ajax_metasync_otto_debug_test_notification', array($this, 'ajax_test_notification_endpoint'));
43 add_action('wp_ajax_metasync_otto_debug_clear_cache', array($this, 'ajax_clear_otto_cache'));
44 add_action('wp_ajax_metasync_otto_debug_simulate_crawl', array($this, 'ajax_simulate_crawl_notification'));
45 add_action('wp_ajax_metasync_otto_debug_test_url', array($this, 'ajax_test_specific_url'));
46 add_action('wp_ajax_metasync_otto_debug_emulate_changes', array($this, 'ajax_emulate_otto_changes'));
47 add_action('wp_ajax_metasync_otto_debug_simple_test', array($this, 'ajax_simple_test'));
48 add_action('wp_ajax_metasync_otto_debug_test_db_permissions', array($this, 'ajax_test_db_permissions'));
49 }
50
51
52 /**
53 * Whether debug tooling is allowed to run at all right now.
54 *
55 * `manage_options` alone isn't a real restriction — every site admin has
56 * it, so this page and its AJAX handlers were reachable by anyone on any
57 * site. Hard-disabled: the menu item, the page, and every AJAX handler
58 * are unreachable for all users on all sites, no toggle or capability
59 * bypasses this. The class and its methods are left in place; only
60 * access is blocked.
61 */
62 private static function is_debug_tools_enabled() {
63 return false;
64 }
65
66 /**
67 * Add debug menu (internal only - hidden on customer production sites)
68 */
69 public function add_debug_menu() {
70 if (!current_user_can('manage_options') || !self::is_debug_tools_enabled()) {
71 return;
72 }
73
74 $menu_slug = Metasync_Admin::$page_slug;
75
76 add_submenu_page(
77 $menu_slug,
78 Metasync::get_whitelabel_otto_name() . ' Debug',
79 Metasync::get_whitelabel_otto_name() . ' Debug',
80 'manage_options',
81 $menu_slug . '-otto-debug',
82 array($this, 'create_debug_page')
83 );
84 }
85
86 /**
87 * Create the debug page
88 */
89 public function create_debug_page() {
90 if (!current_user_can('manage_options') || !self::is_debug_tools_enabled()) {
91 wp_die('Unauthorized');
92 }
93
94 $whitelabel_otto_name = Metasync::get_whitelabel_otto_name();
95 ?>
96 <div class="wrap metasync-otto-debug">
97 <h1><?php echo esc_html($whitelabel_otto_name); ?> Debug & Diagnostics</h1>
98 <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>
99
100 <div class="metasync-debug-container">
101 <?php $this->render_developer_access_status(); ?>
102 <?php $this->render_url_testing_section(); ?>
103 <?php $this->render_configuration_status(); ?>
104 <?php $this->render_notification_endpoint_status(); ?>
105 <?php $this->render_api_connectivity_status(); ?>
106 <?php $this->render_crawl_data_status(); ?>
107 <?php $this->render_processing_status(); ?>
108 <?php $this->render_debug_tools(); ?>
109 </div>
110 </div>
111
112 <style>
113 .metasync-debug-container {
114 display: grid;
115 grid-template-columns: 1fr 1fr;
116 gap: 20px;
117 margin-top: 20px;
118 }
119
120 .debug-section {
121 background: #fff;
122 border: 1px solid #ccd0d4;
123 border-radius: 4px;
124 padding: 20px;
125 box-shadow: 0 1px 1px rgba(0,0,0,.04);
126 }
127
128 .debug-section h3 {
129 margin-top: 0;
130 color: #23282d;
131 border-bottom: 1px solid #eee;
132 padding-bottom: 10px;
133 }
134
135 .status-indicator {
136 display: inline-block;
137 width: 12px;
138 height: 12px;
139 border-radius: 50%;
140 margin-right: 8px;
141 }
142
143 .status-success { background-color: #46b450; }
144 .status-warning { background-color: #ffb900; }
145 .status-error { background-color: #dc3232; }
146 .status-info { background-color: #00a0d2; }
147
148 .debug-item {
149 margin: 10px 0;
150 padding: 8px;
151 background: #f9f9f9;
152 border-left: 4px solid #ddd;
153 }
154
155 .debug-item.success { border-left-color: #46b450; }
156 .debug-item.warning { border-left-color: #ffb900; }
157 .debug-item.error { border-left-color: #dc3232; }
158 .debug-item.info { border-left-color: #00a0d2; }
159
160 .debug-value {
161 font-family: monospace;
162 background: #fff;
163 padding: 4px 8px;
164 border: 1px solid #ddd;
165 border-radius: 3px;
166 word-break: break-all;
167 }
168
169 .debug-tools {
170 grid-column: 1 / -1;
171 }
172
173 .debug-button {
174 background: #0073aa;
175 color: white;
176 border: none;
177 padding: 8px 16px;
178 border-radius: 3px;
179 cursor: pointer;
180 margin: 5px;
181 }
182
183 .debug-button:hover {
184 background: #005a87;
185 }
186
187 .debug-button.danger {
188 background: #dc3232;
189 }
190
191 .debug-button.danger:hover {
192 background: #a00;
193 }
194
195 .debug-results {
196 margin-top: 15px;
197 padding: 15px;
198 background: #f1f1f1;
199 border-radius: 3px;
200 display: none;
201 }
202
203 .debug-results.show {
204 display: block;
205 }
206
207 .debug-results .error {
208 background: #f8d7da;
209 border: 1px solid #f5c6cb;
210 color: #721c24;
211 padding: 10px;
212 border-radius: 4px;
213 margin: 10px 0;
214 }
215
216 .json-output {
217 background: #fff;
218 border: 1px solid #ddd;
219 padding: 10px;
220 border-radius: 3px;
221 font-family: monospace;
222 white-space: pre-wrap;
223 max-height: 300px;
224 overflow-y: auto;
225 }
226 </style>
227 <?php
228 }
229
230 /**
231 * Render developer access status section
232 */
233 private function render_developer_access_status() {
234 $current_user = wp_get_current_user();
235 ?>
236 <div class="debug-section">
237 <h3><span class="status-indicator status-success"></span>Administrator Access</h3>
238
239 <div class="debug-item success">
240 <strong>Debug Access:</strong>
241 <span class="debug-value">Granted via manage_options</span>
242 </div>
243
244 <div class="debug-item info">
245 <strong>Current User:</strong>
246 <span class="debug-value"><?php echo esc_html($current_user->user_login); ?> (ID: <?php echo $current_user->ID; ?>)</span>
247 </div>
248
249 <div class="debug-item info">
250 <strong>User Roles:</strong>
251 <span class="debug-value"><?php echo implode(', ', $current_user->roles); ?></span>
252 </div>
253
254 <div class="debug-item success">
255 <strong>Debug Access Active</strong>
256 <p>You have access to all <?php echo esc_html(Metasync::get_whitelabel_otto_name()); ?> debug tools and diagnostics.</p>
257 </div>
258 </div>
259 <?php
260 }
261
262 /**
263 * Render URL testing section
264 */
265 private function render_url_testing_section() {
266 $whitelabel_otto_name = Metasync::get_whitelabel_otto_name();
267 $site_url = get_site_url();
268 ?>
269 <div class="debug-section debug-tools">
270 <h3><span class="status-indicator status-info"></span>URL Testing & <?php echo esc_html($whitelabel_otto_name); ?> Emulation</h3>
271
272 <div class="debug-item info">
273 <strong>Test Specific URL:</strong>
274 <p>Enter any URL from your site to test <?php echo esc_html($whitelabel_otto_name); ?> functionality and check all diagnostic points.</p>
275 </div>
276
277 <div style="margin-bottom: 20px;">
278 <label for="test-url-input"><strong>URL to Test:</strong></label><br>
279 <input type="url" id="test-url-input" placeholder="<?php echo esc_attr($site_url); ?>/sample-page/" style="width: 100%; padding: 8px; margin: 5px 0;" />
280 <br>
281 <button id="test-specific-url" class="debug-button">Test URL & Check All Points</button>
282 <button id="emulate-otto-changes" class="debug-button">Emulate <?php echo esc_html($whitelabel_otto_name); ?> Changes</button>
283 <button id="simple-ajax-test" class="debug-button">Test AJAX Connection</button>
284 </div>
285
286 <div id="url-test-results" class="debug-results"></div>
287 <div id="emulation-results" class="debug-results"></div>
288
289 <div class="debug-item info">
290 <strong>What This Tests:</strong>
291 <ul style="margin-left: 20px;">
292 <li>URL accessibility and response</li>
293 <li><?php echo esc_html($whitelabel_otto_name); ?> API data for the specific URL</li>
294 <li>Crawl status and processing eligibility</li>
295 <li>Page type detection and exclusions</li>
296 <li><?php echo esc_html($whitelabel_otto_name); ?> recommendations and changes</li>
297 <li>Error simulation and validation</li>
298 </ul>
299 </div>
300
301 <div class="debug-item warning">
302 <strong>Database Permissions Check:</strong>
303 <p>Testing if Action Scheduler can schedule jobs...</p>
304 <button id="test-db-permissions" class="debug-button">Test Database Permissions</button>
305 <div id="db-permissions-results" class="debug-results"></div>
306 </div>
307 </div>
308 <?php
309 }
310
311 /**
312 * Render configuration status section
313 */
314 private function render_configuration_status() {
315 $whitelabel_otto_name = Metasync::get_whitelabel_otto_name();
316 $general_options = Metasync::get_option('general');
317
318 // OTTO SSR is always enabled by default
319 $otto_enabled = true;
320 $otto_uuid = $general_options['otto_pixel_uuid'] ?? '';
321 $otto_disable_loggedin = $general_options['otto_disable_on_loggedin'] ?? false;
322
323 ?>
324 <div class="debug-section">
325 <h3><span class="status-indicator <?php echo !empty($otto_uuid) ? 'status-success' : 'status-error'; ?>"></span>Configuration Status</h3>
326
327 <div class="debug-item success">
328 <strong><?php echo esc_html($whitelabel_otto_name); ?> SSR Enabled:</strong>
329 <span class="debug-value">Yes (Always Active)</span>
330 </div>
331
332 <div class="debug-item <?php echo !empty($otto_uuid) ? 'success' : 'error'; ?>">
333 <strong><?php echo esc_html($whitelabel_otto_name); ?> UUID:</strong>
334 <span class="debug-value"><?php echo !empty($otto_uuid) ? esc_html($otto_uuid) : 'Not Set'; ?></span>
335 </div>
336
337 <div class="debug-item <?php echo $otto_disable_loggedin ? 'warning' : 'info'; ?>">
338 <strong>Disable for Logged-in Users:</strong>
339 <span class="debug-value"><?php echo $otto_disable_loggedin ? 'Yes' : 'No'; ?></span>
340 </div>
341
342 <div class="debug-item info">
343 <strong>Current User Logged In:</strong>
344 <span class="debug-value"><?php echo is_user_logged_in() ? 'Yes' : 'No'; ?></span>
345 </div>
346
347 <div class="debug-item info">
348 <strong>Plugin Version:</strong>
349 <span class="debug-value"><?php echo defined('METASYNC_VERSION') ? METASYNC_VERSION : 'Unknown'; ?></span>
350 </div>
351 </div>
352 <?php
353 }
354
355 /**
356 * Render notification endpoint status
357 */
358 private function render_notification_endpoint_status() {
359 $rest_url = rest_url('metasync/v1/otto_crawl_notify');
360 $site_url = get_site_url();
361
362 ?>
363 <div class="debug-section">
364 <h3><span class="status-indicator status-info"></span>Notification Endpoint Status</h3>
365
366 <div class="debug-item info">
367 <strong>REST API Base URL:</strong>
368 <span class="debug-value"><?php echo esc_html($site_url); ?></span>
369 </div>
370
371 <div class="debug-item info">
372 <strong><?php echo esc_html(Metasync::get_whitelabel_otto_name()); ?> Notification Endpoint:</strong>
373 <span class="debug-value"><?php echo esc_html($rest_url); ?></span>
374 </div>
375
376 <div class="debug-item <?php echo function_exists('rest_url') ? 'success' : 'error'; ?>">
377 <strong>REST API Available:</strong>
378 <span class="debug-value"><?php echo function_exists('rest_url') ? 'Yes' : 'No'; ?></span>
379 </div>
380
381 <div class="debug-item <?php echo $this->is_rest_endpoint_registered() ? 'success' : 'error'; ?>">
382 <strong>Endpoint Registered:</strong>
383 <span class="debug-value"><?php echo $this->is_rest_endpoint_registered() ? 'Yes' : 'No'; ?></span>
384 </div>
385
386 <div class="debug-item info">
387 <strong>Expected Method:</strong>
388 <span class="debug-value">POST</span>
389 </div>
390
391 <div class="debug-item info">
392 <strong>Expected JSON Fields:</strong>
393 <span class="debug-value">domain, urls</span>
394 </div>
395 </div>
396 <?php
397 }
398
399 /**
400 * Render API connectivity status
401 */
402 private function render_api_connectivity_status() {
403 $general_options = Metasync::get_option('general');
404 $otto_uuid = $general_options['otto_pixel_uuid'] ?? '';
405
406 # Use endpoint manager to get the correct API URL
407 $api_url = class_exists('Metasync_Endpoint_Manager')
408 ? Metasync_Endpoint_Manager::get_endpoint('OTTO_URL_DETAILS')
409 : 'https://sa.searchatlas.com/api/v2/otto-url-details';
410 $test_url = add_query_arg(array(
411 'url' => get_site_url(),
412 'uuid' => $otto_uuid
413 ), $api_url);
414
415 ?>
416 <div class="debug-section">
417 <h3><span class="status-indicator status-info"></span>API Connectivity Status</h3>
418
419 <div class="debug-item info">
420 <strong><?php echo esc_html(Metasync::get_whitelabel_otto_name()); ?> API Endpoint:</strong>
421 <span class="debug-value"><?php echo esc_html($api_url); ?></span>
422 </div>
423
424 <div class="debug-item info">
425 <strong>Test URL:</strong>
426 <span class="debug-value"><?php echo esc_html($test_url); ?></span>
427 </div>
428
429 <div class="debug-item <?php echo $this->can_reach_otto_api() ? 'success' : 'error'; ?>">
430 <strong>API Reachable:</strong>
431 <span class="debug-value"><?php echo $this->can_reach_otto_api() ? 'Yes' : 'No'; ?></span>
432 </div>
433
434 <div class="debug-item info">
435 <strong>SSL Verification:</strong>
436 <span class="debug-value">Enabled</span>
437 </div>
438
439 <div class="debug-item info">
440 <strong>Timeout:</strong>
441 <span class="debug-value">30 seconds</span>
442 </div>
443
444 <div class="debug-item info">
445 <strong>User Agent:</strong>
446 <span class="debug-value">MetaSync-WordPress-Plugin/1.0</span>
447 </div>
448 </div>
449 <?php
450 }
451
452 /**
453 * Render crawl data status
454 */
455 private function render_crawl_data_status() {
456 $crawl_data = get_option('metasync_otto_crawldata');
457
458 ?>
459 <div class="debug-section">
460 <h3><span class="status-indicator <?php echo !empty($crawl_data) ? 'status-success' : 'status-warning'; ?>"></span>Crawl Data Status</h3>
461
462 <div class="debug-item <?php echo !empty($crawl_data) ? 'success' : 'warning'; ?>">
463 <strong>Crawl Data Available:</strong>
464 <span class="debug-value"><?php echo !empty($crawl_data) ? 'Yes' : 'No'; ?></span>
465 </div>
466
467 <?php if (!empty($crawl_data)): ?>
468 <div class="debug-item info">
469 <strong>Domain:</strong>
470 <span class="debug-value"><?php echo esc_html($crawl_data['domain'] ?? 'Not Set'); ?></span>
471 </div>
472
473 <div class="debug-item info">
474 <strong>Total URLs Crawled:</strong>
475 <span class="debug-value"><?php echo count($crawl_data['urls'] ?? []); ?></span>
476 </div>
477
478 <div class="debug-item info">
479 <strong>Last Updated:</strong>
480 <span class="debug-value"><?php echo $this->get_option_last_updated('metasync_otto_crawldata'); ?></span>
481 </div>
482
483 <div class="debug-item info">
484 <strong>Sample URLs:</strong>
485 <div class="debug-value">
486 <?php
487 $sample_urls = array_slice($crawl_data['urls'] ?? [], 0, 5);
488 foreach ($sample_urls as $url) {
489 echo esc_html($url) . '<br>';
490 }
491 if (count($crawl_data['urls'] ?? []) > 5) {
492 echo '... and ' . (count($crawl_data['urls']) - 5) . ' more';
493 }
494 ?>
495 </div>
496 </div>
497 <?php endif; ?>
498 </div>
499 <?php
500 }
501
502 /**
503 * Render processing status
504 */
505 private function render_processing_status() {
506 $current_url = $this->get_current_url();
507 $otto_pixel = new Metasync_otto_pixel(Metasync::get_option('general')['otto_pixel_uuid'] ?? '');
508 $is_crawled = $otto_pixel->is_url_crawled($current_url);
509 $render_diagnostics = $this->get_render_strategy_diagnostics();
510
511 ?>
512 <div class="debug-section">
513 <h3><span class="status-indicator <?php echo $is_crawled ? 'status-success' : 'status-warning'; ?>"></span>Processing Status</h3>
514
515 <div class="debug-item info">
516 <strong>Current URL:</strong>
517 <span class="debug-value"><?php echo esc_html($current_url); ?></span>
518 </div>
519
520 <div class="debug-item <?php echo $is_crawled ? 'success' : 'warning'; ?>">
521 <strong>URL Crawled by <?php echo esc_html(Metasync::get_whitelabel_otto_name()); ?>:</strong>
522 <span class="debug-value"><?php echo $is_crawled ? 'Yes' : 'No'; ?></span>
523 </div>
524
525 <div class="debug-item <?php echo $this->is_otto_excluded() ? 'warning' : 'info'; ?>">
526 <strong><?php echo esc_html(Metasync::get_whitelabel_otto_name()); ?> Excluded:</strong>
527 <span class="debug-value"><?php echo $this->is_otto_excluded() ? 'Yes' : 'No'; ?></span>
528 </div>
529
530 <div class="debug-item info">
531 <strong>Page Type:</strong>
532 <span class="debug-value"><?php echo $this->get_page_type(); ?></span>
533 </div>
534
535 <div class="debug-item info">
536 <strong>Cache Status:</strong>
537 <span class="debug-value"><?php echo $this->get_cache_status(); ?></span>
538 </div>
539
540 <div class="debug-item info">
541 <strong>Processing Method:</strong>
542 <span class="debug-value"><?php echo $this->get_processing_method(); ?></span>
543 </div>
544
545 <?php if (!empty($render_diagnostics) && isset($render_diagnostics['available']) === false): ?>
546 <div class="debug-item info">
547 <strong>Render Strategy:</strong>
548 <div class="debug-value">
549 <ul style="margin: 5px 0 0 15px; padding: 0;">
550 <li><strong>PHP:</strong> <?php echo esc_html($render_diagnostics['php_version'] ?? 'Unknown'); ?></li>
551 <li><strong>WP:</strong> <?php echo esc_html($render_diagnostics['wp_version'] ?? 'Unknown'); ?></li>
552 <li><strong>Memory:</strong> <?php echo esc_html($render_diagnostics['memory_limit'] ?? 'Unknown'); ?> (used: <?php echo esc_html($render_diagnostics['memory_used'] ?? 'Unknown'); ?>)</li>
553 <li><strong>Buffer Level:</strong> <?php echo esc_html($render_diagnostics['buffer_level'] ?? 'Unknown'); ?></li>
554 <li><strong>Headers Sent:</strong> <?php echo ($render_diagnostics['headers_sent'] ?? false) ? 'Yes' : 'No'; ?></li>
555 </ul>
556 </div>
557 </div>
558
559 <div class="debug-item info">
560 <strong>Detected Plugins:</strong>
561 <div class="debug-value">
562 <?php
563 $plugins = $render_diagnostics['detected_plugins'] ?? [];
564 foreach ($plugins as $plugin => $active):
565 ?>
566 <span style="display: inline-block; margin: 2px 5px; padding: 2px 8px; background: <?php echo $active ? '#d4edda' : '#f8f9fa'; ?>; border-radius: 3px;">
567 <?php echo esc_html($plugin); ?>: <?php echo $active ? '' : ''; ?>
568 </span>
569 <?php endforeach; ?>
570 </div>
571 </div>
572
573 <div class="debug-item info">
574 <strong>Detected Hosts:</strong>
575 <div class="debug-value">
576 <?php
577 $hosts = $render_diagnostics['detected_hosts'] ?? [];
578 foreach ($hosts as $host => $detected):
579 ?>
580 <span style="display: inline-block; margin: 2px 5px; padding: 2px 8px; background: <?php echo $detected ? '#fff3cd' : '#f8f9fa'; ?>; border-radius: 3px;">
581 <?php echo esc_html($host); ?>: <?php echo $detected ? '' : ''; ?>
582 </span>
583 <?php endforeach; ?>
584 </div>
585 </div>
586 <?php endif; ?>
587 </div>
588 <?php
589 }
590
591 /**
592 * Render debug tools
593 */
594 private function render_debug_tools() {
595 ?>
596 <div class="debug-section debug-tools">
597 <h3><span class="status-indicator status-info"></span>Debug Tools</h3>
598
599 <div style="margin-bottom: 20px;">
600 <button id="test-otto-api" class="debug-button">Test API Connectivity</button>
601 <button id="test-notification-endpoint" class="debug-button">Test Notification Endpoint</button>
602 <button id="simulate-crawl" class="debug-button">Simulate Crawl Notification</button>
603 <button id="clear-otto-cache" class="debug-button danger">Clear <?php echo esc_html(Metasync::get_whitelabel_otto_name()); ?> Cache</button>
604 </div>
605
606 <div id="api-test-results" class="debug-results"></div>
607 <div id="notification-test-results" class="debug-results"></div>
608 <div id="crawl-simulate-results" class="debug-results"></div>
609 <div id="cache-clear-results" class="debug-results"></div>
610
611 <div class="debug-item info">
612 <strong>Note:</strong> These tools help diagnose <?php echo esc_html(Metasync::get_whitelabel_otto_name()); ?> issues. Use with caution in production environments.
613 </div>
614 </div>
615 <?php
616 }
617
618 /**
619 * Check if REST endpoint is registered
620 */
621 private function is_rest_endpoint_registered() {
622 $routes = rest_get_server()->get_routes();
623 return isset($routes['/metasync/v1/otto_crawl_notify']);
624 }
625
626 /**
627 * Check if OTTO API is reachable
628 */
629 private function can_reach_otto_api() {
630 $general_options = Metasync::get_option('general');
631 $otto_uuid = $general_options['otto_pixel_uuid'] ?? '';
632
633 if (empty($otto_uuid)) {
634 return false;
635 }
636
637 # Use endpoint manager to get the correct API URL
638 $api_endpoint = class_exists('Metasync_Endpoint_Manager')
639 ? Metasync_Endpoint_Manager::get_endpoint('OTTO_URL_DETAILS')
640 : 'https://sa.searchatlas.com/api/v2/otto-url-details';
641
642 $api_url = add_query_arg(array(
643 'url' => get_site_url(),
644 'uuid' => $otto_uuid
645 ), $api_endpoint);
646
647 $response = wp_remote_get($api_url, array(
648 'timeout' => 10,
649 'sslverify' => true
650 ));
651
652 return !is_wp_error($response) && wp_remote_retrieve_response_code($response) === 200;
653 }
654
655 /**
656 * Get option last updated time
657 */
658 private function get_option_last_updated($option_name) {
659 global $wpdb;
660
661 $result = $wpdb->get_var($wpdb->prepare(
662 "SELECT option_value FROM {$wpdb->options} WHERE option_name = %s",
663 $option_name
664 ));
665
666 if ($result) {
667 $data = maybe_unserialize($result);
668 if (isset($data['last_updated'])) {
669 return date('Y-m-d H:i:s', $data['last_updated']);
670 }
671 }
672
673 return 'Unknown';
674 }
675
676 /**
677 * Get current URL
678 */
679 private function get_current_url() {
680 $scheme = is_ssl() ? 'https' : 'http';
681 $host = $_SERVER['HTTP_HOST'] ?? '';
682 $uri = $_SERVER['REQUEST_URI'] ?? '';
683 return $scheme . '://' . $host . $uri;
684 }
685
686 /**
687 * Check if OTTO is excluded for current request
688 */
689 private function is_otto_excluded() {
690 // Check AJAX requests
691 if (wp_doing_ajax() || defined('DOING_AJAX') && DOING_AJAX) {
692 return true;
693 }
694
695 // Check WooCommerce pages
696 if (function_exists('is_woocommerce') && is_woocommerce()) {
697 return true;
698 }
699
700 // Check logged-in user exclusion
701 $general_options = Metasync::get_option('general');
702 if (!empty($general_options['otto_disable_on_loggedin']) &&
703 $general_options['otto_disable_on_loggedin'] === 'true' &&
704 is_user_logged_in()) {
705 return true;
706 }
707
708 return false;
709 }
710
711 /**
712 * Get page type
713 */
714 private function get_page_type() {
715 if (is_home()) return 'Home';
716 if (is_front_page()) return 'Front Page';
717 if (is_single()) return 'Single Post';
718 if (is_page()) return 'Page';
719 if (is_category()) return 'Category';
720 if (is_tag()) return 'Tag';
721 if (is_archive()) return 'Archive';
722 if (is_search()) return 'Search';
723 if (is_404()) return '404';
724 return 'Other';
725 }
726
727 /**
728 * Get cache status
729 */
730 private function get_cache_status() {
731 // Cache is disabled in current implementation
732 return 'Disabled (SSR Mode)';
733 }
734
735 /**
736 * Get processing method
737 */
738 private function get_processing_method() {
739 // OTTO SSR is always enabled by default
740 $otto_enabled = true;
741
742 if ($otto_enabled) {
743 // Check which render strategy would be used
744 if (class_exists('Metasync_Otto_Render_Strategy')) {
745 $method = Metasync_Otto_Render_Strategy::determine_method();
746 if ($method === Metasync_Otto_Render_Strategy::METHOD_BUFFER) {
747 return 'Server-Side Rendering (SSR) - Output Buffer (Fast)';
748 } elseif ($method === Metasync_Otto_Render_Strategy::METHOD_HTTP) {
749 return 'Server-Side Rendering (SSR) - HTTP Request (Fallback)';
750 }
751 }
752 return 'Server-Side Rendering (SSR)';
753 } else {
754 return 'Client-Side JavaScript';
755 }
756 }
757
758 /**
759 * Get render strategy diagnostics
760 */
761 public function get_render_strategy_diagnostics() {
762 if (!class_exists('Metasync_Otto_Render_Strategy')) {
763 return array(
764 'available' => false,
765 'message' => 'Render Strategy class not loaded'
766 );
767 }
768
769 return Metasync_Otto_Render_Strategy::get_diagnostics();
770 }
771
772 /**
773 * AJAX handler for testing OTTO API
774 */
775 public function ajax_test_otto_api() {
776 check_ajax_referer('metasync_otto_debug', 'nonce');
777
778 if (!current_user_can('manage_options') || !self::is_debug_tools_enabled()) {
779 wp_die('Unauthorized');
780 }
781
782 $general_options = Metasync::get_option('general');
783 $otto_uuid = $general_options['otto_pixel_uuid'] ?? '';
784
785 if (empty($otto_uuid)) {
786 wp_send_json_error(Metasync::get_whitelabel_otto_name() . ' UUID not configured');
787 }
788
789 $test_url = get_site_url();
790
791 # Use endpoint manager to get the correct API URL
792 $api_endpoint = class_exists('Metasync_Endpoint_Manager')
793 ? Metasync_Endpoint_Manager::get_endpoint('OTTO_URL_DETAILS')
794 : 'https://sa.searchatlas.com/api/v2/otto-url-details';
795
796 $api_url = add_query_arg(array(
797 'url' => $test_url,
798 'uuid' => $otto_uuid
799 ), $api_endpoint);
800
801 $response = wp_remote_get($api_url, array(
802 'timeout' => 30,
803 'sslverify' => true,
804 'headers' => array(
805 'User-Agent' => 'MetaSync-WordPress-Plugin/1.0'
806 )
807 ));
808
809 if (is_wp_error($response)) {
810 wp_send_json_error(array(
811 'error' => $response->get_error_message(),
812 'url' => $api_url
813 ));
814 }
815
816 $response_code = wp_remote_retrieve_response_code($response);
817 $body = wp_remote_retrieve_body($response);
818
819 wp_send_json_success(array(
820 'response_code' => $response_code,
821 'url' => $api_url,
822 'body' => $body,
823 'has_data' => !empty($body),
824 'data_valid' => json_decode($body, true) !== null
825 ));
826 }
827
828 /**
829 * AJAX handler for testing notification endpoint
830 */
831 public function ajax_test_notification_endpoint() {
832 check_ajax_referer('metasync_otto_debug', 'nonce');
833
834 if (!current_user_can('manage_options') || !self::is_debug_tools_enabled()) {
835 wp_die('Unauthorized');
836 }
837
838 $endpoint_url = rest_url('metasync/v1/otto_crawl_notify');
839
840 $test_data = array(
841 'domain' => get_site_url(),
842 'urls' => array('/', '/about/', '/contact/')
843 );
844
845 $response = wp_remote_post($endpoint_url, array(
846 'headers' => array(
847 'Content-Type' => 'application/json'
848 ),
849 'body' => json_encode($test_data),
850 'timeout' => 30
851 ));
852
853 if (is_wp_error($response)) {
854 wp_send_json_error(array(
855 'error' => $response->get_error_message(),
856 'url' => $endpoint_url
857 ));
858 }
859
860 $response_code = wp_remote_retrieve_response_code($response);
861 $body = wp_remote_retrieve_body($response);
862
863 wp_send_json_success(array(
864 'response_code' => $response_code,
865 'url' => $endpoint_url,
866 'body' => $body,
867 'test_data' => $test_data
868 ));
869 }
870
871 /**
872 * AJAX handler for clearing OTTO cache
873 */
874 public function ajax_clear_otto_cache() {
875 check_ajax_referer('metasync_otto_debug', 'nonce');
876
877 if (!current_user_can('manage_options') || !self::is_debug_tools_enabled()) {
878 wp_die('Unauthorized');
879 }
880
881 // Clear crawl data
882 delete_option('metasync_otto_crawldata');
883
884 // Clear any cached API responses
885 $general_options = Metasync::get_option('general');
886 $otto_uuid = $general_options['otto_pixel_uuid'] ?? '';
887
888 if (!empty($otto_uuid)) {
889 delete_transient(Metasync_Heartbeat_Manager::public_hash_cache_key($otto_uuid));
890 }
891
892 delete_transient('metasync_otto_js_detected');
893
894 wp_send_json_success(array(
895 'message' => Metasync::get_whitelabel_otto_name() . ' cache cleared successfully',
896 'cleared_items' => array(
897 'crawl_data' => true,
898 'api_cache' => true
899 )
900 ));
901 }
902
903 /**
904 * AJAX handler for simulating crawl notification
905 */
906 public function ajax_simulate_crawl_notification() {
907 check_ajax_referer('metasync_otto_debug', 'nonce');
908
909 if (!current_user_can('manage_options') || !self::is_debug_tools_enabled()) {
910 wp_die('Unauthorized');
911 }
912
913 $general_options = Metasync::get_option('general');
914 $otto_uuid = $general_options['otto_pixel_uuid'] ?? '';
915
916 if (empty($otto_uuid)) {
917 wp_send_json_error(Metasync::get_whitelabel_otto_name() . ' UUID not configured');
918 }
919
920 // Simulate crawl notification
921 $test_data = array(
922 'domain' => get_site_url(),
923 'urls' => array('/', '/about/', '/contact/', '/blog/')
924 );
925
926 // Create a mock request object
927 $request = new WP_REST_Request('POST', '/metasync/v1/otto_crawl_notify');
928 $request->set_body(json_encode($test_data));
929
930 // Call the notification handler
931 $response = metasync_otto_crawl_notify($request);
932
933 wp_send_json_success(array(
934 'message' => 'Crawl notification simulated',
935 'test_data' => $test_data,
936 'response' => $response->get_data(),
937 'response_code' => $response->get_status()
938 ));
939 }
940
941 /**
942 * AJAX handler for testing specific URL
943 */
944 public function ajax_test_specific_url() {
945 try {
946 check_ajax_referer('metasync_otto_debug', 'nonce');
947
948 if (!current_user_can('manage_options') || !self::is_debug_tools_enabled()) {
949 wp_die('Unauthorized');
950 }
951
952 $test_url = sanitize_url($_POST['test_url'] ?? '');
953
954 if (empty($test_url)) {
955 wp_send_json_error('No URL provided');
956 }
957
958 $results = array(
959 'test_url' => $test_url,
960 'timestamp' => current_time('mysql'),
961 'tests' => array()
962 );
963
964 // Test 1: URL Accessibility
965 $results['tests']['url_accessibility'] = $this->test_url_accessibility($test_url);
966
967 // Test 2: OTTO API Data
968 $results['tests']['otto_api_data'] = $this->test_otto_api_for_url($test_url);
969
970 // Test 3: Crawl Status
971 $results['tests']['crawl_status'] = $this->test_crawl_status($test_url);
972
973 // Test 4: Page Type Detection
974 $results['tests']['page_type_detection'] = $this->test_page_type_detection($test_url);
975
976 // Test 5: Processing Eligibility
977 $results['tests']['processing_eligibility'] = $this->test_processing_eligibility($test_url);
978
979 wp_send_json_success($results);
980
981 } catch (Exception $e) {
982 error_log('MetaSync OTTO Debug: Exception in ajax_test_specific_url: ' . $e->getMessage());
983 wp_send_json_error('Exception: ' . $e->getMessage());
984 }
985 }
986
987 /**
988 * AJAX handler for emulating OTTO changes
989 */
990 public function ajax_emulate_otto_changes() {
991 check_ajax_referer('metasync_otto_debug', 'nonce');
992
993 if (!current_user_can('manage_options') || !self::is_debug_tools_enabled()) {
994 wp_die('Unauthorized');
995 }
996
997 $test_url = sanitize_url($_POST['test_url'] ?? '');
998
999 if (empty($test_url)) {
1000 wp_send_json_error('No URL provided');
1001 }
1002
1003 $results = array(
1004 'test_url' => $test_url,
1005 'timestamp' => current_time('mysql'),
1006 'emulation' => array()
1007 );
1008
1009 // Emulate OTTO processing
1010 $results['emulation'] = $this->emulate_otto_processing($test_url);
1011
1012 wp_send_json_success($results);
1013 }
1014
1015 /**
1016 * Test URL accessibility
1017 */
1018 private function test_url_accessibility($url) {
1019 $response = wp_remote_get($url, array(
1020 'timeout' => 10,
1021 'user-agent' => 'MetaSync Debug Tool'
1022 ));
1023
1024 if (is_wp_error($response)) {
1025 return array(
1026 'status' => 'error',
1027 'message' => $response->get_error_message(),
1028 'accessible' => false
1029 );
1030 }
1031
1032 $status_code = wp_remote_retrieve_response_code($response);
1033 $body = wp_remote_retrieve_body($response);
1034
1035 return array(
1036 'status' => 'success',
1037 'status_code' => $status_code,
1038 'accessible' => $status_code === 200,
1039 'content_length' => strlen($body),
1040 'headers' => wp_remote_retrieve_headers($response)->getAll()
1041 );
1042 }
1043
1044 /**
1045 * Test OTTO API data for specific URL
1046 */
1047 private function test_otto_api_for_url($url) {
1048 $general_options = Metasync::get_option('general');
1049 $otto_uuid = $general_options['otto_pixel_uuid'] ?? '';
1050
1051 if (empty($otto_uuid)) {
1052 return array(
1053 'status' => 'error',
1054 'message' => Metasync::get_whitelabel_otto_name() . ' UUID not configured'
1055 );
1056 }
1057
1058 // Use the existing OTTO API function
1059 if (function_exists('metasync_fetch_otto_seo_data')) {
1060 $data = metasync_fetch_otto_seo_data($url, $otto_uuid);
1061
1062 if (is_wp_error($data)) {
1063 return array(
1064 'status' => 'error',
1065 'message' => $data->get_error_message(),
1066 'has_data' => false
1067 );
1068 }
1069
1070 return array(
1071 'status' => 'success',
1072 'has_data' => !empty($data),
1073 'data_keys' => array_keys($data ?? array()),
1074 'recommendations_count' => count($data['recommendations'] ?? array()),
1075 'sample_data' => array_slice($data ?? array(), 0, 3) // First 3 items for preview
1076 );
1077 }
1078
1079 return array(
1080 'status' => 'error',
1081 'message' => Metasync::get_whitelabel_otto_name() . ' API function not available'
1082 );
1083 }
1084
1085 /**
1086 * Test crawl status for URL
1087 */
1088 private function test_crawl_status($url) {
1089 if (class_exists('Metasync_otto_pixel')) {
1090 $otto_pixel = new Metasync_otto_pixel(false);
1091 $is_crawled = $otto_pixel->is_url_crawled($url);
1092
1093 // Get crawl data from options
1094 $crawl_data = get_option('metasync_otto_crawldata');
1095
1096 return array(
1097 'status' => 'success',
1098 'is_crawled' => $is_crawled,
1099 'crawl_data' => $crawl_data,
1100 'total_crawled_urls' => count($crawl_data['urls'] ?? array()),
1101 'domain' => $crawl_data['domain'] ?? 'Not set'
1102 );
1103 }
1104
1105 return array(
1106 'status' => 'error',
1107 'message' => Metasync::get_whitelabel_otto_name() . ' pixel class not available'
1108 );
1109 }
1110
1111 /**
1112 * Test page type detection
1113 */
1114 private function test_page_type_detection($url) {
1115 $parsed_url = parse_url($url);
1116 $path = $parsed_url['path'] ?? '/';
1117
1118 $detection = array(
1119 'url' => $url,
1120 'path' => $path,
1121 'is_ajax' => strpos($path, 'wp-admin/admin-ajax.php') !== false,
1122 'is_woocommerce' => function_exists('is_woocommerce') ? false : 'WooCommerce not available',
1123 'is_admin' => strpos($path, '/wp-admin/') !== false,
1124 'is_login' => strpos($path, '/wp-login.php') !== false,
1125 'is_cron' => strpos($path, '/wp-cron.php') !== false,
1126 'is_xmlrpc' => strpos($path, '/xmlrpc.php') !== false
1127 );
1128
1129 // Check if it's a WooCommerce page
1130 if (function_exists('is_woocommerce')) {
1131 // This would need to be tested with actual page context
1132 $detection['is_woocommerce'] = 'Requires page context to determine';
1133 }
1134
1135 return $detection;
1136 }
1137
1138 /**
1139 * Test processing eligibility
1140 */
1141 private function test_processing_eligibility($url) {
1142 $general_options = Metasync::get_option('general');
1143 // OTTO SSR is always enabled by default
1144 $otto_enabled = true;
1145 $disable_logged_in = $general_options['otto_disable_on_loggedin'] ?? false;
1146
1147 $eligibility = array(
1148 'otto_enabled' => $otto_enabled,
1149 'disable_logged_in' => $disable_logged_in,
1150 'user_logged_in' => is_user_logged_in(),
1151 'eligible_for_processing' => false,
1152 'exclusion_reasons' => array()
1153 );
1154
1155 // OTTO SSR is always enabled, so this check is no longer needed
1156
1157 if ($disable_logged_in && is_user_logged_in()) {
1158 $eligibility['exclusion_reasons'][] = 'User is logged in and ' . Metasync::get_whitelabel_otto_name() . ' disabled for logged-in users';
1159 }
1160
1161 $eligibility['eligible_for_processing'] = empty($eligibility['exclusion_reasons']);
1162
1163 return $eligibility;
1164 }
1165
1166 /**
1167 * Emulate OTTO processing
1168 */
1169 private function emulate_otto_processing($url) {
1170 $emulation = array(
1171 'url' => $url,
1172 'steps' => array(),
1173 'errors' => array(),
1174 'changes_applied' => array()
1175 );
1176
1177 // Step 1: Check if URL is crawled
1178 $emulation['steps']['check_crawled'] = $this->test_crawl_status($url);
1179
1180 // Step 2: Fetch OTTO data
1181 $emulation['steps']['fetch_otto_data'] = $this->test_otto_api_for_url($url);
1182
1183 // Step 3: Simulate HTML processing
1184 if (class_exists('Metasync_otto_html')) {
1185 try {
1186 $otto_html = new Metasync_otto_html(false);
1187 $emulation['steps']['html_processing'] = array(
1188 'status' => 'success',
1189 'message' => Metasync::get_whitelabel_otto_name() . ' HTML class available'
1190 );
1191
1192 // Simulate processing (without actually modifying files)
1193 $emulation['changes_applied'] = array(
1194 'header_changes' => 'Simulated header modifications',
1195 'body_changes' => 'Simulated body modifications',
1196 'footer_changes' => 'Simulated footer modifications'
1197 );
1198
1199 } catch (Exception $e) {
1200 $emulation['errors'][] = 'HTML processing error: ' . $e->getMessage();
1201 }
1202 } else {
1203 $emulation['errors'][] = Metasync::get_whitelabel_otto_name() . ' HTML class not available';
1204 }
1205
1206 return $emulation;
1207 }
1208
1209 /**
1210 * Simple AJAX test to verify basic functionality
1211 */
1212 public function ajax_simple_test() {
1213 try {
1214 check_ajax_referer('metasync_otto_debug', 'nonce');
1215
1216 if (!current_user_can('manage_options') || !self::is_debug_tools_enabled()) {
1217 wp_send_json_error('Unauthorized');
1218 }
1219
1220 wp_send_json_success(array(
1221 'message' => 'AJAX is working!',
1222 'timestamp' => current_time('mysql'),
1223 'user_id' => get_current_user_id(),
1224 'nonce_verified' => true
1225 ));
1226
1227 } catch (Exception $e) {
1228 error_log('MetaSync OTTO Debug: Exception in ajax_simple_test: ' . $e->getMessage());
1229 wp_send_json_error('Exception: ' . $e->getMessage());
1230 }
1231 }
1232
1233 /**
1234 * AJAX handler for testing database permissions
1235 */
1236 public function ajax_test_db_permissions() {
1237 try {
1238 check_ajax_referer('metasync_otto_debug', 'nonce');
1239
1240 if (!current_user_can('manage_options') || !self::is_debug_tools_enabled()) {
1241 wp_send_json_error('Unauthorized');
1242 }
1243
1244 $results = array(
1245 'timestamp' => current_time('mysql'),
1246 'tests' => array()
1247 );
1248
1249 // Test 1: Try to schedule a simple action
1250 $test_action = 'metasync_debug_test_action';
1251 $scheduled = wp_schedule_single_event(time() + 60, $test_action, array('test' => 'data'));
1252
1253 $results['tests']['action_scheduler'] = array(
1254 'can_schedule' => $scheduled !== false,
1255 'scheduled' => $scheduled,
1256 'message' => $scheduled !== false ? 'Action Scheduler working' : 'Action Scheduler failed - likely database permissions issue'
1257 );
1258
1259 // Test 2: Check if we can access Action Scheduler tables
1260 global $wpdb;
1261 $table_name = $wpdb->prefix . 'actionscheduler_actions';
1262 $table_exists = $wpdb->get_var("SHOW TABLES LIKE '$table_name'") == $table_name;
1263
1264 $results['tests']['table_access'] = array(
1265 'table_exists' => $table_exists,
1266 'table_name' => $table_name,
1267 'message' => $table_exists ? 'Action Scheduler table exists' : 'Action Scheduler table not found'
1268 );
1269
1270 // Test 3: Try to insert a test record
1271 if ($table_exists) {
1272 $insert_result = $wpdb->insert(
1273 $table_name,
1274 array(
1275 'hook' => 'metasync_debug_test',
1276 'status' => 'pending',
1277 'scheduled_date_gmt' => current_time('mysql', 1),
1278 'args' => json_encode(array('test' => true)),
1279 'schedule' => 'once'
1280 ),
1281 array('%s', '%s', '%s', '%s', '%s')
1282 );
1283
1284 $results['tests']['insert_test'] = array(
1285 'can_insert' => $insert_result !== false,
1286 'insert_id' => $wpdb->insert_id,
1287 'last_error' => $wpdb->last_error,
1288 'message' => $insert_result !== false ? 'Can insert records' : 'Cannot insert records - ' . $wpdb->last_error
1289 );
1290
1291 // Clean up test record
1292 if ($insert_result !== false && $wpdb->insert_id) {
1293 $wpdb->delete($table_name, array('ID' => $wpdb->insert_id));
1294 }
1295 }
1296
1297 // Test 4: Check WordPress cron functionality
1298 $cron_disabled = defined('DISABLE_WP_CRON') && DISABLE_WP_CRON;
1299 $results['tests']['wp_cron'] = array(
1300 'enabled' => !$cron_disabled,
1301 'message' => $cron_disabled ? 'WordPress cron is disabled' : 'WordPress cron is enabled'
1302 );
1303
1304 wp_send_json_success($results);
1305
1306 } catch (Exception $e) {
1307 error_log('MetaSync OTTO Debug: Exception in ajax_test_db_permissions: ' . $e->getMessage());
1308 wp_send_json_error('Exception: ' . $e->getMessage());
1309 }
1310 }
1311 }
1312