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 | includes/class-metasync-redirections-admin.php +18 -15 2.7.0 → 2.7.1 View file →
@@ -65,9 +65,9 @@
65 65 $this->check_database_structure();
66 66
67 67 $this->ensure_404_monitor_table();
68 68
69 - $current_tab = isset($_GET['tab']) ? sanitize_text_field($_GET['tab']) : 'redirections';
69 + $current_tab = isset($_GET['tab']) ? sanitize_text_field(wp_unslash($_GET['tab'])) : 'redirections'; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only tab selection
70 70
71 71 $this->add_tabbed_interface_assets();
72 72 $this->admin->render_layout_open('Redirections', 'redirections', 'Manage URL redirects and monitor 404 errors on your site.');
73 73 $this->render_tab_navigation($current_tab);
@@ -101,9 +101,9 @@
101 101
102 102 private function safe_redirect($url)
103 103 {
104 104 if (!headers_sent()) {
105 - wp_redirect($url);
105 + wp_safe_redirect($url);
106 106 exit;
107 107 } else {
108 108 echo '<script type="text/javascript">window.location.href = "' . esc_url($url) . '";</script>';
109 109 echo '<noscript><meta http-equiv="refresh" content="0;url=' . esc_url($url) . '"></noscript>';
@@ -135,15 +135,18 @@
135 135 if (!Metasync::current_user_has_plugin_access()) {
136 136 wp_die('Insufficient permissions.');
137 137 }
138 138
139 - $source_urls = isset($_POST['source_url']) ? array_map('sanitize_text_field', $_POST['source_url']) : [];
140 - $search_types = isset($_POST['search_type']) ? array_map('sanitize_text_field', $_POST['search_type']) : [];
141 - $destination_url = isset($_POST['destination_url']) ? sanitize_text_field($_POST['destination_url']) : '';
139 + // Unslash before sanitizing: source URLs with apostrophes/backslashes
140 + // must be stored in their literal form so the front-end matcher (which
141 + // compares against the unslashed request URI) can hit them.
142 + $source_urls = isset($_POST['source_url']) ? array_map('sanitize_text_field', wp_unslash($_POST['source_url'])) : [];
143 + $search_types = isset($_POST['search_type']) ? array_map('sanitize_text_field', wp_unslash($_POST['search_type'])) : [];
144 + $destination_url = isset($_POST['destination_url']) ? sanitize_text_field(wp_unslash($_POST['destination_url'])) : '';
142 145 $redirect_type = isset($_POST['redirect_type']) ? intval($_POST['redirect_type']) : 301;
143 - $status = isset($_POST['status']) ? sanitize_text_field($_POST['status']) : 'active';
146 + $status = isset($_POST['status']) ? sanitize_text_field(wp_unslash($_POST['status'])) : 'active';
144 147 $regex_pattern = isset($_POST['regex_pattern']) ? wp_unslash(trim($_POST['regex_pattern'])) : '';
145 - $description = isset($_POST['description']) ? sanitize_text_field($_POST['description']) : '';
148 + $description = isset($_POST['description']) ? sanitize_text_field(wp_unslash($_POST['description'])) : '';
146 149 $redirect_id = isset($_POST['redirect_id']) ? intval($_POST['redirect_id']) : 0;
147 150
148 151 $validation_errors = [];
149 152
@@ -323,9 +326,9 @@
323 326 $message = 'Redirection added successfully.';
324 327 }
325 328
326 329 } catch (Exception $e) {
327 - error_log('MetaSync error: ' . $e->getMessage());
330 + error_log('MetaSync error: ' . $e->getMessage()); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- genuine failure path, bounded, no secrets
328 331 set_transient('metasync_redirection_error_' . $uid, 'An error occurred while saving the redirection. Please try again.', 45);
329 332 $this->safe_redirect(admin_url('admin.php?page=' . Metasync_Admin::$page_slug . '-redirections'));
330 333 }
331 334
@@ -548,9 +551,9 @@
548 551
549 552 private function render_redirections_tab($current_tab = null)
550 553 {
551 554 if ($current_tab === null) {
552 - $current_tab = isset($_GET['tab']) ? sanitize_text_field($_GET['tab']) : 'redirections';
555 + $current_tab = isset($_GET['tab']) ? sanitize_text_field(wp_unslash($_GET['tab'])) : 'redirections'; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only tab selection
553 556 }
554 557 $active_class = $current_tab === 'redirections' ? 'active' : '';
555 558
556 559 ?>
@@ -565,9 +568,9 @@
565 568
566 569 private function render_404_monitor_tab($current_tab = null)
567 570 {
568 571 if ($current_tab === null) {
569 - $current_tab = isset($_GET['tab']) ? sanitize_text_field($_GET['tab']) : 'redirections';
572 + $current_tab = isset($_GET['tab']) ? sanitize_text_field(wp_unslash($_GET['tab'])) : 'redirections'; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only tab selection
570 573 }
571 574 $active_class = $current_tab === '404-monitor' ? 'active' : '';
572 575
573 576 ?>
@@ -582,12 +585,12 @@
582 585
583 586 $ErrorMonitor->create_admin_plugin_interface();
584 587
585 588 } catch (Exception $e) {
586 - error_log('MetaSync 404 Monitor Error: ' . $e->getMessage());
589 + error_log('MetaSync 404 Monitor Error: ' . $e->getMessage()); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- genuine failure path, bounded, no secrets
587 590 echo '<div class="notice notice-error"><p>An error occurred while loading the 404 monitor. Please check the server logs for details.</p></div>';
588 591 } catch (Error $e) {
589 - error_log('MetaSync 404 Monitor Fatal Error: ' . $e->getMessage());
592 + error_log('MetaSync 404 Monitor Fatal Error: ' . $e->getMessage()); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- genuine failure path, bounded, no secrets
590 593 echo '<div class="notice notice-error"><p>A fatal error occurred while loading the 404 monitor. Please check the server logs for details.</p></div>';
591 594 }
592 595 ?>
593 596 </div>
@@ -600,9 +603,9 @@
600 603 require_once plugin_dir_path(dirname(__FILE__)) . '404-monitor/class-metasync-404-monitor-database.php';
601 604
602 605 $table_name = $wpdb->prefix . Metasync_Error_Monitor_Database::$table_name;
603 606
604 - if ($wpdb->get_var($wpdb->prepare("SHOW TABLES LIKE %s", $table_name)) != $table_name) {
607 + if ($wpdb->get_var($wpdb->prepare("SHOW TABLES LIKE %s", $table_name)) != $table_name) { // phpcs:ignore WordPress.DB.DirectDatabaseQuery -- admin repair action — re-runs the migration check on demand from the UI
605 608 require_once plugin_dir_path(dirname(__FILE__)) . 'database/class-db-migrations.php';
606 609 MetaSync_DBMigration::run_migrations();
607 610 }
608 611 }
@@ -611,13 +614,13 @@
611 614 {
612 615 global $wpdb;
613 616 $table_name = $wpdb->prefix . 'metasync_redirections';
614 617
615 - if ($wpdb->get_var($wpdb->prepare("SHOW TABLES LIKE %s", $table_name)) != $table_name) {
618 + if ($wpdb->get_var($wpdb->prepare("SHOW TABLES LIKE %s", $table_name)) != $table_name) { // phpcs:ignore WordPress.DB.DirectDatabaseQuery -- admin repair action — re-runs the migration check on demand from the UI
616 619 return;
617 620 }
618 621
619 - $columns = $wpdb->get_col("DESCRIBE {$table_name}");
622 + $columns = $wpdb->get_col("DESCRIBE {$wpdb->prefix}metasync_redirections"); // phpcs:ignore WordPress.DB.DirectDatabaseQuery -- admin repair action — re-runs the migration check on demand from the UI
620 623 $required_columns = ['pattern_type', 'regex_pattern', 'description', 'created_at', 'updated_at', 'last_accessed_at'];
621 624
622 625 $missing_columns = array_diff($required_columns, $columns);
623 626