| @@ -72,14 +72,23 @@ | ||
| 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 | } |
| 83 | + | |
| 84 | + $can_manage_debug_settings = current_user_can('manage_options'); | |
| 85 | + if (isset($_POST['wp_debug_nonce']) && !$can_manage_debug_settings) { | |
| 86 | + return; | |
| 87 | + } | |
| 80 | 88 | |
| 81 | - if (isset($_POST['wp_debug_log_enabled']) && | |
| 89 | + if ($can_manage_debug_settings && | |
| 90 | + isset($_POST['wp_debug_log_enabled']) && | |
| 82 | 91 | isset($_POST['wp_debug_enabled']) && |
| 83 | 92 | isset($_POST['wp_debug_display_enabled']) && |
| 84 | 93 | isset($_POST['wp_debug_nonce']) && |
| 85 | 94 | wp_verify_nonce($_POST['wp_debug_nonce'], 'metasync_wp_debug_settings')) { |
| @@ -92,20 +101,30 @@ | ||
| 92 | 101 | update_option('wp_debug_log_enabled', $wp_debug_log); |
| 93 | 102 | update_option('wp_debug_display_enabled', $wp_debug_display); |
| 94 | 103 | |
| 95 | 104 | $data = new ConfigControllerMetaSync(); |
| 96 | - $data->store(); | |
| 97 | - | |
| 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 | + } | |
| 123 | + } elseif ($can_manage_debug_settings && isset($_POST['wp_debug_nonce']) && !wp_verify_nonce($_POST['wp_debug_nonce'], 'metasync_wp_debug_settings')) { | |
| 98 | 124 | add_settings_error( |
| 99 | 125 | 'metasync_messages', |
| 100 | 126 | 'metasync_message', |
| 101 | - 'WordPress debug settings updated successfully.', | |
| 102 | - 'updated' | |
| 103 | - ); | |
| 104 | - } elseif (isset($_POST['wp_debug_nonce']) && !wp_verify_nonce($_POST['wp_debug_nonce'], 'metasync_wp_debug_settings')) { | |
| 105 | - add_settings_error( | |
| 106 | - 'metasync_messages', | |
| 107 | - 'metasync_message', | |
| 108 | 127 | 'Security verification failed. Please try again.', |
| 109 | 128 | 'error' |
| 110 | 129 | ); |
| 111 | 130 | } |
| @@ -218,9 +237,9 @@ | ||
| 218 | 237 | * Update wp-config.php debug constants. |
| 219 | 238 | */ |
| 220 | 239 | public function metasync_update_wp_config() { |
| 221 | 240 | $wp_config_path = ABSPATH . 'wp-config.php'; |
| 222 | - if (file_exists($wp_config_path) && is_writable($wp_config_path)) { | |
| 241 | + if (file_exists($wp_config_path) && wp_is_writable($wp_config_path)) { | |
| 223 | 242 | $config_file = file_get_contents($wp_config_path); |
| 224 | 243 | |
| 225 | 244 | $wp_debug_enabled = get_option('wp_debug_enabled', 'false') === 'true' ? 'true' : 'false'; |
| 226 | 245 | if (preg_match("/define\s*\(\s*['\"]WP_DEBUG['\"]\s*,\s*.*?\s*\)\s*;/", $config_file)) { |
| @@ -242,8 +261,14 @@ | ||
| 242 | 261 | } else { |
| 243 | 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); |
| 244 | 263 | } |
| 245 | 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). | |
| 246 | 271 | file_put_contents($wp_config_path, $config_file); |
| 247 | 272 | } else { |
| 248 | 273 | wp_die('The wp-config.php file is not writable. Please check the file permissions.'); |
| 249 | 274 | } |
| @@ -280,9 +305,15 @@ | ||
| 280 | 305 | } |
| 281 | 306 | } |
| 282 | 307 | |
| 283 | 308 | if ($changed) { |
| 284 | - require_once plugin_dir_path(dirname(__FILE__)) . 'includes/class-metasync-activator.php'; | |
| 309 | + if (!current_user_can('manage_options')) { | |
| 310 | + return; | |
| 311 | + } | |
| 312 | + | |
| 313 | + if (!class_exists('Metasync_Activator')) { | |
| 314 | + require_once plugin_dir_path(dirname(__FILE__)) . 'includes/class-metasync-activator.php'; | |
| 315 | + } | |
| 285 | 316 | Metasync_Activator::sync_plugin_file_headers(); |
| 286 | 317 | } |
| 287 | 318 | } |
| 288 | 319 | |
| @@ -310,9 +341,9 @@ | ||
| 310 | 341 | $status = $debug_manager->get_status(); |
| 311 | 342 | ?> |
| 312 | 343 | |
| 313 | 344 | <!-- Debug Mode Status Overview --> |
| 314 | - <div style="margin-bottom: 30px;"> | |
| 345 | + <div style="margin-bottom: 30px; padding-top: 20px;"> | |
| 315 | 346 | <h4 style="margin-top: 0; color: var(--dashboard-text-primary);">Current Status</h4> |
| 316 | 347 | <div style="background: rgba(255, 255, 255, 0.05); border: 1px solid var(--dashboard-border); padding: 20px; border-radius: 8px;"> |
| 317 | 348 | <div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 15px;"> |
| 318 | 349 | <!-- Status Badge --> |
| @@ -369,9 +400,9 @@ | ||
| 369 | 400 | <!-- Debug Mode Controls --> |
| 370 | 401 | <div style="margin-bottom: 30px;"> |
| 371 | 402 | <h4 style="margin-top: 0; color: var(--dashboard-text-primary);">Controls</h4> |
| 372 | 403 | |
| 373 | - <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')); ?>"> | |
| 374 | 405 | <input type="hidden" name="metasync_debug_mode_action_advanced" value="1" /> |
| 375 | 406 | <?php wp_nonce_field('metasync_debug_mode_action_advanced', 'metasync_debug_mode_nonce_advanced'); ?> |
| 376 | 407 | |
| 377 | 408 | <?php if (!$status['enabled']): ?> |
| @@ -467,9 +498,9 @@ | ||
| 467 | 498 | } |
| 468 | 499 | }); |
| 469 | 500 | |
| 470 | 501 | <?php if ($status['enabled'] && !$status['indefinite']): ?> |
| 471 | - var initialTimeRemaining = <?php echo $status['time_remaining']; ?>; | |
| 502 | + var initialTimeRemaining = <?php echo (int) $status['time_remaining']; ?>; | |
| 472 | 503 | var hasReloaded = false; |
| 473 | 504 | |
| 474 | 505 | function updateDebugTimeRemaining() { |
| 475 | 506 | if (initialTimeRemaining <= 0 || hasReloaded) { |
| @@ -476,12 +507,12 @@ | ||
| 476 | 507 | return; |
| 477 | 508 | } |
| 478 | 509 | |
| 479 | 510 | $.ajax({ |
| 480 | - url: '<?php echo rest_url('metasync/v1/debug-mode/status'); ?>', | |
| 511 | + url: '<?php echo esc_url(rest_url('metasync/v1/debug-mode/status')); ?>', | |
| 481 | 512 | method: 'GET', |
| 482 | 513 | beforeSend: function(xhr) { |
| 483 | - 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')); ?>'); | |
| 484 | 515 | }, |
| 485 | 516 | success: function(response) { |
| 486 | 517 | console.log('MetaSync Debug Mode Status:', response); |
| 487 | 518 | |
| @@ -523,15 +554,15 @@ | ||
| 523 | 554 | public function render_error_log_content() |
| 524 | 555 | { |
| 525 | 556 | ?> |
| 526 | 557 | <!-- Error Summary Section --> |
| 527 | - <div style="margin-bottom: 30px;"> | |
| 558 | + <div style="margin-bottom: 30px; padding-top: 20px;"> | |
| 528 | 559 | <h4 style="margin-top: 0; color: var(--dashboard-text-primary);">Error Summary</h4> |
| 529 | 560 | <p style="margin-bottom: 15px; color: var(--dashboard-text-secondary);">View categorized error statistics with counts and last occurrence times.</p> |
| 530 | 561 | |
| 531 | 562 | <?php |
| 532 | 563 | if (class_exists('Metasync_Error_Logger')) { |
| 533 | - $error_summary = Metasync_Error_Logger::get_error_summary(); | |
| 564 | + $error_summary = Metasync_Error_Logger::get_visible_error_summary(); | |
| 534 | 565 | |
| 535 | 566 | if (!empty($error_summary) && is_array($error_summary)) { |
| 536 | 567 | uasort($error_summary, function($a, $b) { |
| 537 | 568 | return strtotime($b['last_seen']) - strtotime($a['last_seen']); |
| @@ -551,9 +582,9 @@ | ||
| 551 | 582 | <tbody> |
| 552 | 583 | <?php foreach ($error_summary as $key => $error): ?> |
| 553 | 584 | <tr> |
| 554 | 585 | <td style="padding: 10px 12px; color: var(--dashboard-text-primary);"> |
| 555 | - <strong><?php echo esc_html($error['category']); ?></strong> | |
| 586 | + <strong><?php echo esc_html(Metasync_Error_Logger::get_display_label($error['category'])); ?></strong> | |
| 556 | 587 | </td> |
| 557 | 588 | <td style="padding: 10px 12px; text-align: center; color: var(--dashboard-text-secondary); font-family: monospace;"> |
| 558 | 589 | <code style="background: rgba(255, 255, 255, 0.1); padding: 2px 6px; border-radius: 3px;"><?php echo esc_html($error['code']); ?></code> |
| 559 | 590 | </td> |
| @@ -565,9 +596,9 @@ | ||
| 565 | 596 | <td style="padding: 10px 12px; color: var(--dashboard-text-secondary); font-size: 13px;"> |
| 566 | 597 | <?php |
| 567 | 598 | $last_seen = strtotime($error['last_seen']); |
| 568 | 599 | $time_diff = human_time_diff($last_seen, current_time('timestamp')); |
| 569 | - 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>'; | |
| 570 | 601 | ?> |
| 571 | 602 | </td> |
| 572 | 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']); ?>"> |
| 573 | 604 | <?php echo esc_html($error['message']); ?> |
| @@ -577,9 +608,9 @@ | ||
| 577 | 608 | </tbody> |
| 578 | 609 | </table> |
| 579 | 610 | </div> |
| 580 | 611 | |
| 581 | - <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;"> | |
| 582 | 613 | <input type="hidden" name="clear_error_summary" value="yes" /> |
| 583 | 614 | <?php wp_nonce_field('metasync_clear_error_summary_nonce', 'clear_error_summary_nonce'); ?> |
| 584 | 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;"> |
| 585 | 616 | <span class="dashicons dashicons-trash" style="margin-top:3px;font-size:15px;width:15px;height:15px;"></span> Clear Error Summary |
| @@ -611,9 +642,9 @@ | ||
| 611 | 642 | <div style="margin-bottom: 30px;"> |
| 612 | 643 | <h4 style="margin-top: 0; color: var(--dashboard-text-primary);">Clear Error Logs</h4> |
| 613 | 644 | <p style="margin-bottom: 15px; color: var(--dashboard-text-secondary);">Clear WordPress error logs to free up space and remove old entries.</p> |
| 614 | 645 | |
| 615 | - <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;"> | |
| 616 | 647 | <input type="hidden" name="clear_log" value="yes" /> |
| 617 | 648 | <?php wp_nonce_field('metasync_clear_log_nonce', 'clear_log_nonce'); ?> |
| 618 | 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)';"> |
| 619 | 650 | 🧹 Clear Error Logs |
| @@ -642,11 +673,41 @@ | ||
| 642 | 673 | </ul> |
| 643 | 674 | |
| 644 | 675 | <?php if (!$wp_debug): ?> |
| 645 | 676 | <p style="color: var(--dashboard-accent);">💡 To enable error logging, add these lines to your wp-config.php file:</p> |
| 646 | - <pre style="background: rgba(255, 255, 255, 0.05); border: 1px solid var(--dashboard-border); padding: 10px; border-radius: 4px; color: var(--dashboard-text-primary);">define('WP_DEBUG', true); | |
| 677 | + <div class="metasync-copy-wrap"><pre class="metasync-copy-snippet" style="background: rgba(255, 255, 255, 0.05); border: 1px solid var(--dashboard-border); padding: 10px; border-radius: 4px; color: var(--dashboard-text-primary);">define('WP_DEBUG', true); | |
| 647 | 678 | define('WP_DEBUG_LOG', true); |
| 648 | -define('WP_DEBUG_DISPLAY', false);</pre> | |
| 679 | +define('WP_DEBUG_DISPLAY', false);</pre><span class="metasync-copy-badge">Copy</span></div> | |
| 680 | + <?php /* click-to-copy for the wp-config snippet above */ ?> | |
| 681 | + <style> | |
| 682 | + .metasync-copy-wrap { position: relative; } | |
| 683 | + .metasync-copy-snippet { cursor: pointer; outline: 1px solid transparent; transition: outline-color .15s ease; } | |
| 684 | + .metasync-copy-wrap:hover .metasync-copy-snippet { outline-color: var(--dashboard-border, #374151); } | |
| 685 | + .metasync-copy-badge { position: absolute; top: 8px; right: 10px; font-size: 11px; font-weight: 600; padding: 2px 8px; border-radius: 4px; pointer-events: none; opacity: 0; transition: opacity .15s ease; background: var(--dashboard-border, #374151); color: var(--dashboard-text-primary, #fff); } | |
| 686 | + .metasync-copy-wrap:hover .metasync-copy-badge { opacity: .85; } | |
| 687 | + .metasync-copy-badge.metasync-copy-done { opacity: 1; background: var(--dashboard-gradient-primary, linear-gradient(135deg, #667eea 0%, #764ba2 100%)); color: #fff; } | |
| 688 | + </style> | |
| 689 | + <script> | |
| 690 | + (function(){ | |
| 691 | + if (window.__metasyncCopyInit) return; window.__metasyncCopyInit = true; | |
| 692 | + function fallback(text){ var ta=document.createElement('textarea'); ta.value=text; ta.style.position='fixed'; ta.style.opacity='0'; document.body.appendChild(ta); ta.focus(); ta.select(); try{document.execCommand('copy');}catch(e){} document.body.removeChild(ta); } | |
| 693 | + function attach(){ | |
| 694 | + document.querySelectorAll('.metasync-copy-snippet').forEach(function(pre){ | |
| 695 | + if (pre.dataset.copyBound) return; pre.dataset.copyBound='1'; | |
| 696 | + pre.setAttribute('title','Click to copy'); | |
| 697 | + pre.addEventListener('click', function(){ | |
| 698 | + var text = pre.textContent.trim(); | |
| 699 | + var wrap = pre.closest('.metasync-copy-wrap') || pre.parentNode; | |
| 700 | + var badge = wrap.querySelector('.metasync-copy-badge'); | |
| 701 | + var done = function(){ if(!badge) return; badge.textContent='Copied!'; badge.classList.add('metasync-copy-done'); clearTimeout(badge._t); badge._t=setTimeout(function(){ badge.textContent='Copy'; badge.classList.remove('metasync-copy-done'); },1500); }; | |
| 702 | + if (navigator.clipboard && navigator.clipboard.writeText){ navigator.clipboard.writeText(text).then(done).catch(function(){ fallback(text); done(); }); } | |
| 703 | + else { fallback(text); done(); } | |
| 704 | + }); | |
| 705 | + }); | |
| 706 | + } | |
| 707 | + if (document.readyState==='loading'){ document.addEventListener('DOMContentLoaded', attach); } else { attach(); } | |
| 708 | + })(); | |
| 709 | + </script> | |
| 649 | 710 | <?php endif; ?> |
| 650 | 711 | </form> |
| 651 | 712 | </div> |
| 652 | 713 | |
| @@ -699,9 +760,9 @@ | ||
| 699 | 760 | { |
| 700 | 761 | if (isset($_POST['metasync_debug_mode_action_advanced'])) { |
| 701 | 762 | if (!wp_verify_nonce($_POST['metasync_debug_mode_nonce_advanced'], 'metasync_debug_mode_action_advanced')) { |
| 702 | 763 | $redirect_url = admin_url('admin.php?page=' . $this->get_page_slug() . '&tab=advanced&debug_error=1'); |
| 703 | - wp_redirect($redirect_url); | |
| 764 | + wp_safe_redirect($redirect_url); | |
| 704 | 765 | exit; |
| 705 | 766 | } |
| 706 | 767 | |
| 707 | 768 | if (!current_user_can('manage_options')) { |
| @@ -709,9 +770,9 @@ | ||
| 709 | 770 | } |
| 710 | 771 | |
| 711 | 772 | if (!class_exists('Metasync_Debug_Mode_Manager')) { |
| 712 | 773 | $redirect_url = admin_url('admin.php?page=' . $this->get_page_slug() . '&tab=advanced&debug_error=1&msg=manager_not_available'); |
| 713 | - wp_redirect($redirect_url); | |
| 774 | + wp_safe_redirect($redirect_url); | |
| 714 | 775 | exit; |
| 715 | 776 | } |
| 716 | 777 | |
| 717 | 778 | $debug_manager = Metasync_Debug_Mode_Manager::get_instance(); |
| @@ -748,9 +809,9 @@ | ||
| 748 | 809 | $redirect_url = add_query_arg('debug_error', '1', $redirect_url); |
| 749 | 810 | break; |
| 750 | 811 | } |
| 751 | 812 | |
| 752 | - wp_redirect($redirect_url); | |
| 813 | + wp_safe_redirect($redirect_url); | |
| 753 | 814 | exit; |
| 754 | 815 | } |
| 755 | 816 | } |
| 756 | 817 | |
| @@ -758,29 +819,36 @@ | ||
| 758 | 819 | * Handle error log operations (clear). |
| 759 | 820 | */ |
| 760 | 821 | public function handle_error_log_operations() |
| 761 | 822 | { |
| 823 | + if ((isset($_POST['clear_log']) || isset($_POST['clear_error_summary'])) && !current_user_can('manage_options')) { | |
| 824 | + return; | |
| 825 | + } | |
| 826 | + | |
| 762 | 827 | if (isset($_POST['clear_log'])) { |
| 763 | 828 | if (wp_verify_nonce($_POST['clear_log_nonce'], 'metasync_clear_log_nonce')) { |
| 764 | - $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'); | |
| 765 | 831 | |
| 766 | - if (file_exists($log_file)) { | |
| 832 | + if (false !== $log_file && file_exists($log_file)) { | |
| 767 | 833 | file_put_contents($log_file, ''); |
| 768 | 834 | |
| 769 | - $backup_files = glob(WP_CONTENT_DIR . '/metasync_data/plugin_errors.log.old.*'); | |
| 770 | - if ($backup_files) { | |
| 771 | - foreach ($backup_files as $backup_file) { | |
| 772 | - @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 | + } | |
| 773 | 841 | } |
| 774 | 842 | } |
| 775 | 843 | } |
| 776 | 844 | |
| 777 | 845 | $redirect_url = admin_url('admin.php?page=' . $this->get_page_slug() . '&tab=advanced&log_cleared=1'); |
| 778 | - wp_redirect($redirect_url); | |
| 846 | + wp_safe_redirect($redirect_url); | |
| 779 | 847 | exit; |
| 780 | 848 | } else { |
| 781 | 849 | $redirect_url = admin_url('admin.php?page=' . $this->get_page_slug() . '&tab=advanced&clear_error=1'); |
| 782 | - wp_redirect($redirect_url); | |
| 850 | + wp_safe_redirect($redirect_url); | |
| 783 | 851 | exit; |
| 784 | 852 | } |
| 785 | 853 | } |
| 786 | 854 | |
| @@ -788,18 +856,18 @@ | ||
| 788 | 856 | if (wp_verify_nonce($_POST['clear_error_summary_nonce'], 'metasync_clear_error_summary_nonce')) { |
| 789 | 857 | if (class_exists('Metasync_Error_Logger')) { |
| 790 | 858 | Metasync_Error_Logger::clear_error_summary(); |
| 791 | 859 | $redirect_url = admin_url('admin.php?page=' . $this->get_page_slug() . '&tab=advanced&error_summary_cleared=1'); |
| 792 | - wp_redirect($redirect_url); | |
| 860 | + wp_safe_redirect($redirect_url); | |
| 793 | 861 | exit; |
| 794 | 862 | } else { |
| 795 | 863 | $redirect_url = admin_url('admin.php?page=' . $this->get_page_slug() . '&tab=advanced&error_summary_error=1'); |
| 796 | - wp_redirect($redirect_url); | |
| 864 | + wp_safe_redirect($redirect_url); | |
| 797 | 865 | exit; |
| 798 | 866 | } |
| 799 | 867 | } else { |
| 800 | 868 | $redirect_url = admin_url('admin.php?page=' . $this->get_page_slug() . '&tab=advanced&error_summary_error=1'); |
| 801 | - wp_redirect($redirect_url); | |
| 869 | + wp_safe_redirect($redirect_url); | |
| 802 | 870 | exit; |
| 803 | 871 | } |
| 804 | 872 | } |
| 805 | 873 | } |
| @@ -808,8 +876,12 @@ | ||
| 808 | 876 | * Handle clear all settings operations. |
| 809 | 877 | */ |
| 810 | 878 | public function handle_clear_all_settings() |
| 811 | 879 | { |
| 880 | + if (isset($_POST['clear_all_settings']) && !current_user_can('manage_options')) { | |
| 881 | + return; | |
| 882 | + } | |
| 883 | + | |
| 812 | 884 | if (isset($_POST['clear_all_settings'])) { |
| 813 | 885 | if (wp_verify_nonce($_POST['clear_all_settings_nonce'], 'metasync_clear_all_settings_nonce')) { |
| 814 | 886 | |
| 815 | 887 | $metasync_options_to_clear = [ |
| @@ -821,10 +893,27 @@ | ||
| 821 | 893 | 'metasync_wp_sa_connect_token', |
| 822 | 894 | 'wp_debug_enabled', |
| 823 | 895 | 'wp_debug_log_enabled', |
| 824 | 896 | 'wp_debug_display_enabled', |
| 897 | + // Media Optimization settings & cache | |
| 898 | + 'metasync_media_optimization', | |
| 899 | + 'metasync_batch_optimize_queue', | |
| 900 | + 'metasync_batch_optimize_progress', | |
| 901 | + 'metasync_batch_optimize_settings', | |
| 902 | + // Code Minification settings | |
| 903 | + 'metasync_code_minification', | |
| 825 | 904 | ]; |
| 826 | 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 | + | |
| 827 | 916 | $cleared_count = 0; |
| 828 | 917 | foreach ($metasync_options_to_clear as $option_name) { |
| 829 | 918 | if (get_option($option_name) !== false) { |
| 830 | 919 | delete_option($option_name); |
| @@ -839,11 +928,18 @@ | ||
| 839 | 928 | foreach ($transients_to_clear as $transient_name) { |
| 840 | 929 | delete_transient($transient_name); |
| 841 | 930 | } |
| 842 | 931 | |
| 843 | - $timestamp = wp_next_scheduled('metasync_heartbeat_cron_check'); | |
| 844 | - if ($timestamp) { | |
| 845 | - wp_unschedule_event($timestamp, 'metasync_heartbeat_cron_check'); | |
| 932 | + $cron_hooks_to_clear = [ | |
| 933 | + 'metasync_heartbeat_cron_check', | |
| 934 | + 'metasync_media_batch_optimize_cron', | |
| 935 | + ]; | |
| 936 | + | |
| 937 | + foreach ($cron_hooks_to_clear as $cron_hook) { | |
| 938 | + $timestamp = wp_next_scheduled($cron_hook); | |
| 939 | + if ($timestamp) { | |
| 940 | + wp_unschedule_event($timestamp, $cron_hook); | |
| 941 | + } | |
| 846 | 942 | } |
| 847 | 943 | |
| 848 | 944 | $new_plugin_auth_token = wp_generate_password(32, false, false); |
| 849 | 945 | |
| @@ -859,15 +955,41 @@ | ||
| 859 | 955 | 'options_cleared_count' => $cleared_count, |
| 860 | 956 | 'new_token_prefix' => substr($new_plugin_auth_token, 0, 8) . '...', |
| 861 | 957 | 'triggered_by' => 'settings_reset_action' |
| 862 | 958 | ), 'info'); |
| 863 | - | |
| 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 | + | |
| 864 | 986 | $redirect_url = admin_url('admin.php?page=' . $this->get_page_slug() . '&tab=advanced&settings_cleared=1'); |
| 865 | - wp_redirect($redirect_url); | |
| 987 | + wp_safe_redirect($redirect_url); | |
| 866 | 988 | exit; |
| 867 | 989 | } else { |
| 868 | 990 | $redirect_url = admin_url('admin.php?page=' . $this->get_page_slug() . '&tab=advanced&clear_settings_error=1'); |
| 869 | - wp_redirect($redirect_url); | |
| 991 | + wp_safe_redirect($redirect_url); | |
| 870 | 992 | exit; |
| 871 | 993 | } |
| 872 | 994 | } |
| 873 | 995 | } |
| @@ -882,9 +1004,9 @@ | ||
| 882 | 1004 | public function get_error_log_content() |
| 883 | 1005 | { |
| 884 | 1006 | $execution_time = $this->get_execution_setting('max_execution_time'); |
| 885 | 1007 | if (function_exists('set_time_limit')) { |
| 886 | - @set_time_limit($execution_time); | |
| 1008 | + @set_time_limit($execution_time); // phpcs:ignore Squiz.PHP.DiscouragedFunctions.Discouraged -- runtime PHP setting with no WordPress API | |
| 887 | 1009 | } |
| 888 | 1010 | |
| 889 | 1011 | $log_file = WP_CONTENT_DIR . '/debug.log'; |
| 890 | 1012 | |
| @@ -916,9 +1038,9 @@ | ||
| 916 | 1038 | public function get_log_tail($file_path, $lines = null) |
| 917 | 1039 | { |
| 918 | 1040 | $execution_time = $this->get_execution_setting('max_execution_time'); |
| 919 | 1041 | if (function_exists('set_time_limit')) { |
| 920 | - @set_time_limit($execution_time); | |
| 1042 | + @set_time_limit($execution_time); // phpcs:ignore Squiz.PHP.DiscouragedFunctions.Discouraged -- runtime PHP setting with no WordPress API | |
| 921 | 1043 | } |
| 922 | 1044 | |
| 923 | 1045 | if ($lines === null) { |
| 924 | 1046 | $lines = $this->get_execution_setting('log_batch_size'); |
| @@ -923,9 +1045,9 @@ | ||
| 923 | 1045 | if ($lines === null) { |
| 924 | 1046 | $lines = $this->get_execution_setting('log_batch_size'); |
| 925 | 1047 | } |
| 926 | 1048 | |
| 927 | - $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 | |
| 928 | 1050 | if (!$handle) { |
| 929 | 1051 | return false; |
| 930 | 1052 | } |
| 931 | 1053 | |
| @@ -954,9 +1076,9 @@ | ||
| 954 | 1076 | if (!empty($line) && $line_count < $lines) { |
| 955 | 1077 | array_unshift($result_lines, strrev($line)); |
| 956 | 1078 | } |
| 957 | 1079 | |
| 958 | - fclose($handle); | |
| 1080 | + fclose($handle); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fclose -- operates on a native stream handle | |
| 959 | 1081 | |
| 960 | 1082 | return implode("\n", $result_lines); |
| 961 | 1083 | } |
| 962 | 1084 | } |