42 "summary": "yoast_head_json is Yoast's RENDERED output for the record, not the values the author typed. Every key is populated for every post whether or not anyone edited its SEO: `title` falls back to the site title template, `og_description` falls back to the excerpt/content, `og_title` mirrors the title. [VERIFIED LIVE 2026-08-16: every sampled post returned a fully populated yoast_head_json while every one had EMPTY _yoast_wpseo_title and _yoast_wpseo_metadesc, i.e. zero genuine per-post overrides.] Importing it wholesale into Wix Item SEO Tags converts inherited/templated values into hard per-item overrides on every record - the exact anti-pattern the Wix SEO docs warn about. Pair it with the post-seo-override-signal entity and import per-item tags only where the source proves an override."
43 },
44 {
45 "code": "head-json-key-set-varies-by-record",
46 "severity": "warning",
47 "summary": "Keys are present only when Yoast emits them, so absence is normal and is not profile drift. [VERIFIED LIVE 2026-08-16: across sampled posts the constant keys were title, robots, og_locale, og_type, og_title, og_description, og_url, og_site_name, article_published_time, author, twitter_card, twitter_misc, schema; on pages og_description and twitter_misc appeared only on some records; on wc/v3 products og_image and article_modified_time appeared on most and twitter_misc on a minority.] Notably ABSENT on a noindex site with no meta descriptions: `canonical` and `description` - `description` because no post has a meta description, and `canonical` because the whole site is noindex (blog_public = 0), which makes Yoast drop the canonical presenter. On a production source both normally appear. [NEEDS-VERIFICATION on an indexed production site: the exact shape of `canonical` and `description`.]"
48 },
49 {
50 "code": "robots-noindex-is-a-source-artefact",
51 "severity": "blocker",
52 "summary": "[VERIFIED LIVE 2026-08-16] on a WordPress site that discourages search engines every record reports robots {index: noindex, follow: follow, ...}. Carrying a robots meta tag across without checking would de-index the new Wix site. Indexability is a launch decision (see seo/site-seo-tags pitfall site-noindex-is-writable-here), never a migrated field."
53 },
54 {
55 "code": "schema-graph-is-source-shaped",
56 "severity": "warning",
57 "summary": "yoast_head_json.schema is a full JSON-LD @graph whose @id values are absolute SOURCE URLs (https://<source-host>/... plus #article, #primaryimage, #/schema/person/<hash> fragments) and whose image URLs point at the source CDN. Copying it into a Wix script tag republishes structured data that references the old domain. Either drop it (Wix generates its own structured data) or rewrite every @id and URL through the URL/media crosswalks - never pass it through verbatim."
76 "summary": "Yoast registers exactly three meta keys into the REST `meta` object - _yoast_wpseo_title, _yoast_wpseo_metadesc, _yoast_wpseo_focuskw - and they are visible only to an authenticated caller. [VERIFIED LIVE 2026-08-16 on a /wp/v2/posts record: the authenticated response carried those three keys and the unauthenticated response carried none of them, with all other meta keys identical.] This entity's propertyPath names the title key; the other two travel with it and must be read from the same `meta` object. An unauthenticated run therefore cannot tell an override from a default and must fall back to post-seo-meta alone, recorded as reduced fidelity rather than as absent data."
81 "summary": "[VERIFIED LIVE 2026-08-16] the three keys appeared on every sampled /wp/v2/posts record but on NONE of the sampled /wp/v2/pages records and none of /wp/v2/product (authenticated in every case). So the override signal exists for blog posts only; for pages, products and CPTs there is no REST-visible way to distinguish a genuine Yoast override from Yoast's computed default. [NEEDS-VERIFICATION: whether this is a Yoast registration scope per post type or a host/config effect.]"
86 "summary": "The per-post canonical override (_yoast_wpseo_canonical) and the Open Graph / Twitter overrides (_yoast_wpseo_opengraph-title, -description, -image, _yoast_wpseo_twitter-title, ...) are NOT among the registered keys and never appear in `meta`. [VERIFIED LIVE 2026-08-16: only the three keys above were present.] Their VALUES are still readable, because Yoast folds them into yoast_head_json - but there is no REST-visible way to tell an authored canonical from Yoast's computed one. Migrating a computed canonical would point the new Wix page at the old domain, so a canonical is only safe to carry after it is rewritten through the URL ledger or dropped in favour of Wix's own."
105 "summary": "[VERIFIED LIVE 2026-08-16] yoast_head_json rides on /wc/v3/products (present on every sampled product), but /wc/v3/products itself returns 401 woocommerce_rest_cannot_view unauthenticated, so the whole entity is unreadable without the Application Password. The same product's SEO is ALSO reachable unauthenticated on /wp/v2/product, which can be public and carries yoast_head_json too - a useful fallback for an unauthenticated survey, though it exposes no Woo commerce fields."
106 },
107 {
108 "code": "no-yoast-keys-in-woo-meta-data",
109 "severity": "info",
110 "summary": "[VERIFIED LIVE 2026-08-16] no _yoast_* key appeared in the meta_data array of any sampled product, and the three registered keys were absent from /wp/v2/product meta. The raw override meta can still exist in postmeta when REST shows none (read outside ordinary REST), and a rendered yoast_head_json.title can be present on every product while no raw title override exists. Read it per field through lib/yoast-product-seo-evidence.js: REST meta when it carries the key, else a wix-wp-plugin-v2 key-scoped postmeta read of exactly the three keys. When neither is available the evidence is unknown and product SEO is held for an owner decision."
115 "summary": "Catalog V3 products carry their own `seoData` (SeoSchema: tags[] plus settings.preventAutoRedirect) on create/update, so product SEO rides the product import. That is the ONLY product write path; never route Stores products through the generic Item SEO bulk writer (2026-08-27: per-entry success, nothing persisted), and write only proven per-field overrides."
120 "summary": "Product yoast_head_json.title/description are rendered template output unless the raw override meta proves otherwise, field by field. A nonblank raw title authorizes only the title and a nonblank raw description only the description; the value then comes from the matching resolved yoast_head_json field (the raw value may hold %%variables%%). og_description, og_title and excerpt text are never a fallback. Unknown evidence is held for the owner (acquire evidence, omit, or materialize); no default is chosen. Canonical, robots, schema, social tags and focus keyphrases are not written."
138 "summary": "[VERIFIED LIVE 2026-08-16] taxonomy terms carry yoast_head_json too - present on every sampled /wp/v2/categories and /wc/v3/products/categories record - so archive-page SEO is real, readable source data. But Wix Item SEO Tags documents item types by example only (STATIC_PAGE, BLOG_POST, STORES_PRODUCT, WIX_DATA_PAGE_ITEM-{pageId}) and says the real list is per site, discoverable from the UNSUPPORTED_ITEM_TYPE error message. No item type for a blog category, blog tag or store category has been confirmed, and neither blog/category nor stores/category exposes a seoData field. candidateTargetRefs is deliberately empty rather than pointing at a target that may reject the write: probe the supported item types at setup and resolve this at the mapping review."
139 },
140 {
141 "code": "wp-users-also-carry-it",
142 "severity": "info",
143 "summary": "[VERIFIED LIVE 2026-08-16] /wp/v2/users records carry yoast_head_json as well (author-archive SEO, on every sampled user). Author archives have no Wix counterpart at all, so this is noted for completeness and is not proposed for migration."
144 }
145 ]
146 }
147 ],
148 "quirks": [
149 "Plugin file id is `wordpress-seo/wp-seo` - the main-file basename differs from the directory and the /wp/v2/plugins id carries no .php suffix [VERIFIED LIVE 2026-08-16 active, version 28.2, textdomain wordpress-seo]. Never construct dir/dir.php.",
150 "Storage model: BOTH resolved-output-on-the-record and registered meta, and they answer different questions. The values are read as `yoast_head_json` injected into core and WooCommerce REST records (channel core-embedded); whether a value was actually authored is read from three registered meta keys (channel core-meta). Unregistered Yoast meta - the canonical and Open Graph/Twitter overrides - is invisible to REST as raw meta but is folded into yoast_head_json, so nothing is lost, only the provenance. [VERIFIED LIVE 2026-08-16.]",
151 "core-embedded VERIFICATION - this profile is the first user of the channel and it is now confirmed against a live site. [VERIFIED LIVE 2026-08-16] yoast_head_json is a top-level key on every sampled record of: /wp/v2/posts, /wp/v2/pages, /wp/v2/product, /wp/v2/podcast, /wp/v2/tribe_events, /wp/v2/categories, /wp/v2/users, /wc/v3/products, /wc/v3/products/categories. It is present with and without authentication and in context=edit, identically. It is ABSENT on /wp/v2/media - attachments get no Yoast head. So the channel's probe (declared key present in a sampled record) fires from an ordinary unauthenticated sample and needs no special context.",
152 "`yoast/v1` is DELIBERATELY NOT declared in detect.restNamespaces, even though the namespace is real and public. Two reasons. (1) It buys nothing: an authenticated run already matches pluginFileIds against /wp/v2/plugins, and an unauthenticated run that samples any record sees `yoast_head_json`, which is a stronger signal because it proves the SEO data is actually there. (2) Claiming the namespace would suppress the fingerprinted tier for Yoast - `yoast` is the alias map's canonical entry (fingerprint-aliases.json: yoast -> Yoast SEO / wordpress-seo), and the public URL-scan funnel depends on an unauthenticated, unsampled run still naming Yoast from the namespace alone. A profile claiming the namespace turns that row off. If this profile ever needs the namespace as a signal, the fingerprint alias and its contract tests have to be reconsidered in the same change.",
153 "Registers dozens of REST routes under /yoast/v1 and NOT ONE of them is a data collection [VERIFIED LIVE 2026-08-16, identical authenticated and unauthenticated]: they are AI generation (ai_generator/*, ai_content_planner/*), indexing jobs (indexing/*, link-indexing/*), setup wizard state (configuration/*), dashboards (statistics, seo_scores, readability_scores, time_based_seo_metrics, workouts), integrations (semrush/*, wincher/*, site_kit_*) and UI dismissals. This is the live evidence behind the rule that `/yoast/*` must never be opened wholesale, and behind the classifier's existing wp.integration.yoast exclusion - the per-record SEO data does not live there, it rides the core records. The one route that might tempt an author, /yoast/v1/get_head, is a URL-to-head helper, not a collection.",
154 "Yoast's head can be NOT visible in the rendered front-end HTML [VERIFIED LIVE 2026-08-16]: the homepage and a post permalink both contained no `Yoast SEO plugin` comments, no og: meta tags, and no wp-content/plugins/wordpress-seo asset path - a host caching layer served a head without them, while the REST yoast_head / yoast_head_json fields are fully populated. Two consequences: assetPathSlugs will not fire for Yoast on such a host (so the fingerprinted tier cannot see it), and a public HTML scrape is not a substitute for the REST read.",
155 "Plugin CONFIGURATION is not data. Yoast's sitemap settings (Wix generates its own sitemap), its per-post-type title/description templates, breadcrumbs, social profile URLs and knowledge-graph organisation data all live in the wpseo_* wp_options rows, which WordPress REST does not expose at all. They are reconfigure-in-wix; the templates have a real Wix home if the user supplies them (seo/seo-pattern), and the search-engine verification tags have one too (seo/site-seo-tags).",
156 "Redirects are a Yoast Premium feature; determine whether source redirect data exists from the active source inventory. Other redirect plugins may hold independent maps. Wix publicly documents the SEO Redirects API in Developer Preview, but this migration capability remains pending until extraction, safe application and frontend verification are integrated (seo/domain.json pitfall url-redirect-api-not-yet-integrated)."