PluginProbe
Search Atlas SEO – OTTO AI SEO Automation for WordPress / 2.7.1
Search Atlas SEO – OTTO AI SEO Automation for WordPress v2.7.1
2.7.1 2.7.2 2.7.0 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 All 141 releases
← All changes | admin/class-metasync-otto-debug.php +38 -315 2.6.11 → 2.7.1 View file →
@@ -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,29 @@
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 + * Add debug menu (internal only - hidden on customer production sites)
68 + */
58 69 public function add_debug_menu() {
59 - // Check if user has developer capabilities
60 - if (!Metasync::current_user_has_plugin_access()) {
70 + if (!current_user_can('manage_options') || !self::is_debug_tools_enabled()) {
61 71 return;
62 72 }
63 73
64 - // Check if debug access is enabled via magic word
65 - if (!$this->is_debug_access_enabled()) {
66 - return;
67 - }
68 -
69 74 $menu_slug = Metasync_Admin::$page_slug;
70 75
71 76 add_submenu_page(
72 77 $menu_slug,
@@ -78,169 +83,13 @@
78 83 );
79 84 }
80 85
81 86 /**
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 87 * Create the debug page
230 88 */
231 89 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;
90 + if (!current_user_can('manage_options') || !self::is_debug_tools_enabled()) {
91 + wp_die('Unauthorized');
243 92 }
244 93
245 94 $whitelabel_otto_name = Metasync::get_whitelabel_otto_name();
246 95 ?>
@@ -378,110 +227,19 @@
378 227 <?php
379 228 }
380 229
381 230 /**
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 MetaSync 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 231 * Render developer access status section
471 232 */
472 233 private function render_developer_access_status() {
473 234 $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 235 ?>
478 236 <div class="debug-section">
479 - <h3><span class="status-indicator <?php echo $is_debug_enabled ? 'status-success' : 'status-warning'; ?>"></span>Developer Access Status</h3>
237 + <h3><span class="status-indicator status-success"></span>Administrator Access</h3>
480 238
481 - <div class="debug-item <?php echo $is_debug_enabled ? 'success' : 'warning'; ?>">
239 + <div class="debug-item success">
482 240 <strong>Debug Access:</strong>
483 - <span class="debug-value"><?php echo $is_debug_enabled ? 'Granted' : 'Not Granted'; ?></span>
241 + <span class="debug-value">Granted via manage_options</span>
484 242 </div>
485 243
486 244 <div class="debug-item info">
487 245 <strong>Current User:</strong>
@@ -492,47 +250,12 @@
492 250 <strong>User Roles:</strong>
493 251 <span class="debug-value"><?php echo implode(', ', $current_user->roles); ?></span>
494 252 </div>
495 253
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 254 <div class="debug-item success">
529 255 <strong>Debug Access Active</strong>
530 256 <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 257 </div>
534 - <?php endif; ?>
535 258 </div>
536 259 <?php
537 260 }
538 261
@@ -934,9 +657,9 @@
934 657 */
935 658 private function get_option_last_updated($option_name) {
936 659 global $wpdb;
937 660
938 - $result = $wpdb->get_var($wpdb->prepare(
661 + $result = $wpdb->get_var($wpdb->prepare( // phpcs:ignore WordPress.DB.DirectDatabaseQuery -- admin debug tool — scratch diagnostics storage outside any WordPress API
939 662 "SELECT option_value FROM {$wpdb->options} WHERE option_name = %s",
940 663 $option_name
941 664 ));
942 665
@@ -942,9 +665,9 @@
942 665
943 666 if ($result) {
944 667 $data = maybe_unserialize($result);
945 668 if (isset($data['last_updated'])) {
946 - return date('Y-m-d H:i:s', $data['last_updated']);
669 + return gmdate('Y-m-d H:i:s', $data['last_updated']);
947 670 }
948 671 }
949 672
950 673 return 'Unknown';
@@ -1051,9 +774,9 @@
1051 774 */
1052 775 public function ajax_test_otto_api() {
1053 776 check_ajax_referer('metasync_otto_debug', 'nonce');
1054 777
1055 - if (!Metasync::current_user_has_plugin_access()) {
778 + if (!current_user_can('manage_options') || !self::is_debug_tools_enabled()) {
1056 779 wp_die('Unauthorized');
1057 780 }
1058 781
1059 782 $general_options = Metasync::get_option('general');
@@ -1107,9 +830,9 @@
1107 830 */
1108 831 public function ajax_test_notification_endpoint() {
1109 832 check_ajax_referer('metasync_otto_debug', 'nonce');
1110 833
1111 - if (!Metasync::current_user_has_plugin_access()) {
834 + if (!current_user_can('manage_options') || !self::is_debug_tools_enabled()) {
1112 835 wp_die('Unauthorized');
1113 836 }
1114 837
1115 838 $endpoint_url = rest_url('metasync/v1/otto_crawl_notify');
@@ -1150,9 +873,9 @@
1150 873 */
1151 874 public function ajax_clear_otto_cache() {
1152 875 check_ajax_referer('metasync_otto_debug', 'nonce');
1153 876
1154 - if (!Metasync::current_user_has_plugin_access()) {
877 + if (!current_user_can('manage_options') || !self::is_debug_tools_enabled()) {
1155 878 wp_die('Unauthorized');
1156 879 }
1157 880
1158 881 // Clear crawl data
@@ -1182,9 +905,9 @@
1182 905 */
1183 906 public function ajax_simulate_crawl_notification() {
1184 907 check_ajax_referer('metasync_otto_debug', 'nonce');
1185 908
1186 - if (!Metasync::current_user_has_plugin_access()) {
909 + if (!current_user_can('manage_options') || !self::is_debug_tools_enabled()) {
1187 910 wp_die('Unauthorized');
1188 911 }
1189 912
1190 913 $general_options = Metasync::get_option('general');
@@ -1221,9 +944,9 @@
1221 944 public function ajax_test_specific_url() {
1222 945 try {
1223 946 check_ajax_referer('metasync_otto_debug', 'nonce');
1224 947
1225 - if (!Metasync::current_user_has_plugin_access()) {
948 + if (!current_user_can('manage_options') || !self::is_debug_tools_enabled()) {
1226 949 wp_die('Unauthorized');
1227 950 }
1228 951
1229 952 $test_url = sanitize_url($_POST['test_url'] ?? '');
@@ -1255,9 +978,9 @@
1255 978
1256 979 wp_send_json_success($results);
1257 980
1258 981 } catch (Exception $e) {
1259 - error_log('MetaSync OTTO Debug: Exception in ajax_test_specific_url: ' . $e->getMessage());
982 + 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 983 wp_send_json_error('Exception: ' . $e->getMessage());
1261 984 }
1262 985 }
1263 986
@@ -1266,9 +989,9 @@
1266 989 */
1267 990 public function ajax_emulate_otto_changes() {
1268 991 check_ajax_referer('metasync_otto_debug', 'nonce');
1269 992
1270 - if (!Metasync::current_user_has_plugin_access()) {
993 + if (!current_user_can('manage_options') || !self::is_debug_tools_enabled()) {
1271 994 wp_die('Unauthorized');
1272 995 }
1273 996
1274 997 $test_url = sanitize_url($_POST['test_url'] ?? '');
@@ -1388,9 +1111,9 @@
1388 1111 /**
1389 1112 * Test page type detection
1390 1113 */
1391 1114 private function test_page_type_detection($url) {
1392 - $parsed_url = parse_url($url);
1115 + $parsed_url = wp_parse_url($url);
1393 1116 $path = $parsed_url['path'] ?? '/';
1394 1117
1395 1118 $detection = array(
1396 1119 'url' => $url,
@@ -1489,9 +1212,9 @@
1489 1212 public function ajax_simple_test() {
1490 1213 try {
1491 1214 check_ajax_referer('metasync_otto_debug', 'nonce');
1492 1215
1493 - if (!Metasync::current_user_has_plugin_access()) {
1216 + if (!current_user_can('manage_options') || !self::is_debug_tools_enabled()) {
1494 1217 wp_send_json_error('Unauthorized');
1495 1218 }
1496 1219
1497 1220 wp_send_json_success(array(
@@ -1501,9 +1224,9 @@
1501 1224 'nonce_verified' => true
1502 1225 ));
1503 1226
1504 1227 } catch (Exception $e) {
1505 - error_log('MetaSync OTTO Debug: Exception in ajax_simple_test: ' . $e->getMessage());
1228 + 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 1229 wp_send_json_error('Exception: ' . $e->getMessage());
1507 1230 }
1508 1231 }
1509 1232
@@ -1513,9 +1236,9 @@
1513 1236 public function ajax_test_db_permissions() {
1514 1237 try {
1515 1238 check_ajax_referer('metasync_otto_debug', 'nonce');
1516 1239
1517 - if (!Metasync::current_user_has_plugin_access()) {
1240 + if (!current_user_can('manage_options') || !self::is_debug_tools_enabled()) {
1518 1241 wp_send_json_error('Unauthorized');
1519 1242 }
1520 1243
1521 1244 $results = array(
@@ -1535,9 +1258,9 @@
1535 1258
1536 1259 // Test 2: Check if we can access Action Scheduler tables
1537 1260 global $wpdb;
1538 1261 $table_name = $wpdb->prefix . 'actionscheduler_actions';
1539 - $table_exists = $wpdb->get_var("SHOW TABLES LIKE '$table_name'") == $table_name;
1262 + $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 1263
1541 1264 $results['tests']['table_access'] = array(
1542 1265 'table_exists' => $table_exists,
1543 1266 'table_name' => $table_name,
@@ -1545,9 +1268,9 @@
1545 1268 );
1546 1269
1547 1270 // Test 3: Try to insert a test record
1548 1271 if ($table_exists) {
1549 - $insert_result = $wpdb->insert(
1272 + $insert_result = $wpdb->insert( // phpcs:ignore WordPress.DB.DirectDatabaseQuery -- admin debug tool — scratch diagnostics storage outside any WordPress API
1550 1273 $table_name,
1551 1274 array(
1552 1275 'hook' => 'metasync_debug_test',
1553 1276 'status' => 'pending',
@@ -1566,9 +1289,9 @@
1566 1289 );
1567 1290
1568 1291 // Clean up test record
1569 1292 if ($insert_result !== false && $wpdb->insert_id) {
1570 - $wpdb->delete($table_name, array('ID' => $wpdb->insert_id));
1293 + $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 1294 }
1572 1295 }
1573 1296
1574 1297 // Test 4: Check WordPress cron functionality
@@ -1580,9 +1303,9 @@
1580 1303
1581 1304 wp_send_json_success($results);
1582 1305
1583 1306 } catch (Exception $e) {
1584 - error_log('MetaSync OTTO Debug: Exception in ajax_test_db_permissions: ' . $e->getMessage());
1307 + 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 1308 wp_send_json_error('Exception: ' . $e->getMessage());
1586 1309 }
1587 1310 }
1588 1311 }