PluginProbe
Search Atlas SEO – OTTO AI SEO Automation for WordPress / 2.7.2
Search Atlas SEO – OTTO AI SEO Automation for WordPress v2.7.2
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 | includes/class-metasync-debug-manager.php +96 -38 2.6.24 → 2.7.2 View file →
@@ -72,9 +72,12 @@
72 72 *
73 73 * @param Metasync_Admin $admin The admin instance (needed for header/nav rendering).
74 74 */
75 75 public function metasync_display_error_log($admin) {
76 - $log_file = WP_CONTENT_DIR . '/metasync_data/plugin_errors.log';
76 + $log_file = Metasync_Data_Store::file_path('plugin_errors.log');
77 + if (false === $log_file) {
78 + $log_file = '';
79 + }
77 80 if (!Metasync::current_user_has_plugin_access()) {
78 81 return;
79 82 }
80 83
@@ -98,16 +101,26 @@
98 101 update_option('wp_debug_log_enabled', $wp_debug_log);
99 102 update_option('wp_debug_display_enabled', $wp_debug_display);
100 103
101 104 $data = new ConfigControllerMetaSync();
102 - $data->store();
103 -
104 - add_settings_error(
105 - 'metasync_messages',
106 - 'metasync_message',
107 - 'WordPress debug settings updated successfully.',
108 - 'updated'
109 - );
105 + $saved = $data->store();
106 +
107 + if ($saved) {
108 + add_settings_error(
109 + 'metasync_messages',
110 + 'metasync_message',
111 + 'WordPress debug settings updated successfully.',
112 + 'updated'
113 + );
114 + } else {
115 + add_settings_error(
116 + 'metasync_messages',
117 + 'metasync_message',
118 + 'Debug settings were saved, but wp-config.php could not be updated: '
119 + . ($data->getConfigError() !== '' ? $data->getConfigError() : 'the file is not writable.'),
120 + 'error'
121 + );
122 + }
110 123 } elseif ($can_manage_debug_settings && isset($_POST['wp_debug_nonce']) && !wp_verify_nonce($_POST['wp_debug_nonce'], 'metasync_wp_debug_settings')) {
111 124 add_settings_error(
112 125 'metasync_messages',
113 126 'metasync_message',
@@ -224,9 +237,9 @@
224 237 * Update wp-config.php debug constants.
225 238 */
226 239 public function metasync_update_wp_config() {
227 240 $wp_config_path = ABSPATH . 'wp-config.php';
228 - if (file_exists($wp_config_path) && is_writable($wp_config_path)) {
241 + if (file_exists($wp_config_path) && wp_is_writable($wp_config_path)) {
229 242 $config_file = file_get_contents($wp_config_path);
230 243
231 244 $wp_debug_enabled = get_option('wp_debug_enabled', 'false') === 'true' ? 'true' : 'false';
232 245 if (preg_match("/define\s*\(\s*['\"]WP_DEBUG['\"]\s*,\s*.*?\s*\)\s*;/", $config_file)) {
@@ -248,8 +261,14 @@
248 261 } else {
249 262 $config_file = str_replace("/* That's all, stop editing! Happy publishing. */", "define('WP_DEBUG_DISPLAY', $wp_debug_display_enabled);\n\n/* That's all, stop editing! Happy publishing. */", $config_file);
250 263 }
251 264
265 + // ABSPATH is intentional and verified: the Debug Mode feature
266 + // toggles WP_DEBUG constants in wp-config.php itself, the one
267 + // file whose location ABSPATH exists to describe. It is not a
268 + // plugin-directory or generated-content write, so it stays here
269 + // (Plugin Check's ABSPATHDetected warning is a false positive —
270 + // wp-config.php cannot live in the uploads directory).
252 271 file_put_contents($wp_config_path, $config_file);
253 272 } else {
254 273 wp_die('The wp-config.php file is not writable. Please check the file permissions.');
255 274 }
@@ -381,9 +400,9 @@
381 400 <!-- Debug Mode Controls -->
382 401 <div style="margin-bottom: 30px;">
383 402 <h4 style="margin-top: 0; color: var(--dashboard-text-primary);">Controls</h4>
384 403
385 - <form method="post" action="<?php echo admin_url('admin.php?page=' . $this->get_page_slug() . '&tab=advanced'); ?>">
404 + <form method="post" action="<?php echo esc_url(admin_url('admin.php?page=' . $this->get_page_slug() . '&tab=advanced')); ?>">
386 405 <input type="hidden" name="metasync_debug_mode_action_advanced" value="1" />
387 406 <?php wp_nonce_field('metasync_debug_mode_action_advanced', 'metasync_debug_mode_nonce_advanced'); ?>
388 407
389 408 <?php if (!$status['enabled']): ?>
@@ -479,9 +498,9 @@
479 498 }
480 499 });
481 500
482 501 <?php if ($status['enabled'] && !$status['indefinite']): ?>
483 - var initialTimeRemaining = <?php echo $status['time_remaining']; ?>;
502 + var initialTimeRemaining = <?php echo (int) $status['time_remaining']; ?>;
484 503 var hasReloaded = false;
485 504
486 505 function updateDebugTimeRemaining() {
487 506 if (initialTimeRemaining <= 0 || hasReloaded) {
@@ -488,12 +507,12 @@
488 507 return;
489 508 }
490 509
491 510 $.ajax({
492 - url: '<?php echo rest_url('metasync/v1/debug-mode/status'); ?>',
511 + url: '<?php echo esc_url(rest_url('metasync/v1/debug-mode/status')); ?>',
493 512 method: 'GET',
494 513 beforeSend: function(xhr) {
495 - xhr.setRequestHeader('X-WP-Nonce', '<?php echo wp_create_nonce('wp_rest'); ?>');
514 + xhr.setRequestHeader('X-WP-Nonce', '<?php echo esc_attr(wp_create_nonce('wp_rest')); ?>');
496 515 },
497 516 success: function(response) {
498 517 console.log('MetaSync Debug Mode Status:', response);
499 518
@@ -577,9 +596,9 @@
577 596 <td style="padding: 10px 12px; color: var(--dashboard-text-secondary); font-size: 13px;">
578 597 <?php
579 598 $last_seen = strtotime($error['last_seen']);
580 599 $time_diff = human_time_diff($last_seen, current_time('timestamp'));
581 - echo esc_html($error['last_seen']) . ' <span style="color: var(--dashboard-text-secondary);">(' . $time_diff . ' ago)</span>';
600 + echo esc_html($error['last_seen']) . ' <span style="color: var(--dashboard-text-secondary);">(' . esc_html($time_diff) . ' ago)</span>';
582 601 ?>
583 602 </td>
584 603 <td style="padding: 10px 12px; color: var(--dashboard-text-primary); max-width: 400px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;" title="<?php echo esc_attr($error['message']); ?>">
585 604 <?php echo esc_html($error['message']); ?>
@@ -589,9 +608,9 @@
589 608 </tbody>
590 609 </table>
591 610 </div>
592 611
593 - <form method="post" action="<?php echo admin_url('admin.php?page=' . $this->get_page_slug() . '&tab=advanced'); ?>" style="margin-bottom: 20px;">
612 + <form method="post" action="<?php echo esc_url(admin_url('admin.php?page=' . $this->get_page_slug() . '&tab=advanced')); ?>" style="margin-bottom: 20px;">
594 613 <input type="hidden" name="clear_error_summary" value="yes" />
595 614 <?php wp_nonce_field('metasync_clear_error_summary_nonce', 'clear_error_summary_nonce'); ?>
596 615 <button type="submit" class="button button-secondary" style="background: #dc3232; color: #ffffff; border: none; padding: 8px 16px; border-radius: 4px; font-weight: 500; cursor: pointer;">
597 616 <span class="dashicons dashicons-trash" style="margin-top:3px;font-size:15px;width:15px;height:15px;"></span> Clear Error Summary
@@ -623,9 +642,9 @@
623 642 <div style="margin-bottom: 30px;">
624 643 <h4 style="margin-top: 0; color: var(--dashboard-text-primary);">Clear Error Logs</h4>
625 644 <p style="margin-bottom: 15px; color: var(--dashboard-text-secondary);">Clear WordPress error logs to free up space and remove old entries.</p>
626 645
627 - <form method="post" action="<?php echo admin_url('admin.php?page=' . $this->get_page_slug() . '&tab=advanced'); ?>" style="margin-bottom: 20px;">
646 + <form method="post" action="<?php echo esc_url(admin_url('admin.php?page=' . $this->get_page_slug() . '&tab=advanced')); ?>" style="margin-bottom: 20px;">
628 647 <input type="hidden" name="clear_log" value="yes" />
629 648 <?php wp_nonce_field('metasync_clear_log_nonce', 'clear_log_nonce'); ?>
630 649 <button type="submit" class="metasync-btn-primary" style="background: var(--dashboard-gradient-primary); color: #ffffff; border: none; padding: 10px 20px; border-radius: 8px; font-weight: 500; cursor: pointer; transition: all 0.3s ease; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); display: inline-block; width: auto; min-width: 240px; max-width: fit-content;" onmouseover="this.style.transform='translateY(-2px)'; this.style.boxShadow='0 4px 8px rgba(0, 0, 0, 0.15)';" onmouseout="this.style.transform='translateY(0)'; this.style.boxShadow='0 2px 4px rgba(0, 0, 0, 0.1)';">
631 650 🧹 Clear Error Logs
@@ -741,9 +760,9 @@
741 760 {
742 761 if (isset($_POST['metasync_debug_mode_action_advanced'])) {
743 762 if (!wp_verify_nonce($_POST['metasync_debug_mode_nonce_advanced'], 'metasync_debug_mode_action_advanced')) {
744 763 $redirect_url = admin_url('admin.php?page=' . $this->get_page_slug() . '&tab=advanced&debug_error=1');
745 - wp_redirect($redirect_url);
764 + wp_safe_redirect($redirect_url);
746 765 exit;
747 766 }
748 767
749 768 if (!current_user_can('manage_options')) {
@@ -751,9 +770,9 @@
751 770 }
752 771
753 772 if (!class_exists('Metasync_Debug_Mode_Manager')) {
754 773 $redirect_url = admin_url('admin.php?page=' . $this->get_page_slug() . '&tab=advanced&debug_error=1&msg=manager_not_available');
755 - wp_redirect($redirect_url);
774 + wp_safe_redirect($redirect_url);
756 775 exit;
757 776 }
758 777
759 778 $debug_manager = Metasync_Debug_Mode_Manager::get_instance();
@@ -790,9 +809,9 @@
790 809 $redirect_url = add_query_arg('debug_error', '1', $redirect_url);
791 810 break;
792 811 }
793 812
794 - wp_redirect($redirect_url);
813 + wp_safe_redirect($redirect_url);
795 814 exit;
796 815 }
797 816 }
798 817
@@ -806,27 +825,30 @@
806 825 }
807 826
808 827 if (isset($_POST['clear_log'])) {
809 828 if (wp_verify_nonce($_POST['clear_log_nonce'], 'metasync_clear_log_nonce')) {
810 - $log_file = WP_CONTENT_DIR . '/metasync_data/plugin_errors.log';
829 + $data_dir = Metasync_Data_Store::base_dir();
830 + $log_file = Metasync_Data_Store::file_path('plugin_errors.log');
811 831
812 - if (file_exists($log_file)) {
832 + if (false !== $log_file && file_exists($log_file)) {
813 833 file_put_contents($log_file, '');
814 834
815 - $backup_files = glob(WP_CONTENT_DIR . '/metasync_data/plugin_errors.log.old.*');
816 - if ($backup_files) {
817 - foreach ($backup_files as $backup_file) {
818 - @unlink($backup_file);
835 + if (false !== $data_dir) {
836 + $backup_files = glob($data_dir . '/plugin_errors.log.old.*');
837 + if ($backup_files) {
838 + foreach ($backup_files as $backup_file) {
839 + @wp_delete_file($backup_file);
840 + }
819 841 }
820 842 }
821 843 }
822 844
823 845 $redirect_url = admin_url('admin.php?page=' . $this->get_page_slug() . '&tab=advanced&log_cleared=1');
824 - wp_redirect($redirect_url);
846 + wp_safe_redirect($redirect_url);
825 847 exit;
826 848 } else {
827 849 $redirect_url = admin_url('admin.php?page=' . $this->get_page_slug() . '&tab=advanced&clear_error=1');
828 - wp_redirect($redirect_url);
850 + wp_safe_redirect($redirect_url);
829 851 exit;
830 852 }
831 853 }
832 854
@@ -834,18 +856,18 @@
834 856 if (wp_verify_nonce($_POST['clear_error_summary_nonce'], 'metasync_clear_error_summary_nonce')) {
835 857 if (class_exists('Metasync_Error_Logger')) {
836 858 Metasync_Error_Logger::clear_error_summary();
837 859 $redirect_url = admin_url('admin.php?page=' . $this->get_page_slug() . '&tab=advanced&error_summary_cleared=1');
838 - wp_redirect($redirect_url);
860 + wp_safe_redirect($redirect_url);
839 861 exit;
840 862 } else {
841 863 $redirect_url = admin_url('admin.php?page=' . $this->get_page_slug() . '&tab=advanced&error_summary_error=1');
842 - wp_redirect($redirect_url);
864 + wp_safe_redirect($redirect_url);
843 865 exit;
844 866 }
845 867 } else {
846 868 $redirect_url = admin_url('admin.php?page=' . $this->get_page_slug() . '&tab=advanced&error_summary_error=1');
847 - wp_redirect($redirect_url);
869 + wp_safe_redirect($redirect_url);
848 870 exit;
849 871 }
850 872 }
851 873 }
@@ -880,8 +902,18 @@
880 902 // Code Minification settings
881 903 'metasync_code_minification',
882 904 ];
883 905
906 + // Capture the complete white-label identity BEFORE the
907 + // destructive clear so it can be restored afterwards. The
908 + // reset is meant to remove operational data and credentials,
909 + // not the reseller's public branding, logos, domains, custom
910 + // OTTO name, visibility/access controls, or recovery settings.
911 + if (!class_exists('Metasync_Whitelabel_Preservation')) {
912 + require_once plugin_dir_path(dirname(__FILE__)) . 'includes/class-metasync-whitelabel-preservation.php';
913 + }
914 + $whitelabel_state = Metasync_Whitelabel_Preservation::extract_whitelabel_state();
915 +
884 916 $cleared_count = 0;
885 917 foreach ($metasync_options_to_clear as $option_name) {
886 918 if (get_option($option_name) !== false) {
887 919 delete_option($option_name);
@@ -923,15 +955,41 @@
923 955 'options_cleared_count' => $cleared_count,
924 956 'new_token_prefix' => substr($new_plugin_auth_token, 0, 8) . '...',
925 957 'triggered_by' => 'settings_reset_action'
926 958 ), 'info');
927 -
959 +
960 + // Restore the preserved white-label identity over the freshly
961 + // cleared options. A failed restore must not report success.
962 + $restored = Metasync_Whitelabel_Preservation::restore_whitelabel_state($whitelabel_state);
963 + if (!$restored) {
964 + $redirect_url = admin_url('admin.php?page=' . $this->get_page_slug() . '&tab=advanced&clear_settings_error=1');
965 + wp_redirect($redirect_url);
966 + exit;
967 + }
968 +
969 + // Re-synchronise the branded plugin file headers so the
970 + // WordPress plugin list and the plugin UI stay branded after
971 + // the reset. Only attempted when white-label branding exists,
972 + // and a failed sync is logged as a warning, not reported as a
973 + // reset failure: the reset itself (operational clear + fresh
974 + // token + branding restore) has already succeeded at this
975 + // point, and hosts with read-only plugin files would otherwise
976 + // never see a successful reset.
977 + if (!empty($whitelabel_state['whitelabel']) || !empty($whitelabel_state['general'])) {
978 + if (!class_exists('Metasync_Activator')) {
979 + require_once plugin_dir_path(dirname(__FILE__)) . 'includes/class-metasync-activator.php';
980 + }
981 + if (!Metasync_Activator::sync_plugin_file_headers()) {
982 + error_log('MetaSync: failed to re-synchronise branded plugin file headers after the settings reset.');
983 + }
984 + }
985 +
928 986 $redirect_url = admin_url('admin.php?page=' . $this->get_page_slug() . '&tab=advanced&settings_cleared=1');
929 - wp_redirect($redirect_url);
987 + wp_safe_redirect($redirect_url);
930 988 exit;
931 989 } else {
932 990 $redirect_url = admin_url('admin.php?page=' . $this->get_page_slug() . '&tab=advanced&clear_settings_error=1');
933 - wp_redirect($redirect_url);
991 + wp_safe_redirect($redirect_url);
934 992 exit;
935 993 }
936 994 }
937 995 }
@@ -946,9 +1004,9 @@
946 1004 public function get_error_log_content()
947 1005 {
948 1006 $execution_time = $this->get_execution_setting('max_execution_time');
949 1007 if (function_exists('set_time_limit')) {
950 - @set_time_limit($execution_time);
1008 + @set_time_limit($execution_time); // phpcs:ignore Squiz.PHP.DiscouragedFunctions.Discouraged -- runtime PHP setting with no WordPress API
951 1009 }
952 1010
953 1011 $log_file = WP_CONTENT_DIR . '/debug.log';
954 1012
@@ -980,9 +1038,9 @@
980 1038 public function get_log_tail($file_path, $lines = null)
981 1039 {
982 1040 $execution_time = $this->get_execution_setting('max_execution_time');
983 1041 if (function_exists('set_time_limit')) {
984 - @set_time_limit($execution_time);
1042 + @set_time_limit($execution_time); // phpcs:ignore Squiz.PHP.DiscouragedFunctions.Discouraged -- runtime PHP setting with no WordPress API
985 1043 }
986 1044
987 1045 if ($lines === null) {
988 1046 $lines = $this->get_execution_setting('log_batch_size');
@@ -987,9 +1045,9 @@
987 1045 if ($lines === null) {
988 1046 $lines = $this->get_execution_setting('log_batch_size');
989 1047 }
990 1048
991 - $handle = fopen($file_path, 'r');
1049 + $handle = fopen($file_path, 'r'); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fopen -- streaming file I/O; WP_Filesystem cannot return a raw stream handle
992 1050 if (!$handle) {
993 1051 return false;
994 1052 }
995 1053
@@ -1018,9 +1076,9 @@
1018 1076 if (!empty($line) && $line_count < $lines) {
1019 1077 array_unshift($result_lines, strrev($line));
1020 1078 }
1021 1079
1022 - fclose($handle);
1080 + fclose($handle); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fclose -- operates on a native stream handle
1023 1081
1024 1082 return implode("\n", $result_lines);
1025 1083 }
1026 1084 }