| @@ -36,11 +36,8 @@ | ||
| 36 | 36 | |
| 37 | 37 | // Add admin menu |
| 38 | 38 | add_action('admin_menu', array($this, 'add_debug_menu')); |
| 39 | 39 | |
| 40 | - // Add magic word handler | |
| 41 | - add_action('admin_init', array($this, 'handle_magic_word_access')); | |
| 42 | - | |
| 43 | 40 | // Add AJAX handlers |
| 44 | 41 | add_action('wp_ajax_metasync_otto_debug_test_api', array($this, 'ajax_test_otto_api')); |
| 45 | 42 | add_action('wp_ajax_metasync_otto_debug_test_notification', array($this, 'ajax_test_notification_endpoint')); |
| 46 | 43 | add_action('wp_ajax_metasync_otto_debug_clear_cache', array($this, 'ajax_clear_otto_cache')); |
| @@ -52,21 +49,46 @@ | ||
| 52 | 49 | } |
| 53 | 50 | |
| 54 | 51 | |
| 55 | 52 | /** |
| 56 | - * Add debug menu (developer only - hidden by default) | |
| 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. | |
| 57 | 61 | */ |
| 62 | + private static function is_debug_tools_enabled() { | |
| 63 | + return false; | |
| 64 | + } | |
| 65 | + | |
| 66 | + /** | |
| 67 | + * Whether a URL's crawl pipeline has completed, per the bounded | |
| 68 | + * Metasync_Otto_Job_Status store. Replaces the legacy unbounded | |
| 69 | + * metasync_otto_crawldata option lookup: state history is pruned | |
| 70 | + * 48 hours after completion, so a URL finished longer ago reads as | |
| 71 | + * "not crawled" here without implying Otto never touched it. | |
| 72 | + */ | |
| 73 | + private static function is_url_crawled($url) { | |
| 74 | + if (!class_exists('Metasync_Otto_Job_Status')) { | |
| 75 | + return false; | |
| 76 | + } | |
| 77 | + $entry = Metasync_Otto_Job_Status::get($url); | |
| 78 | + return is_array($entry) | |
| 79 | + && isset($entry['state']) | |
| 80 | + && $entry['state'] === Metasync_Otto_Job_Status::STATE_COMPLETED; | |
| 81 | + } | |
| 82 | + | |
| 83 | + /** | |
| 84 | + * Add debug menu (internal only - hidden on customer production sites) | |
| 85 | + */ | |
| 58 | 86 | public function add_debug_menu() { |
| 59 | - // Check if user has developer capabilities | |
| 60 | - if (!Metasync::current_user_has_plugin_access()) { | |
| 87 | + if (!current_user_can('manage_options') || !self::is_debug_tools_enabled()) { | |
| 61 | 88 | return; |
| 62 | 89 | } |
| 63 | 90 | |
| 64 | - // Check if debug access is enabled via magic word | |
| 65 | - if (!$this->is_debug_access_enabled()) { | |
| 66 | - return; | |
| 67 | - } | |
| 68 | - | |
| 69 | 91 | $menu_slug = Metasync_Admin::$page_slug; |
| 70 | 92 | |
| 71 | 93 | add_submenu_page( |
| 72 | 94 | $menu_slug, |
| @@ -78,169 +100,13 @@ | ||
| 78 | 100 | ); |
| 79 | 101 | } |
| 80 | 102 | |
| 81 | 103 | /** |
| 82 | - * Add magic word handler for direct access | |
| 83 | - */ | |
| 84 | - public function handle_magic_word_access() { | |
| 85 | - // Check if magic word is provided | |
| 86 | - if (isset($_GET['metasync_debug']) && $_GET['metasync_debug'] === 'abracadabra@2020') { | |
| 87 | - // Enable debug access via user meta (persistent, no sessions needed) | |
| 88 | - $current_user = wp_get_current_user(); | |
| 89 | - if ($current_user && $current_user->ID) { | |
| 90 | - update_user_meta($current_user->ID, 'metasync_debug_enabled', 'true'); | |
| 91 | - } | |
| 92 | - | |
| 93 | - // Redirect to admin with debug access enabled | |
| 94 | - $redirect_url = admin_url('admin.php?page=' . Metasync_Admin::$page_slug . '-otto-debug'); | |
| 95 | - wp_redirect($redirect_url); | |
| 96 | - exit; | |
| 97 | - } | |
| 98 | - } | |
| 99 | - | |
| 100 | - /** | |
| 101 | - * Check if debug access is enabled via magic word system | |
| 102 | - * Hidden from regular users, only accessible with secret key | |
| 103 | - */ | |
| 104 | - private function is_debug_access_enabled() { | |
| 105 | - // Magic word for developer access | |
| 106 | - $magic_word = 'abracadabra@2020'; | |
| 107 | - | |
| 108 | - // Check if magic word is provided in URL parameter | |
| 109 | - if (isset($_GET['metasync_debug']) && $_GET['metasync_debug'] === $magic_word) { | |
| 110 | - // Enable debug access via user meta (persistent, no sessions needed) | |
| 111 | - $current_user = wp_get_current_user(); | |
| 112 | - if ($current_user && $current_user->ID) { | |
| 113 | - update_user_meta($current_user->ID, 'metasync_debug_enabled', 'true'); | |
| 114 | - } | |
| 115 | - return true; | |
| 116 | - } | |
| 117 | - | |
| 118 | - // Check if debug access is enabled via user meta (for persistent access) | |
| 119 | - $current_user = wp_get_current_user(); | |
| 120 | - if ($current_user && $current_user->ID) { | |
| 121 | - $debug_enabled = get_user_meta($current_user->ID, 'metasync_debug_enabled', true); | |
| 122 | - if ($debug_enabled === 'true') { | |
| 123 | - return true; | |
| 124 | - } | |
| 125 | - } | |
| 126 | - | |
| 127 | - return false; | |
| 128 | - } | |
| 129 | - | |
| 130 | - /** | |
| 131 | - * Check if current user is a developer | |
| 132 | - * Multiple methods to identify developers without requiring WP_DEBUG | |
| 133 | - */ | |
| 134 | - private function is_developer_user($user) { | |
| 135 | - // Method 1: Check for specific user meta | |
| 136 | - $is_developer = get_user_meta($user->ID, 'metasync_developer', true); | |
| 137 | - if ($is_developer === 'true') { | |
| 138 | - return true; | |
| 139 | - } | |
| 140 | - | |
| 141 | - // Method 2: Check for specific user roles | |
| 142 | - $developer_roles = array('administrator', 'developer', 'super_admin'); | |
| 143 | - $user_roles = $user->roles; | |
| 144 | - | |
| 145 | - foreach ($developer_roles as $role) { | |
| 146 | - if (in_array($role, $user_roles)) { | |
| 147 | - return true; | |
| 148 | - } | |
| 149 | - } | |
| 150 | - | |
| 151 | - // Method 3: Check for specific capabilities | |
| 152 | - if ($user->has_cap('manage_options') && $user->has_cap('edit_plugins')) { | |
| 153 | - return true; | |
| 154 | - } | |
| 155 | - | |
| 156 | - // Method 4: Check for specific email domains (optional) | |
| 157 | - $email_domain = substr(strrchr($user->user_email, "@"), 1); | |
| 158 | - $developer_domains = array('searchatlas.com', 'yourcompany.com'); // Add your company domains | |
| 159 | - | |
| 160 | - if (in_array($email_domain, $developer_domains)) { | |
| 161 | - return true; | |
| 162 | - } | |
| 163 | - | |
| 164 | - // Method 5: Check for specific username patterns | |
| 165 | - $username_patterns = array('/^dev_/', '/^admin_/', '/^support_/'); | |
| 166 | - foreach ($username_patterns as $pattern) { | |
| 167 | - if (preg_match($pattern, $user->user_login)) { | |
| 168 | - return true; | |
| 169 | - } | |
| 170 | - } | |
| 171 | - | |
| 172 | - return false; | |
| 173 | - } | |
| 174 | - | |
| 175 | - /** | |
| 176 | - * Helper function to enable developer access for a specific user | |
| 177 | - * Call this function to grant debug access to a user | |
| 178 | - * | |
| 179 | - * Usage: Metasync_Otto_Debug::enable_developer_access($user_id); | |
| 180 | - */ | |
| 181 | - public static function enable_developer_access($user_id) { | |
| 182 | - update_user_meta($user_id, 'metasync_debug_enabled', 'true'); | |
| 183 | - } | |
| 184 | - | |
| 185 | - /** | |
| 186 | - * Helper function to disable developer access for a specific user | |
| 187 | - * | |
| 188 | - * Usage: Metasync_Otto_Debug::disable_developer_access($user_id); | |
| 189 | - */ | |
| 190 | - public static function disable_developer_access($user_id) { | |
| 191 | - delete_user_meta($user_id, 'metasync_debug_enabled'); | |
| 192 | - } | |
| 193 | - | |
| 194 | - /** | |
| 195 | - * Get the magic word for debug access | |
| 196 | - * | |
| 197 | - * Usage: Metasync_Otto_Debug::get_magic_word(); | |
| 198 | - */ | |
| 199 | - public static function get_magic_word() { | |
| 200 | - return 'abracadabra@2020'; | |
| 201 | - } | |
| 202 | - | |
| 203 | - /** | |
| 204 | - * Generate debug access URL | |
| 205 | - * | |
| 206 | - * Usage: Metasync_Otto_Debug::get_debug_access_url(); | |
| 207 | - */ | |
| 208 | - public static function get_debug_access_url() { | |
| 209 | - $admin_url = admin_url('admin.php'); | |
| 210 | - $magic_word = self::get_magic_word(); | |
| 211 | - return add_query_arg('metasync_debug', $magic_word, $admin_url); | |
| 212 | - } | |
| 213 | - | |
| 214 | - /** | |
| 215 | - * Quick enable debug access for current user | |
| 216 | - * | |
| 217 | - * Usage: Metasync_Otto_Debug::quick_enable_debug(); | |
| 218 | - */ | |
| 219 | - public static function quick_enable_debug() { | |
| 220 | - $current_user = wp_get_current_user(); | |
| 221 | - if ($current_user && $current_user->ID) { | |
| 222 | - update_user_meta($current_user->ID, 'metasync_debug_enabled', 'true'); | |
| 223 | - return true; | |
| 224 | - } | |
| 225 | - return false; | |
| 226 | - } | |
| 227 | - | |
| 228 | - /** | |
| 229 | 104 | * Create the debug page |
| 230 | 105 | */ |
| 231 | 106 | public function create_debug_page() { |
| 232 | - // Check if this is a magic word access request | |
| 233 | - if (isset($_GET['metasync_debug']) && $_GET['metasync_debug'] === 'abracadabra@2020') { | |
| 234 | - // Enable debug access via user meta (persistent, no sessions needed) | |
| 235 | - $current_user = wp_get_current_user(); | |
| 236 | - if ($current_user && $current_user->ID) { | |
| 237 | - update_user_meta($current_user->ID, 'metasync_debug_enabled', 'true'); | |
| 238 | - } | |
| 239 | - | |
| 240 | - // Show access granted message | |
| 241 | - $this->show_access_granted_page(); | |
| 242 | - return; | |
| 107 | + if (!current_user_can('manage_options') || !self::is_debug_tools_enabled()) { | |
| 108 | + wp_die('Unauthorized'); | |
| 243 | 109 | } |
| 244 | 110 | |
| 245 | 111 | $whitelabel_otto_name = Metasync::get_whitelabel_otto_name(); |
| 246 | 112 | ?> |
| @@ -253,9 +119,8 @@ | ||
| 253 | 119 | <?php $this->render_url_testing_section(); ?> |
| 254 | 120 | <?php $this->render_configuration_status(); ?> |
| 255 | 121 | <?php $this->render_notification_endpoint_status(); ?> |
| 256 | 122 | <?php $this->render_api_connectivity_status(); ?> |
| 257 | - <?php $this->render_crawl_data_status(); ?> | |
| 258 | 123 | <?php $this->render_processing_status(); ?> |
| 259 | 124 | <?php $this->render_debug_tools(); ?> |
| 260 | 125 | </div> |
| 261 | 126 | </div> |
| @@ -378,161 +243,35 @@ | ||
| 378 | 243 | <?php |
| 379 | 244 | } |
| 380 | 245 | |
| 381 | 246 | /** |
| 382 | - * Show access granted page | |
| 383 | - */ | |
| 384 | - private function show_access_granted_page() { | |
| 385 | - $whitelabel_otto_name = Metasync::get_whitelabel_otto_name(); | |
| 386 | - $current_user = wp_get_current_user(); | |
| 387 | - ?> | |
| 388 | - <div class="wrap"> | |
| 389 | - <h1><?php echo esc_html($whitelabel_otto_name); ?> Debug Access Granted</h1> | |
| 390 | - | |
| 391 | - <div class="notice notice-success"> | |
| 392 | - <p><strong>Debug Access Enabled!</strong></p> | |
| 393 | - <p>You now have access to the <?php echo esc_html($whitelabel_otto_name); ?> Debug page.</p> | |
| 394 | - </div> | |
| 395 | - | |
| 396 | - <div class="card"> | |
| 397 | - <h2>Next Steps</h2> | |
| 398 | - <ol> | |
| 399 | - <li><strong>Access Debug Page:</strong> The "<?php echo esc_html($whitelabel_otto_name); ?> Debug" menu should now be visible in the <?php echo esc_html(Metasync::get_effective_plugin_name()); ?> plugin menu</li> | |
| 400 | - <li><strong>Use Diagnostics:</strong> Click on "<?php echo esc_html($whitelabel_otto_name); ?> Debug" to access comprehensive diagnostic tools</li> | |
| 401 | - <li><strong>Troubleshoot Issues:</strong> Use the debug tools to identify why <?php echo esc_html($whitelabel_otto_name); ?> changes may not be applied</li> | |
| 402 | - </ol> | |
| 403 | - </div> | |
| 404 | - | |
| 405 | - <div class="card"> | |
| 406 | - <h2>Access Information</h2> | |
| 407 | - <table class="form-table"> | |
| 408 | - <tr> | |
| 409 | - <th scope="row">Magic Word</th> | |
| 410 | - <td><code>abracadabra@2020</code></td> | |
| 411 | - </tr> | |
| 412 | - <tr> | |
| 413 | - <th scope="row">Current User</th> | |
| 414 | - <td><?php echo esc_html($current_user->user_login); ?> (ID: <?php echo $current_user->ID; ?>)</td> | |
| 415 | - </tr> | |
| 416 | - <tr> | |
| 417 | - <th scope="row">Access Type</th> | |
| 418 | - <td>User Meta (persistent)</td> | |
| 419 | - </tr> | |
| 420 | - <tr> | |
| 421 | - <th scope="row">Debug Page URL</th> | |
| 422 | - <td><code><?php echo esc_html(admin_url('admin.php?page=' . Metasync_Admin::$page_slug . '-otto-debug')); ?></code></td> | |
| 423 | - </tr> | |
| 424 | - </table> | |
| 425 | - </div> | |
| 426 | - | |
| 427 | - <div class="card"> | |
| 428 | - <h2>Security Notes</h2> | |
| 429 | - <ul> | |
| 430 | - <li><strong>Persistent Access:</strong> This access is stored in your user profile and persists across sessions</li> | |
| 431 | - <li><strong>Magic Word:</strong> Keep the magic word <code>abracadabra@2020</code> confidential</li> | |
| 432 | - <li><strong>Developer Only:</strong> This debug page is intended for plugin developers only</li> | |
| 433 | - <li><strong>To Revoke Access:</strong> Use <code>Metasync_Otto_Debug::disable_developer_access(<?php echo $current_user->ID; ?>)</code></li> | |
| 434 | - </ul> | |
| 435 | - </div> | |
| 436 | - | |
| 437 | - <div class="card"> | |
| 438 | - <h2>Quick Access</h2> | |
| 439 | - <p>To access the debug page directly, use this URL:</p> | |
| 440 | - <p><a href="<?php echo esc_url(admin_url('admin.php?page=' . Metasync_Admin::$page_slug . '-otto-debug')); ?>" class="button button-primary">Open <?php echo esc_html($whitelabel_otto_name); ?> Debug Page</a></p> | |
| 441 | - | |
| 442 | - <p>Or add the magic word to any WordPress admin URL:</p> | |
| 443 | - <p><code>?metasync_debug=abracadabra@2020</code></p> | |
| 444 | - </div> | |
| 445 | - | |
| 446 | - <style> | |
| 447 | - .card { | |
| 448 | - background: #fff; | |
| 449 | - border: 1px solid #ccd0d4; | |
| 450 | - border-radius: 4px; | |
| 451 | - padding: 20px; | |
| 452 | - margin: 20px 0; | |
| 453 | - box-shadow: 0 1px 1px rgba(0,0,0,.04); | |
| 454 | - } | |
| 455 | - .card h2 { | |
| 456 | - margin-top: 0; | |
| 457 | - color: #23282d; | |
| 458 | - border-bottom: 1px solid #eee; | |
| 459 | - padding-bottom: 10px; | |
| 460 | - } | |
| 461 | - .form-table th { | |
| 462 | - width: 200px; | |
| 463 | - } | |
| 464 | - </style> | |
| 465 | - </div> | |
| 466 | - <?php | |
| 467 | - } | |
| 468 | - | |
| 469 | - /** | |
| 470 | 247 | * Render developer access status section |
| 471 | 248 | */ |
| 472 | 249 | private function render_developer_access_status() { |
| 473 | 250 | $current_user = wp_get_current_user(); |
| 474 | - $is_debug_enabled = $this->is_debug_access_enabled(); | |
| 475 | - $debug_meta = get_user_meta($current_user->ID, 'metasync_debug_enabled', true); | |
| 476 | - | |
| 477 | 251 | ?> |
| 478 | 252 | <div class="debug-section"> |
| 479 | - <h3><span class="status-indicator <?php echo $is_debug_enabled ? 'status-success' : 'status-warning'; ?>"></span>Developer Access Status</h3> | |
| 253 | + <h3><span class="status-indicator status-success"></span>Administrator Access</h3> | |
| 480 | 254 | |
| 481 | - <div class="debug-item <?php echo $is_debug_enabled ? 'success' : 'warning'; ?>"> | |
| 255 | + <div class="debug-item success"> | |
| 482 | 256 | <strong>Debug Access:</strong> |
| 483 | - <span class="debug-value"><?php echo $is_debug_enabled ? 'Granted' : 'Not Granted'; ?></span> | |
| 257 | + <span class="debug-value">Granted via manage_options</span> | |
| 484 | 258 | </div> |
| 485 | 259 | |
| 486 | 260 | <div class="debug-item info"> |
| 487 | 261 | <strong>Current User:</strong> |
| 488 | - <span class="debug-value"><?php echo esc_html($current_user->user_login); ?> (ID: <?php echo $current_user->ID; ?>)</span> | |
| 262 | + <span class="debug-value"><?php echo esc_html($current_user->user_login); ?> (ID: <?php echo (int) $current_user->ID; ?>)</span> | |
| 489 | 263 | </div> |
| 490 | 264 | |
| 491 | 265 | <div class="debug-item info"> |
| 492 | 266 | <strong>User Roles:</strong> |
| 493 | - <span class="debug-value"><?php echo implode(', ', $current_user->roles); ?></span> | |
| 267 | + <span class="debug-value"><?php echo esc_html(implode(', ', $current_user->roles)); ?></span> | |
| 494 | 268 | </div> |
| 495 | 269 | |
| 496 | - <div class="debug-item info"> | |
| 497 | - <strong>Email Domain:</strong> | |
| 498 | - <span class="debug-value"><?php echo esc_html(substr(strrchr($current_user->user_email, "@"), 1)); ?></span> | |
| 499 | - </div> | |
| 500 | - | |
| 501 | - <div class="debug-item info"> | |
| 502 | - <strong>Debug Meta:</strong> | |
| 503 | - <span class="debug-value"><?php echo $debug_meta ? esc_html($debug_meta) : 'Not Set'; ?></span> | |
| 504 | - </div> | |
| 505 | - | |
| 506 | - <?php if (!$is_debug_enabled): ?> | |
| 507 | - <div class="debug-item warning"> | |
| 508 | - <strong>Enable Debug Access:</strong> | |
| 509 | - <p><strong>Method 1 - Magic Word (Recommended):</strong></p> | |
| 510 | - <p>Add this parameter to any WordPress admin URL:</p> | |
| 511 | - <div class="debug-value"> | |
| 512 | - <code>?metasync_debug=abracadabra@2020</code> | |
| 513 | - </div> | |
| 514 | - <p><strong>Example:</strong> <code><?php echo esc_html(admin_url('admin.php?metasync_debug=abracadabra@2020')); ?></code></p> | |
| 515 | - | |
| 516 | - <p><strong>Method 2 - User Meta:</strong></p> | |
| 517 | - <p>Run this code in WordPress:</p> | |
| 518 | - <div class="debug-value"> | |
| 519 | - <code>Metasync_Otto_Debug::enable_developer_access(<?php echo $current_user->ID; ?>);</code> | |
| 520 | - </div> | |
| 521 | - | |
| 522 | - <p><strong>Method 3 - WordPress CLI:</strong></p> | |
| 523 | - <div class="debug-value"> | |
| 524 | - <code>wp user meta update <?php echo $current_user->ID; ?> metasync_debug_enabled true</code> | |
| 525 | - </div> | |
| 526 | - </div> | |
| 527 | - <?php else: ?> | |
| 528 | 270 | <div class="debug-item success"> |
| 529 | 271 | <strong>Debug Access Active</strong> |
| 530 | 272 | <p>You have access to all <?php echo esc_html(Metasync::get_whitelabel_otto_name()); ?> debug tools and diagnostics.</p> |
| 531 | - <p><strong>Magic Word:</strong> <code>abracadabra@2020</code></p> | |
| 532 | - <p><strong>Access URL:</strong> <code><?php echo esc_html(self::get_debug_access_url()); ?></code></p> | |
| 533 | 273 | </div> |
| 534 | - <?php endif; ?> | |
| 535 | 274 | </div> |
| 536 | 275 | <?php |
| 537 | 276 | } |
| 538 | 277 | |
| @@ -622,9 +361,9 @@ | ||
| 622 | 361 | </div> |
| 623 | 362 | |
| 624 | 363 | <div class="debug-item info"> |
| 625 | 364 | <strong>Plugin Version:</strong> |
| 626 | - <span class="debug-value"><?php echo defined('METASYNC_VERSION') ? METASYNC_VERSION : 'Unknown'; ?></span> | |
| 365 | + <span class="debug-value"><?php echo esc_html(defined('METASYNC_VERSION') ? METASYNC_VERSION : 'Unknown'); ?></span> | |
| 627 | 366 | </div> |
| 628 | 367 | </div> |
| 629 | 368 | <?php |
| 630 | 369 | } |
| @@ -726,64 +465,13 @@ | ||
| 726 | 465 | <?php |
| 727 | 466 | } |
| 728 | 467 | |
| 729 | 468 | /** |
| 730 | - * Render crawl data status | |
| 731 | - */ | |
| 732 | - private function render_crawl_data_status() { | |
| 733 | - $crawl_data = get_option('metasync_otto_crawldata'); | |
| 734 | - | |
| 735 | - ?> | |
| 736 | - <div class="debug-section"> | |
| 737 | - <h3><span class="status-indicator <?php echo !empty($crawl_data) ? 'status-success' : 'status-warning'; ?>"></span>Crawl Data Status</h3> | |
| 738 | - | |
| 739 | - <div class="debug-item <?php echo !empty($crawl_data) ? 'success' : 'warning'; ?>"> | |
| 740 | - <strong>Crawl Data Available:</strong> | |
| 741 | - <span class="debug-value"><?php echo !empty($crawl_data) ? 'Yes' : 'No'; ?></span> | |
| 742 | - </div> | |
| 743 | - | |
| 744 | - <?php if (!empty($crawl_data)): ?> | |
| 745 | - <div class="debug-item info"> | |
| 746 | - <strong>Domain:</strong> | |
| 747 | - <span class="debug-value"><?php echo esc_html($crawl_data['domain'] ?? 'Not Set'); ?></span> | |
| 748 | - </div> | |
| 749 | - | |
| 750 | - <div class="debug-item info"> | |
| 751 | - <strong>Total URLs Crawled:</strong> | |
| 752 | - <span class="debug-value"><?php echo count($crawl_data['urls'] ?? []); ?></span> | |
| 753 | - </div> | |
| 754 | - | |
| 755 | - <div class="debug-item info"> | |
| 756 | - <strong>Last Updated:</strong> | |
| 757 | - <span class="debug-value"><?php echo $this->get_option_last_updated('metasync_otto_crawldata'); ?></span> | |
| 758 | - </div> | |
| 759 | - | |
| 760 | - <div class="debug-item info"> | |
| 761 | - <strong>Sample URLs:</strong> | |
| 762 | - <div class="debug-value"> | |
| 763 | - <?php | |
| 764 | - $sample_urls = array_slice($crawl_data['urls'] ?? [], 0, 5); | |
| 765 | - foreach ($sample_urls as $url) { | |
| 766 | - echo esc_html($url) . '<br>'; | |
| 767 | - } | |
| 768 | - if (count($crawl_data['urls'] ?? []) > 5) { | |
| 769 | - echo '... and ' . (count($crawl_data['urls']) - 5) . ' more'; | |
| 770 | - } | |
| 771 | - ?> | |
| 772 | - </div> | |
| 773 | - </div> | |
| 774 | - <?php endif; ?> | |
| 775 | - </div> | |
| 776 | - <?php | |
| 777 | - } | |
| 778 | - | |
| 779 | - /** | |
| 780 | 469 | * Render processing status |
| 781 | 470 | */ |
| 782 | 471 | private function render_processing_status() { |
| 783 | 472 | $current_url = $this->get_current_url(); |
| 784 | - $otto_pixel = new Metasync_otto_pixel(Metasync::get_option('general')['otto_pixel_uuid'] ?? ''); | |
| 785 | - $is_crawled = $otto_pixel->is_url_crawled($current_url); | |
| 473 | + $is_crawled = self::is_url_crawled($current_url); | |
| 786 | 474 | $render_diagnostics = $this->get_render_strategy_diagnostics(); |
| 787 | 475 | |
| 788 | 476 | ?> |
| 789 | 477 | <div class="debug-section"> |
| @@ -805,19 +493,19 @@ | ||
| 805 | 493 | </div> |
| 806 | 494 | |
| 807 | 495 | <div class="debug-item info"> |
| 808 | 496 | <strong>Page Type:</strong> |
| 809 | - <span class="debug-value"><?php echo $this->get_page_type(); ?></span> | |
| 497 | + <span class="debug-value"><?php echo esc_html($this->get_page_type()); ?></span> | |
| 810 | 498 | </div> |
| 811 | 499 | |
| 812 | 500 | <div class="debug-item info"> |
| 813 | 501 | <strong>Cache Status:</strong> |
| 814 | - <span class="debug-value"><?php echo $this->get_cache_status(); ?></span> | |
| 502 | + <span class="debug-value"><?php echo esc_html($this->get_cache_status()); ?></span> | |
| 815 | 503 | </div> |
| 816 | 504 | |
| 817 | 505 | <div class="debug-item info"> |
| 818 | 506 | <strong>Processing Method:</strong> |
| 819 | - <span class="debug-value"><?php echo $this->get_processing_method(); ?></span> | |
| 507 | + <span class="debug-value"><?php echo esc_html($this->get_processing_method()); ?></span> | |
| 820 | 508 | </div> |
| 821 | 509 | |
| 822 | 510 | <?php if (!empty($render_diagnostics) && isset($render_diagnostics['available']) === false): ?> |
| 823 | 511 | <div class="debug-item info"> |
| @@ -929,29 +617,8 @@ | ||
| 929 | 617 | return !is_wp_error($response) && wp_remote_retrieve_response_code($response) === 200; |
| 930 | 618 | } |
| 931 | 619 | |
| 932 | 620 | /** |
| 933 | - * Get option last updated time | |
| 934 | - */ | |
| 935 | - private function get_option_last_updated($option_name) { | |
| 936 | - global $wpdb; | |
| 937 | - | |
| 938 | - $result = $wpdb->get_var($wpdb->prepare( | |
| 939 | - "SELECT option_value FROM {$wpdb->options} WHERE option_name = %s", | |
| 940 | - $option_name | |
| 941 | - )); | |
| 942 | - | |
| 943 | - if ($result) { | |
| 944 | - $data = maybe_unserialize($result); | |
| 945 | - if (isset($data['last_updated'])) { | |
| 946 | - return date('Y-m-d H:i:s', $data['last_updated']); | |
| 947 | - } | |
| 948 | - } | |
| 949 | - | |
| 950 | - return 'Unknown'; | |
| 951 | - } | |
| 952 | - | |
| 953 | - /** | |
| 954 | 621 | * Get current URL |
| 955 | 622 | */ |
| 956 | 623 | private function get_current_url() { |
| 957 | 624 | $scheme = is_ssl() ? 'https' : 'http'; |
| @@ -1051,9 +718,9 @@ | ||
| 1051 | 718 | */ |
| 1052 | 719 | public function ajax_test_otto_api() { |
| 1053 | 720 | check_ajax_referer('metasync_otto_debug', 'nonce'); |
| 1054 | 721 | |
| 1055 | - if (!Metasync::current_user_has_plugin_access()) { | |
| 722 | + if (!current_user_can('manage_options') || !self::is_debug_tools_enabled()) { | |
| 1056 | 723 | wp_die('Unauthorized'); |
| 1057 | 724 | } |
| 1058 | 725 | |
| 1059 | 726 | $general_options = Metasync::get_option('general'); |
| @@ -1107,9 +774,9 @@ | ||
| 1107 | 774 | */ |
| 1108 | 775 | public function ajax_test_notification_endpoint() { |
| 1109 | 776 | check_ajax_referer('metasync_otto_debug', 'nonce'); |
| 1110 | 777 | |
| 1111 | - if (!Metasync::current_user_has_plugin_access()) { | |
| 778 | + if (!current_user_can('manage_options') || !self::is_debug_tools_enabled()) { | |
| 1112 | 779 | wp_die('Unauthorized'); |
| 1113 | 780 | } |
| 1114 | 781 | |
| 1115 | 782 | $endpoint_url = rest_url('metasync/v1/otto_crawl_notify'); |
| @@ -1149,20 +816,23 @@ | ||
| 1149 | 816 | * AJAX handler for clearing OTTO cache |
| 1150 | 817 | */ |
| 1151 | 818 | public function ajax_clear_otto_cache() { |
| 1152 | 819 | check_ajax_referer('metasync_otto_debug', 'nonce'); |
| 1153 | - | |
| 1154 | - if (!Metasync::current_user_has_plugin_access()) { | |
| 820 | + | |
| 821 | + if (!current_user_can('manage_options') || !self::is_debug_tools_enabled()) { | |
| 1155 | 822 | wp_die('Unauthorized'); |
| 1156 | 823 | } |
| 1157 | - | |
| 1158 | - // Clear crawl data | |
| 824 | + | |
| 825 | + // Clear the retired crawl-data option if an internal debug tool is | |
| 826 | + // ever re-enabled. This explicit action is harmless and preserves | |
| 827 | + // the old clear-cache contract; production never reaches this | |
| 828 | + // handler because debug tools are hard-disabled. | |
| 1159 | 829 | delete_option('metasync_otto_crawldata'); |
| 1160 | - | |
| 830 | + | |
| 1161 | 831 | // Clear any cached API responses |
| 1162 | 832 | $general_options = Metasync::get_option('general'); |
| 1163 | 833 | $otto_uuid = $general_options['otto_pixel_uuid'] ?? ''; |
| 1164 | - | |
| 834 | + | |
| 1165 | 835 | if (!empty($otto_uuid)) { |
| 1166 | 836 | delete_transient(Metasync_Heartbeat_Manager::public_hash_cache_key($otto_uuid)); |
| 1167 | 837 | } |
| 1168 | 838 | |
| @@ -1182,9 +852,9 @@ | ||
| 1182 | 852 | */ |
| 1183 | 853 | public function ajax_simulate_crawl_notification() { |
| 1184 | 854 | check_ajax_referer('metasync_otto_debug', 'nonce'); |
| 1185 | 855 | |
| 1186 | - if (!Metasync::current_user_has_plugin_access()) { | |
| 856 | + if (!current_user_can('manage_options') || !self::is_debug_tools_enabled()) { | |
| 1187 | 857 | wp_die('Unauthorized'); |
| 1188 | 858 | } |
| 1189 | 859 | |
| 1190 | 860 | $general_options = Metasync::get_option('general'); |
| @@ -1221,9 +891,9 @@ | ||
| 1221 | 891 | public function ajax_test_specific_url() { |
| 1222 | 892 | try { |
| 1223 | 893 | check_ajax_referer('metasync_otto_debug', 'nonce'); |
| 1224 | 894 | |
| 1225 | - if (!Metasync::current_user_has_plugin_access()) { | |
| 895 | + if (!current_user_can('manage_options') || !self::is_debug_tools_enabled()) { | |
| 1226 | 896 | wp_die('Unauthorized'); |
| 1227 | 897 | } |
| 1228 | 898 | |
| 1229 | 899 | $test_url = sanitize_url($_POST['test_url'] ?? ''); |
| @@ -1255,9 +925,9 @@ | ||
| 1255 | 925 | |
| 1256 | 926 | wp_send_json_success($results); |
| 1257 | 927 | |
| 1258 | 928 | } catch (Exception $e) { |
| 1259 | - error_log('MetaSync OTTO Debug: Exception in ajax_test_specific_url: ' . $e->getMessage()); | |
| 929 | + 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 | |
| 1260 | 930 | wp_send_json_error('Exception: ' . $e->getMessage()); |
| 1261 | 931 | } |
| 1262 | 932 | } |
| 1263 | 933 | |
| @@ -1266,9 +936,9 @@ | ||
| 1266 | 936 | */ |
| 1267 | 937 | public function ajax_emulate_otto_changes() { |
| 1268 | 938 | check_ajax_referer('metasync_otto_debug', 'nonce'); |
| 1269 | 939 | |
| 1270 | - if (!Metasync::current_user_has_plugin_access()) { | |
| 940 | + if (!current_user_can('manage_options') || !self::is_debug_tools_enabled()) { | |
| 1271 | 941 | wp_die('Unauthorized'); |
| 1272 | 942 | } |
| 1273 | 943 | |
| 1274 | 944 | $test_url = sanitize_url($_POST['test_url'] ?? ''); |
| @@ -1362,27 +1032,27 @@ | ||
| 1362 | 1032 | /** |
| 1363 | 1033 | * Test crawl status for URL |
| 1364 | 1034 | */ |
| 1365 | 1035 | private function test_crawl_status($url) { |
| 1366 | - if (class_exists('Metasync_otto_pixel')) { | |
| 1367 | - $otto_pixel = new Metasync_otto_pixel(false); | |
| 1368 | - $is_crawled = $otto_pixel->is_url_crawled($url); | |
| 1369 | - | |
| 1370 | - // Get crawl data from options | |
| 1371 | - $crawl_data = get_option('metasync_otto_crawldata'); | |
| 1372 | - | |
| 1036 | + if (class_exists('Metasync_Otto_Job_Status')) { | |
| 1037 | + $entry = Metasync_Otto_Job_Status::get($url); | |
| 1038 | + $is_crawled = is_array($entry) | |
| 1039 | + && isset($entry['state']) | |
| 1040 | + && $entry['state'] === Metasync_Otto_Job_Status::STATE_COMPLETED; | |
| 1041 | + | |
| 1373 | 1042 | return array( |
| 1374 | 1043 | 'status' => 'success', |
| 1375 | 1044 | 'is_crawled' => $is_crawled, |
| 1376 | - 'crawl_data' => $crawl_data, | |
| 1377 | - 'total_crawled_urls' => count($crawl_data['urls'] ?? array()), | |
| 1378 | - 'domain' => $crawl_data['domain'] ?? 'Not set' | |
| 1045 | + 'job_state' => is_array($entry) && isset($entry['state']) ? $entry['state'] : 'unknown', | |
| 1046 | + 'job_stage' => is_array($entry) && isset($entry['stage']) ? $entry['stage'] : '', | |
| 1047 | + 'job_attempts' => is_array($entry) && isset($entry['attempts']) ? (int) $entry['attempts'] : 0, | |
| 1048 | + 'job_updated' => is_array($entry) && isset($entry['updated']) ? $entry['updated'] : null | |
| 1379 | 1049 | ); |
| 1380 | 1050 | } |
| 1381 | - | |
| 1051 | + | |
| 1382 | 1052 | return array( |
| 1383 | 1053 | 'status' => 'error', |
| 1384 | - 'message' => Metasync::get_whitelabel_otto_name() . ' pixel class not available' | |
| 1054 | + 'message' => Metasync::get_whitelabel_otto_name() . ' job status class not available' | |
| 1385 | 1055 | ); |
| 1386 | 1056 | } |
| 1387 | 1057 | |
| 1388 | 1058 | /** |
| @@ -1388,9 +1058,9 @@ | ||
| 1388 | 1058 | /** |
| 1389 | 1059 | * Test page type detection |
| 1390 | 1060 | */ |
| 1391 | 1061 | private function test_page_type_detection($url) { |
| 1392 | - $parsed_url = parse_url($url); | |
| 1062 | + $parsed_url = wp_parse_url($url); | |
| 1393 | 1063 | $path = $parsed_url['path'] ?? '/'; |
| 1394 | 1064 | |
| 1395 | 1065 | $detection = array( |
| 1396 | 1066 | 'url' => $url, |
| @@ -1489,9 +1159,9 @@ | ||
| 1489 | 1159 | public function ajax_simple_test() { |
| 1490 | 1160 | try { |
| 1491 | 1161 | check_ajax_referer('metasync_otto_debug', 'nonce'); |
| 1492 | 1162 | |
| 1493 | - if (!Metasync::current_user_has_plugin_access()) { | |
| 1163 | + if (!current_user_can('manage_options') || !self::is_debug_tools_enabled()) { | |
| 1494 | 1164 | wp_send_json_error('Unauthorized'); |
| 1495 | 1165 | } |
| 1496 | 1166 | |
| 1497 | 1167 | wp_send_json_success(array( |
| @@ -1501,9 +1171,9 @@ | ||
| 1501 | 1171 | 'nonce_verified' => true |
| 1502 | 1172 | )); |
| 1503 | 1173 | |
| 1504 | 1174 | } catch (Exception $e) { |
| 1505 | - error_log('MetaSync OTTO Debug: Exception in ajax_simple_test: ' . $e->getMessage()); | |
| 1175 | + error_log('MetaSync OTTO Debug: Exception in ajax_simple_test: ' . $e->getMessage()); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- unreachable in production | |
| 1506 | 1176 | wp_send_json_error('Exception: ' . $e->getMessage()); |
| 1507 | 1177 | } |
| 1508 | 1178 | } |
| 1509 | 1179 | |
| @@ -1513,9 +1183,9 @@ | ||
| 1513 | 1183 | public function ajax_test_db_permissions() { |
| 1514 | 1184 | try { |
| 1515 | 1185 | check_ajax_referer('metasync_otto_debug', 'nonce'); |
| 1516 | 1186 | |
| 1517 | - if (!Metasync::current_user_has_plugin_access()) { | |
| 1187 | + if (!current_user_can('manage_options') || !self::is_debug_tools_enabled()) { | |
| 1518 | 1188 | wp_send_json_error('Unauthorized'); |
| 1519 | 1189 | } |
| 1520 | 1190 | |
| 1521 | 1191 | $results = array( |
| @@ -1535,9 +1205,9 @@ | ||
| 1535 | 1205 | |
| 1536 | 1206 | // Test 2: Check if we can access Action Scheduler tables |
| 1537 | 1207 | global $wpdb; |
| 1538 | 1208 | $table_name = $wpdb->prefix . 'actionscheduler_actions'; |
| 1539 | - $table_exists = $wpdb->get_var("SHOW TABLES LIKE '$table_name'") == $table_name; | |
| 1209 | + $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 | |
| 1540 | 1210 | |
| 1541 | 1211 | $results['tests']['table_access'] = array( |
| 1542 | 1212 | 'table_exists' => $table_exists, |
| 1543 | 1213 | 'table_name' => $table_name, |
| @@ -1545,9 +1215,9 @@ | ||
| 1545 | 1215 | ); |
| 1546 | 1216 | |
| 1547 | 1217 | // Test 3: Try to insert a test record |
| 1548 | 1218 | if ($table_exists) { |
| 1549 | - $insert_result = $wpdb->insert( | |
| 1219 | + $insert_result = $wpdb->insert( // phpcs:ignore WordPress.DB.DirectDatabaseQuery -- admin debug tool — scratch diagnostics storage outside any WordPress API | |
| 1550 | 1220 | $table_name, |
| 1551 | 1221 | array( |
| 1552 | 1222 | 'hook' => 'metasync_debug_test', |
| 1553 | 1223 | 'status' => 'pending', |
| @@ -1566,9 +1236,9 @@ | ||
| 1566 | 1236 | ); |
| 1567 | 1237 | |
| 1568 | 1238 | // Clean up test record |
| 1569 | 1239 | if ($insert_result !== false && $wpdb->insert_id) { |
| 1570 | - $wpdb->delete($table_name, array('ID' => $wpdb->insert_id)); | |
| 1240 | + $wpdb->delete($table_name, array('ID' => $wpdb->insert_id)); // phpcs:ignore WordPress.DB.DirectDatabaseQuery -- admin debug tool — scratch diagnostics storage outside any WordPress API | |
| 1571 | 1241 | } |
| 1572 | 1242 | } |
| 1573 | 1243 | |
| 1574 | 1244 | // Test 4: Check WordPress cron functionality |
| @@ -1580,9 +1250,9 @@ | ||
| 1580 | 1250 | |
| 1581 | 1251 | wp_send_json_success($results); |
| 1582 | 1252 | |
| 1583 | 1253 | } catch (Exception $e) { |
| 1584 | - error_log('MetaSync OTTO Debug: Exception in ajax_test_db_permissions: ' . $e->getMessage()); | |
| 1254 | + 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 | |
| 1585 | 1255 | wp_send_json_error('Exception: ' . $e->getMessage()); |
| 1586 | 1256 | } |
| 1587 | 1257 | } |
| 1588 | 1258 | } |