← back to Consulting Designerwallcoverings Com
scripts/aeo-build-jsonld-snippet.mjs
97 lines
#!/usr/bin/env node
// TK-20 — Build the DRAFT handle-keyed theme snippet `dw-aeo-jsonld.liquid`
// from the committed docs/aeo-drafts/*.jsonld files, so the FAQPage schema the
// snippet emits stays in EXACT sync with the reviewed/approved draft content.
// DRAFT-ONLY: writes a .liquid file into the repo. It performs NO theme write.
import fs from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';
const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
const DRAFTS = path.join(ROOT, 'docs/aeo-drafts');
const OUT = path.join(DRAFTS, 'theme-snippets', 'dw-aeo-jsonld.liquid');
// handle → { file, template } . template = 'collection' | 'page'
const MAP = [
{ handle: 'versace-wallpaper', file: 'versace-wallpaper.jsonld', template: 'collection' },
{ handle: 'osborne-little', file: 'osborne-and-little.jsonld', template: 'collection' },
{ handle: 'zuber-wallcoverings', file: 'zuber-wallpaper.jsonld', template: 'collection' },
{ handle: 'wall-coverings', file: 'wall-coverings.jsonld', template: 'page' },
{ handle: 'designer-wallpaper', file: 'designer-wallpaper.jsonld', template: 'page' },
];
const read = f => JSON.parse(fs.readFileSync(path.join(DRAFTS, f), 'utf8'));
// From a committed graph, keep only the schema nodes that are SAFE to add without
// duplicating what the theme already emits:
// - pages : WebPage + FAQPage (sections/page.liquid emits neither)
// - collections: FAQPage ONLY (sections/dw-collection-hero.liquid already
// emits CollectionPage + BreadcrumbList; we must NOT re-emit them)
function schemaFor(entry) {
const j = read(entry.file);
const graph = (j['@graph'] || []).filter(n => {
if (n['@type'] === 'FAQPage') return true;
if (entry.template === 'page' && n['@type'] === 'WebPage') return true;
return false; // drop CollectionPage on collections (theme already emits it)
});
return { '@context': 'https://schema.org', '@graph': graph };
}
let cases = '';
for (const e of MAP) {
const obj = schemaFor(e);
// pretty JSON, indented under the script tag
const jsonStr = JSON.stringify(obj, null, 2).split('\n').map(l => ' ' + l).join('\n');
const guard = e.template === 'collection'
// only emit if the theme's metafield-driven FAQ is NOT set, to avoid a
// duplicate FAQPage (dw-collection-hero emits FAQPage from custom.faq).
? ` {%- assign _mf_faq = collection.metafields.custom.faq.value -%}\n {%- if _mf_faq == blank -%}`
: ` {%- comment -%} page: theme emits no FAQPage; safe to emit {%- endcomment -%}`;
const close = e.template === 'collection' ? ` {%- endif -%}\n` : ``;
cases += ` {%- when '${e.handle}' -%}\n${guard}\n <script type="application/ld+json">\n${jsonStr}\n </script>\n${close}`;
}
const snippet = `{%- comment -%}
dw-aeo-jsonld.liquid — DRAFT (TK-20, DW consulting) — do NOT inject until Steve GO.
Emits the reviewed/approved FAQPage (and WebPage for landing pages) JSON-LD for the
striking-distance AEO targets, KEYED ON HANDLE. Generated from the committed
docs/aeo-drafts/*.jsonld by scripts/aeo-build-jsonld-snippet.mjs — regenerate, do not
hand-edit, so the schema stays in sync with the approved copy.
WHY THIS SNIPPET EXISTS
-----------------------
* PAGES (/pages/wall-coverings, /pages/designer-wallpaper): sections/page.liquid renders
page.content visibly but emits NO FAQPage/WebPage JSON-LD. This snippet supplies it.
* COLLECTIONS (versace-wallpaper, osborne-little, zuber-wallcoverings): the theme ALREADY
emits FAQPage + CollectionPage + BreadcrumbList from sections/dw-collection-hero.liquid
when the collection's custom.faq metafield is populated. The RECOMMENDED path for
collections is therefore to WRITE THE METAFIELDS (see the memo), not this snippet.
The collection branches below are a FALLBACK — they emit FAQPage ONLY, and only when
custom.faq is blank, so they never double-emit.
INSTALL (both are Steve-gated theme writes — see the memo for exact PUT commands):
1. PUT this file to snippets/dw-aeo-jsonld.liquid on the live theme.
2. Add {% render 'dw-aeo-jsonld' %} near the end of sections/page.liquid
(covers pages). For the collection fallback, also add it to
sections/dw-collection-hero.liquid (guarded branch handles the dedupe).
{%- endcomment -%}
{%- liquid
assign _tpl = template.name
if _tpl == 'page'
assign _aeo_handle = page.handle
elsif _tpl == 'collection'
assign _aeo_handle = collection.handle
else
assign _aeo_handle = ''
endif
-%}
{%- case _aeo_handle -%}
${cases} {%- else -%}
{%- endcase -%}
`;
fs.mkdirSync(path.dirname(OUT), { recursive: true });
fs.writeFileSync(OUT, snippet);
console.log('wrote', path.relative(ROOT, OUT), `(${snippet.length} bytes, ${MAP.length} handles)`);