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-post-meta-setting.php +26 -9 2.6.25 → 2.7.1 View file →
@@ -57,9 +57,9 @@
57 57 $post_types = array_diff($post_types, ['attachment']);
58 58
59 59 // Resolve the current post ID in admin_init context: $_GET['post'] on the
60 60 // edit screen, $_POST['post_ID'] on save. Mirrors the sidebar enqueue.
61 - $post_id = isset($_GET['post']) ? intval($_GET['post']) : (isset($_POST['post_ID']) ? intval($_POST['post_ID']) : 0);
61 + $post_id = isset($_GET['post']) ? intval($_GET['post']) : (isset($_POST['post_ID']) ? intval($_POST['post_ID']) : 0); // phpcs:ignore WordPress.Security.NonceVerification.Missing, WordPress.Security.NonceVerification.Recommended -- read-only post ID to pick meta boxes
62 62
63 63 // LPS / custom-HTML pages carry their own baked SEO served before wp_head,
64 64 // so the editable SEO fields here do nothing and mislead editors.
65 65 // otto_pixel.php (where metasync_is_custom_or_lps_page lives) is only
@@ -297,9 +297,9 @@
297 297 if (defined('REST_REQUEST') && REST_REQUEST && !empty(get_post_meta($post_id, '_metasync_robots_advanced', true))) {
298 298 return;
299 299 }
300 300
301 - $post_data = metasync_sanitize_input_array($_POST);
301 + $post_data = metasync_sanitize_input_array($_POST); // phpcs:ignore WordPress.Security.NonceVerification.Missing -- wp_verify_nonce() runs before any meta write
302 302 // Check for new field name first, then old for backward compatibility
303 303 $field_name = isset($post_data['common_robots_meta']) ? 'common_robots_meta' : 'common_robots_mata';
304 304
305 305 // Unchecked checkboxes are omitted from the request. Require the nonce,
@@ -331,9 +331,9 @@
331 331 if (defined('REST_REQUEST') && REST_REQUEST && !empty(get_post_meta($post_id, '_metasync_robots_advanced', true))) {
332 332 return;
333 333 }
334 334
335 - $post_data = metasync_sanitize_input_array($_POST);
335 + $post_data = metasync_sanitize_input_array($_POST); // phpcs:ignore WordPress.Security.NonceVerification.Missing -- wp_verify_nonce() runs before any meta write
336 336 // Check for new field name first, then old for backward compatibility
337 337 $field_name = isset($post_data['advanced_robots_meta']) ? 'advanced_robots_meta' : 'advanced_robots_mata';
338 338
339 339 if (!isset($post_data['metasync_advance_robots_nonce'], $post_data[$field_name]) || !wp_verify_nonce($post_data['metasync_advance_robots_nonce'], 'metasync_advance_robots_nonce'))
@@ -353,9 +353,9 @@
353 353 {
354 354 if (!current_user_can('edit_post', $post_id))
355 355 return;
356 356
357 - $post_data = metasync_sanitize_input_array($_POST);
357 + $post_data = metasync_sanitize_input_array($_POST); // phpcs:ignore WordPress.Security.NonceVerification.Missing -- wp_verify_nonce() runs before any meta write
358 358 // Check for new field name first, then old for backward compatibility
359 359 $field_name = isset($post_data['post_redirect_meta']) ? 'post_redirect_meta' : 'post_redirect_mata';
360 360
361 361 if (!isset($post_data['metasync_post_redirection_nonce'], $post_data[$field_name]) || !wp_verify_nonce($post_data['metasync_post_redirection_nonce'], 'metasync_post_redirection_nonce'))
@@ -462,8 +462,21 @@
462 462 // keep the previously stored rule and skip the write. The guard above
463 463 // already returned when a non-410/451 type had an empty destination,
464 464 // so $dest is known non-empty here.
465 465 if (!$is_gone) {
466 + // Destination guard — same checks as the admin form and MCP tools.
467 + // Backslashes and protocol-relative hosts bypass host validation in
468 + // browsers while looking internal to wp_validate_redirect. On a
469 + // bad destination we keep the previously stored rule and skip the
470 + // write, same skip-write semantics as the loop guard below.
471 + if (!class_exists('Metasync_Redirection_Validator')) {
472 + require_once dirname(__FILE__, 2) . '/redirections/class-metasync-redirection-validator.php';
473 + }
474 + if (!Metasync_Redirection_Validator::is_safe_destination_syntax($dest)
475 + || (!get_option('metasync_allow_external_redirects', 0) && wp_validate_redirect($dest, '') !== $dest)) {
476 + return;
477 + }
478 +
466 479 if (!class_exists('Metasync_Redirection')) {
467 480 require_once dirname(__FILE__, 2) . '/redirections/class-metasync-redirection.php';
468 481 }
469 482 $db_ref = $db;
@@ -498,9 +511,9 @@
498 511 {
499 512 if (!current_user_can('edit_post', $post_id))
500 513 return;
501 514
502 - $post_data = metasync_sanitize_input_array($_POST);
515 + $post_data = metasync_sanitize_input_array($_POST); // phpcs:ignore WordPress.Security.NonceVerification.Missing -- wp_verify_nonce() runs before any meta write
503 516 // Check for new field name first, then old for backward compatibility
504 517 $field_name = isset($post_data['post_canonical_url_meta']) ? 'post_canonical_url_meta' : 'post_canonical_url_mata';
505 518
506 519 if (!isset($post_data['metasync_post_canonical_nonce'], $post_data[$field_name]) || !wp_verify_nonce($post_data['metasync_post_canonical_nonce'], 'metasync_post_canonical_nonce'))
@@ -661,12 +674,14 @@
661 674
662 675 wp_nonce_field('metasync_seo_meta_nonce', 'metasync_seo_meta_nonce');
663 676 ?>
664 677 <p style="color: #666; margin-bottom: 12px;">
678 + <?php /* translators: %s: OTTO name (whitelabel). */ ?>
665 679 <?php printf(esc_html__('Set the SEO Title and Meta Description for this post. Leave the field blank to use %s suggestion.', 'metasync'), esc_html(Metasync::get_whitelabel_otto_name())); ?>
666 680 </p>
667 681 <?php if ($title_is_imported) : ?>
668 682 <p style="color: #666; margin-bottom: 12px;">
683 + <?php /* translators: %s: OTTO name (whitelabel). */ ?>
669 684 <?php printf(esc_html__('The greyed-out value below was imported from another SEO plugin. It is used only until %s has a suggestion for this page.', 'metasync'), esc_html(Metasync::get_whitelabel_otto_name())); ?>
670 685 </p>
671 686 <?php endif; ?>
672 687 <table class="form-table" style="margin: 0;">
@@ -706,11 +721,13 @@
706 721 return;
707 722 }
708 723
709 724 if (isset($_POST['metasync_seo_title'])) {
710 - $seo_title = sanitize_text_field($_POST['metasync_seo_title']);
725 + $seo_title = sanitize_text_field(wp_unslash($_POST['metasync_seo_title']));
711 726 if (!empty($seo_title)) {
712 - update_post_meta($post_id, '_metasync_seo_title', $seo_title);
727 + // update_post_meta() unslashes again, so re-slash to keep
728 + // literal backslashes and quotes in the stored value.
729 + update_post_meta($post_id, '_metasync_seo_title', wp_slash($seo_title));
713 730 } else {
714 731 delete_post_meta($post_id, '_metasync_seo_title');
715 732 }
716 733 }
@@ -715,11 +732,11 @@
715 732 }
716 733 }
717 734
718 735 if (isset($_POST['metasync_seo_desc'])) {
719 - $seo_desc = sanitize_textarea_field($_POST['metasync_seo_desc']);
736 + $seo_desc = sanitize_textarea_field(wp_unslash($_POST['metasync_seo_desc']));
720 737 if (!empty($seo_desc)) {
721 - update_post_meta($post_id, '_metasync_seo_desc', $seo_desc);
738 + update_post_meta($post_id, '_metasync_seo_desc', wp_slash($seo_desc));
722 739 } else {
723 740 delete_post_meta($post_id, '_metasync_seo_desc');
724 741 }
725 742 }