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.php +5 -98 2.7.2 → 2.7.1 View file →
@@ -297,17 +297,8 @@
297 297 // `metasync_enable_seo_suite` filter.
298 298 require_once plugin_dir_path(dirname(__FILE__)) . 'includes/class-metasync-seo-suite.php';
299 299 new Metasync_Seo_Suite();
300 300
301 - // Classic-editor save path for the three fields that exist only as
302 - // Gutenberg sidebar (REST) meta otherwise: breadcrumb title, language
303 - // alternates, primary category. The Suite renders the first two and
304 - // emits the nonce; this handler persists them from the classic form.
305 - // It guards itself against block-editor and managed-page context, so
306 - // it is safe to register unconditionally.
307 - require_once plugin_dir_path(dirname(__FILE__)) . 'admin/class-metasync-classic-seo-fields.php';
308 - new Metasync_Classic_Seo_Fields();
309 -
310 301 // SEO Health CSV export: must run on admin_init (before output).
311 302 // Cheap $_GET check avoids loading the class on every admin page.
312 303 if (
313 304 isset($_GET['page'], $_GET['export'], $_GET['_wpnonce']) && // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- routing check, the handler verifies nonce and capability
@@ -352,8 +343,13 @@
352 343 if (class_exists('Metasync_Breadcrumbs_Schema')) {
353 344 new Metasync_Breadcrumbs_Schema($this->get_plugin_name(), $this->get_version());
354 345 }
355 346
347 + // Initialize Developer Panel (for endpoint switching)
348 + if (class_exists('Metasync_Dev_Panel')) {
349 + $dev_panel = new Metasync_Dev_Panel($this->get_plugin_name(), $this->get_version());
350 + }
351 +
356 352 // Initialize Site Health integration
357 353 if (class_exists('Metasync_Site_Health')) {
358 354 $site_health = new Metasync_Site_Health();
359 355 $site_health->register_tests();
@@ -572,20 +568,8 @@
572 568 // One-time upgrade: regenerate sitemap to remove any Beaver Builder template entries
573 569 if ( ! get_option( 'metasync_sitemap_bb_exclusion_applied' ) ) {
574 570 $this->loader->add_action('init', $this, 'maybe_regenerate_sitemap_after_upgrade');
575 571 }
576 -
577 - // One-time upgrade: delete the legacy Otto crawl-data option. Nothing
578 - // reads or writes it anymore (the webhook and SEO sync job stopped
579 - // persisting crawl data), and on sites where OTTO crawled many URLs
580 - // the row could grow to megabytes while being autoloaded on every
581 - // request before WordPress 6.6. The guard below runs on every request,
582 - // so the flag must be autoloaded (like the sitemap flag above): a
583 - // boolean true costs ~2 bytes inside the alloptions query WordPress
584 - // already always runs, keeping the steady-state cost a cache hit.
585 - if ( ! get_option( 'metasync_otto_crawldata_removed' ) ) {
586 - $this->loader->add_action('init', $this, 'maybe_delete_legacy_otto_crawl_data');
587 - }
588 572 }
589 573
590 574 /**
591 575 * One-time upgrade routine: regenerate the XML sitemap so that Beaver Builder
@@ -615,40 +599,8 @@
615 599 // so that enabling sitemaps later will still clean up BB templates.
616 600 }
617 601
618 602 /**
619 - * One-time upgrade routine: delete the legacy Otto crawl-data option.
620 - *
621 - * The option stored every URL Otto ever sent and grew without bound;
622 - * nothing writes it anymore and nothing in production reads it (per-URL
623 - * state lives in Metasync_Otto_Job_Status, delivery receipts in
624 - * Metasync_Otto_Webhook_Audit, both bounded). This drops the leftover
625 - * row — which on long-running sites can be megabytes of autoloaded data.
626 - *
627 - * Runs once on 'init' and sets a flag so it never runs again. The flag
628 - * is autoloaded deliberately: the registration guard reads it on every
629 - * request, and an autoloaded boolean is a free cache hit inside the
630 - * alloptions query WordPress always performs — a non-autoloaded flag
631 - * would cost a dedicated SELECT per request forever, the exact waste
632 - * this routine exists to remove. delete_option() is called directly
633 - * without reading the option first: loading a multi-megabyte value into
634 - * memory just to delete it would be the one way this cleanup could hurt
635 - * a site, and the SQL DELETE never needs the value.
636 - */
637 - public function maybe_delete_legacy_otto_crawl_data() {
638 - $done_key = 'metasync_otto_crawldata_removed';
639 - if ( get_option( $done_key ) ) {
640 - return;
641 - }
642 -
643 - // No "feature in use" conditional here, unlike the sitemap routine:
644 - // the row is dead weight whether or not Otto is configured, and
645 - // delete_option() on an absent row is a cheap no-op.
646 - delete_option( 'metasync_otto_crawldata' );
647 - update_option( $done_key, true );
648 - }
649 -
650 - /**
651 603 * Initialize endpoint URL filtering for staging mode
652 604 * Intercepts HTTP requests and replaces production URLs with staging URLs
653 605 */
654 606 private function init_endpoint_filtering() {
@@ -951,52 +903,8 @@
951 903 return is_string($value) && strncmp($value, self::API_KEY_ENC_PREFIX, strlen(self::API_KEY_ENC_PREFIX)) === 0;
952 904 }
953 905
954 906 /**
955 - * Whether a value is a strictly valid UUID (versions 1-8).
956 - *
957 - * The single shared validator for every write path that persists
958 - * `general.otto_pixel_uuid` (SSO push callback, pull-based connect,
959 - * heartbeat writes, settings sanitizer). The OTTO Pixel UUID must never
960 - * hold arbitrary text — usernames such as `raza.imran` landing in it
961 - * break OTTO SSR authentication — so every write path funnels through
962 - * this check instead of a scattered one-off regex.
963 - *
964 - * Deliberately stricter than wp_is_uuid(), which only checks the
965 - * 8-4-4-4-12 hex shape and would accept placeholder values such as
966 - * `11111111-2222-3333-4444-555555555555`. The version nibble (first hex
967 - * of the third group) must be 1-8 — RFC 4122 defined 1-5 and RFC 9562
968 - * added 6/7/8, which modern generators increasingly emit — and the
969 - * variant nibble (first hex of the fourth group) must be 8/9/a/b. That
970 - * keeps behaviour identical with and without the WP helper loaded (unit
971 - * tests run without it).
972 - *
973 - * An empty string is NOT valid: clearing the field is a separate concern
974 - * owned by the disconnect flow (unset + write_options_without_stored_merge),
975 - * so '' must not masquerade as a usable UUID here.
976 - *
977 - * @param mixed $value
978 - * @return bool True only for a canonical 8-4-4-4-12 hex UUID of version 1-8
979 - * with an RFC-4122 variant (8/9/a/b) in the fourth group.
980 - */
981 - public static function is_valid_uuid($value)
982 - {
983 - if (!is_string($value)) {
984 - return false;
985 - }
986 -
987 - $value = trim($value);
988 - if ($value === '') {
989 - return false;
990 - }
991 -
992 - return (bool) preg_match(
993 - '/^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i',
994 - $value
995 - );
996 - }
997 -
998 - /**
999 907 * Encrypt a plaintext Search Atlas API key for storage at rest.
1000 908 *
1001 909 * Uses AES-256-GCM (authenticated) with a random 12-byte IV. The IV, the
1002 910 * 16-byte GCM tag and the ciphertext are concatenated and base64-encoded
@@ -1586,9 +1494,8 @@
1586 1494 * @param string $text Plain-English help text (escaped internally).
1587 1495 */
1588 1496 public static function render_tooltip_icon($tooltip_id, $text)
1589 1497 {
1590 - // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- get_tooltip_icon_html() escapes every interpolated value internally (esc_attr / esc_html)
1591 1498 echo self::get_tooltip_icon_html($tooltip_id, $text);
1592 1499 }
1593 1500
1594 1501 /**