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/metasync-helpers.php +40 -6 2.7.0 → 2.7.1 View file →
@@ -63,9 +63,9 @@
63 63 *
64 64 * @return bool True when the current request is a WP core scrape self-check.
65 65 */
66 66 function metasync_is_scrape_request(){
67 - return isset($_GET['wp_scrape_key']) || isset($_GET['wp_scrape_nonce']);
67 + return isset($_GET['wp_scrape_key']) || isset($_GET['wp_scrape_nonce']); // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only front-end flag to skip buffering
68 68 }
69 69 }
70 70
71 71 if (!function_exists('metasync_get_custom_page_exclusion_meta_query')) {
@@ -147,9 +147,10 @@
147 147 if (!isset($wpdb) || !is_object($wpdb) || empty($wpdb->postmeta) || empty($wpdb->posts)) {
148 148 return '';
149 149 }
150 150
151 - $sql = " AND NOT EXISTS (\n"
151 + return $wpdb->prepare(
152 + " AND NOT EXISTS (\n"
152 153 . "\tSELECT 1 FROM {$wpdb->postmeta} AS _ms_ex_html\n"
153 154 . "\tWHERE _ms_ex_html.post_id = {$wpdb->posts}.ID\n"
154 155 . "\t\tAND _ms_ex_html.meta_key = %s\n"
155 156 . "\t\tAND _ms_ex_html.meta_value = %s\n"
@@ -164,12 +165,9 @@
164 165 . "\tSELECT 1 FROM {$wpdb->postmeta} AS _ms_ex_api\n"
165 166 . "\tWHERE _ms_ex_api.post_id = {$wpdb->posts}.ID\n"
166 167 . "\t\tAND _ms_ex_api.meta_key = %s\n"
167 168 . "\t\tAND _ms_ex_api.meta_value NOT IN ('', '0')\n"
168 - . ")";
169 -
170 - return $wpdb->prepare(
171 - $sql,
169 + . ")",
172 170 '_metasync_is_custom_html_page',
173 171 '1',
174 172 '_metasync_lps_import',
175 173 '_metasync_created_via_api'
@@ -490,5 +488,41 @@
490 488 }
491 489
492 490 return $result;
493 491 }
492 +}
493 +
494 +/**
495 + * Is headless mode active right now?
496 + *
497 + * Single skew-proof entry point for every caller that needs the headless flag.
498 + *
499 + * Metasync_Headless_Config is reached ONLY through the committed Composer
500 + * classmap — nothing require_once's it, and vendor/composer/autoload_psr4.php
501 + * is empty, so there is no fallback lookup path. A partially updated install
502 + * (an interrupted upgrade, a half-finished file sync, or stale opcache bytecode
503 + * for a single file) can therefore leave a newer caller beside a missing or
504 + * older copy of the class, and an unguarded static call fatals. Several callers
505 + * run on wp/wp_head, where that fatal is a white screen on every page view
506 + * rather than a degraded feature.
507 + *
508 + * This file IS explicitly require_once'd by metasync.php, so it cannot itself
509 + * be the unresolvable one — which is why the guard lives here rather than in a
510 + * class that would have the same problem it is trying to solve.
511 + *
512 + * Treating an unresolvable class as "not headless" is the safe default: the
513 + * site keeps rendering exactly as it did before headless mode existed.
514 + *
515 + * @return bool True only when the class resolves AND reports headless active.
516 + */
517 +function metasync_headless_is_active()
518 +{
519 + // class_exists() is redundant to static analysis — the class ships in this
520 + // same plugin, so PHPStan proves the call always resolves. It is kept for
521 + // the upgrade window described above, which exists only at runtime.
522 + // @phpstan-ignore-next-line function.alreadyNarrowedType
523 + if (!class_exists('Metasync_Headless_Config')) {
524 + return false;
525 + }
526 +
527 + return (bool) Metasync_Headless_Config::is_active();
494 528 }