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 +78 -30 2.7.0 → 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
@@ -234,9 +237,9 @@
234 237 * Update wp-config.php debug constants.
235 238 */
236 239 public function metasync_update_wp_config() {
237 240 $wp_config_path = ABSPATH . 'wp-config.php';
238 - if (file_exists($wp_config_path) && is_writable($wp_config_path)) {
241 + if (file_exists($wp_config_path) && wp_is_writable($wp_config_path)) {
239 242 $config_file = file_get_contents($wp_config_path);
240 243
241 244 $wp_debug_enabled = get_option('wp_debug_enabled', 'false') === 'true' ? 'true' : 'false';
242 245 if (preg_match("/define\s*\(\s*['\"]WP_DEBUG['\"]\s*,\s*.*?\s*\)\s*;/", $config_file)) {
@@ -258,8 +261,14 @@
258 261 } else {
259 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);
260 263 }
261 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).
262 271 file_put_contents($wp_config_path, $config_file);
263 272 } else {
264 273 wp_die('The wp-config.php file is not writable. Please check the file permissions.');
265 274 }
@@ -391,9 +400,9 @@
391 400 <!-- Debug Mode Controls -->
392 401 <div style="margin-bottom: 30px;">
393 402 <h4 style="margin-top: 0; color: var(--dashboard-text-primary);">Controls</h4>
394 403
395 - <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')); ?>">
396 405 <input type="hidden" name="metasync_debug_mode_action_advanced" value="1" />
397 406 <?php wp_nonce_field('metasync_debug_mode_action_advanced', 'metasync_debug_mode_nonce_advanced'); ?>
398 407
399 408 <?php if (!$status['enabled']): ?>
@@ -489,9 +498,9 @@
489 498 }
490 499 });
491 500
492 501 <?php if ($status['enabled'] && !$status['indefinite']): ?>
493 - var initialTimeRemaining = <?php echo $status['time_remaining']; ?>;
502 + var initialTimeRemaining = <?php echo (int) $status['time_remaining']; ?>;
494 503 var hasReloaded = false;
495 504
496 505 function updateDebugTimeRemaining() {
497 506 if (initialTimeRemaining <= 0 || hasReloaded) {
@@ -498,12 +507,12 @@
498 507 return;
499 508 }
500 509
501 510 $.ajax({
502 - url: '<?php echo rest_url('metasync/v1/debug-mode/status'); ?>',
511 + url: '<?php echo esc_url(rest_url('metasync/v1/debug-mode/status')); ?>',
503 512 method: 'GET',
504 513 beforeSend: function(xhr) {
505 - 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')); ?>');
506 515 },
507 516 success: function(response) {
508 517 console.log('MetaSync Debug Mode Status:', response);
509 518
@@ -587,9 +596,9 @@
587 596 <td style="padding: 10px 12px; color: var(--dashboard-text-secondary); font-size: 13px;">
588 597 <?php
589 598 $last_seen = strtotime($error['last_seen']);
590 599 $time_diff = human_time_diff($last_seen, current_time('timestamp'));
591 - 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>';
592 601 ?>
593 602 </td>
594 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']); ?>">
595 604 <?php echo esc_html($error['message']); ?>
@@ -599,9 +608,9 @@
599 608 </tbody>
600 609 </table>
601 610 </div>
602 611
603 - <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;">
604 613 <input type="hidden" name="clear_error_summary" value="yes" />
605 614 <?php wp_nonce_field('metasync_clear_error_summary_nonce', 'clear_error_summary_nonce'); ?>
606 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;">
607 616 <span class="dashicons dashicons-trash" style="margin-top:3px;font-size:15px;width:15px;height:15px;"></span> Clear Error Summary
@@ -633,9 +642,9 @@
633 642 <div style="margin-bottom: 30px;">
634 643 <h4 style="margin-top: 0; color: var(--dashboard-text-primary);">Clear Error Logs</h4>
635 644 <p style="margin-bottom: 15px; color: var(--dashboard-text-secondary);">Clear WordPress error logs to free up space and remove old entries.</p>
636 645
637 - <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;">
638 647 <input type="hidden" name="clear_log" value="yes" />
639 648 <?php wp_nonce_field('metasync_clear_log_nonce', 'clear_log_nonce'); ?>
640 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)';">
641 650 🧹 Clear Error Logs
@@ -751,9 +760,9 @@
751 760 {
752 761 if (isset($_POST['metasync_debug_mode_action_advanced'])) {
753 762 if (!wp_verify_nonce($_POST['metasync_debug_mode_nonce_advanced'], 'metasync_debug_mode_action_advanced')) {
754 763 $redirect_url = admin_url('admin.php?page=' . $this->get_page_slug() . '&tab=advanced&debug_error=1');
755 - wp_redirect($redirect_url);
764 + wp_safe_redirect($redirect_url);
756 765 exit;
757 766 }
758 767
759 768 if (!current_user_can('manage_options')) {
@@ -761,9 +770,9 @@
761 770 }
762 771
763 772 if (!class_exists('Metasync_Debug_Mode_Manager')) {
764 773 $redirect_url = admin_url('admin.php?page=' . $this->get_page_slug() . '&tab=advanced&debug_error=1&msg=manager_not_available');
765 - wp_redirect($redirect_url);
774 + wp_safe_redirect($redirect_url);
766 775 exit;
767 776 }
768 777
769 778 $debug_manager = Metasync_Debug_Mode_Manager::get_instance();
@@ -800,9 +809,9 @@
800 809 $redirect_url = add_query_arg('debug_error', '1', $redirect_url);
801 810 break;
802 811 }
803 812
804 - wp_redirect($redirect_url);
813 + wp_safe_redirect($redirect_url);
805 814 exit;
806 815 }
807 816 }
808 817
@@ -816,27 +825,30 @@
816 825 }
817 826
818 827 if (isset($_POST['clear_log'])) {
819 828 if (wp_verify_nonce($_POST['clear_log_nonce'], 'metasync_clear_log_nonce')) {
820 - $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');
821 831
822 - if (file_exists($log_file)) {
832 + if (false !== $log_file && file_exists($log_file)) {
823 833 file_put_contents($log_file, '');
824 834
825 - $backup_files = glob(WP_CONTENT_DIR . '/metasync_data/plugin_errors.log.old.*');
826 - if ($backup_files) {
827 - foreach ($backup_files as $backup_file) {
828 - @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 + }
829 841 }
830 842 }
831 843 }
832 844
833 845 $redirect_url = admin_url('admin.php?page=' . $this->get_page_slug() . '&tab=advanced&log_cleared=1');
834 - wp_redirect($redirect_url);
846 + wp_safe_redirect($redirect_url);
835 847 exit;
836 848 } else {
837 849 $redirect_url = admin_url('admin.php?page=' . $this->get_page_slug() . '&tab=advanced&clear_error=1');
838 - wp_redirect($redirect_url);
850 + wp_safe_redirect($redirect_url);
839 851 exit;
840 852 }
841 853 }
842 854
@@ -844,18 +856,18 @@
844 856 if (wp_verify_nonce($_POST['clear_error_summary_nonce'], 'metasync_clear_error_summary_nonce')) {
845 857 if (class_exists('Metasync_Error_Logger')) {
846 858 Metasync_Error_Logger::clear_error_summary();
847 859 $redirect_url = admin_url('admin.php?page=' . $this->get_page_slug() . '&tab=advanced&error_summary_cleared=1');
848 - wp_redirect($redirect_url);
860 + wp_safe_redirect($redirect_url);
849 861 exit;
850 862 } else {
851 863 $redirect_url = admin_url('admin.php?page=' . $this->get_page_slug() . '&tab=advanced&error_summary_error=1');
852 - wp_redirect($redirect_url);
864 + wp_safe_redirect($redirect_url);
853 865 exit;
854 866 }
855 867 } else {
856 868 $redirect_url = admin_url('admin.php?page=' . $this->get_page_slug() . '&tab=advanced&error_summary_error=1');
857 - wp_redirect($redirect_url);
869 + wp_safe_redirect($redirect_url);
858 870 exit;
859 871 }
860 872 }
861 873 }
@@ -890,8 +902,18 @@
890 902 // Code Minification settings
891 903 'metasync_code_minification',
892 904 ];
893 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 +
894 916 $cleared_count = 0;
895 917 foreach ($metasync_options_to_clear as $option_name) {
896 918 if (get_option($option_name) !== false) {
897 919 delete_option($option_name);
@@ -933,15 +955,41 @@
933 955 'options_cleared_count' => $cleared_count,
934 956 'new_token_prefix' => substr($new_plugin_auth_token, 0, 8) . '...',
935 957 'triggered_by' => 'settings_reset_action'
936 958 ), 'info');
937 -
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 +
938 986 $redirect_url = admin_url('admin.php?page=' . $this->get_page_slug() . '&tab=advanced&settings_cleared=1');
939 - wp_redirect($redirect_url);
987 + wp_safe_redirect($redirect_url);
940 988 exit;
941 989 } else {
942 990 $redirect_url = admin_url('admin.php?page=' . $this->get_page_slug() . '&tab=advanced&clear_settings_error=1');
943 - wp_redirect($redirect_url);
991 + wp_safe_redirect($redirect_url);
944 992 exit;
945 993 }
946 994 }
947 995 }
@@ -956,9 +1004,9 @@
956 1004 public function get_error_log_content()
957 1005 {
958 1006 $execution_time = $this->get_execution_setting('max_execution_time');
959 1007 if (function_exists('set_time_limit')) {
960 - @set_time_limit($execution_time);
1008 + @set_time_limit($execution_time); // phpcs:ignore Squiz.PHP.DiscouragedFunctions.Discouraged -- runtime PHP setting with no WordPress API
961 1009 }
962 1010
963 1011 $log_file = WP_CONTENT_DIR . '/debug.log';
964 1012
@@ -990,9 +1038,9 @@
990 1038 public function get_log_tail($file_path, $lines = null)
991 1039 {
992 1040 $execution_time = $this->get_execution_setting('max_execution_time');
993 1041 if (function_exists('set_time_limit')) {
994 - @set_time_limit($execution_time);
1042 + @set_time_limit($execution_time); // phpcs:ignore Squiz.PHP.DiscouragedFunctions.Discouraged -- runtime PHP setting with no WordPress API
995 1043 }
996 1044
997 1045 if ($lines === null) {
998 1046 $lines = $this->get_execution_setting('log_batch_size');
@@ -997,9 +1045,9 @@
997 1045 if ($lines === null) {
998 1046 $lines = $this->get_execution_setting('log_batch_size');
999 1047 }
1000 1048
1001 - $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
1002 1050 if (!$handle) {
1003 1051 return false;
1004 1052 }
1005 1053
@@ -1028,9 +1076,9 @@
1028 1076 if (!empty($line) && $line_count < $lines) {
1029 1077 array_unshift($result_lines, strrev($line));
1030 1078 }
1031 1079
1032 - fclose($handle);
1080 + fclose($handle); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fclose -- operates on a native stream handle
1033 1081
1034 1082 return implode("\n", $result_lines);
1035 1083 }
1036 1084 }