← back to Consulting Designerwallcoverings Com
scripts/aeo-build-collection-metafields.mjs
86 lines
#!/usr/bin/env node
// TK-20 — Build the DRAFT collection-metafield payload + ready-to-run (GATED)
// `metafieldsSet` mutations that populate custom.faq (json) + custom.category
// (single_line_text_field) on the 3 AEO collections, from the committed FAQ drafts.
// The live theme's sections/dw-collection-hero.liquid already renders these
// metafields as a VISIBLE FAQ <details> + emits FAQPage + CollectionPage JSON-LD.
// DRAFT-ONLY: writes files into the repo. Performs NO Shopify 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 OUTDIR = path.join(DRAFTS, 'collection-metafields');
// handle → { gid, file, category } (category = brand-voice default; hero falls back to 'wallcovering')
const COLL = [
{ handle: 'versace-wallpaper', gid: 'gid://shopify/Collection/79911911536', file: 'versace-wallpaper.jsonld', category: 'wallcovering' },
{ handle: 'osborne-little', gid: 'gid://shopify/Collection/298974314547', file: 'osborne-and-little.jsonld', category: 'wallcovering' },
{ handle: 'zuber-wallcoverings', gid: 'gid://shopify/Collection/299575803955', file: 'zuber-wallpaper.jsonld', category: 'mural' },
];
const read = f => JSON.parse(fs.readFileSync(path.join(DRAFTS, f), 'utf8'));
// Pull the FAQPage mainEntity → [{q,a}] exactly as the theme expects (item.q / item.a).
function faqPairs(file) {
const j = read(file);
const faq = (j['@graph'] || []).find(n => n['@type'] === 'FAQPage');
if (!faq) throw new Error('no FAQPage in ' + file);
return faq.mainEntity.map(qa => ({ q: qa.name, a: qa.acceptedAnswer.text }));
}
fs.mkdirSync(OUTDIR, { recursive: true });
const mutations = [];
for (const c of COLL) {
const pairs = faqPairs(c.file);
// payload the metafield stores: a JSON *string* (json metafield value is a stringified array)
const faqValueString = JSON.stringify(pairs);
fs.writeFileSync(path.join(OUTDIR, `${c.handle}.faq.json`), JSON.stringify(pairs, null, 2));
// Ready-to-run GraphQL metafieldsSet mutation (GATED — do not run until Steve GO).
const vars = {
metafields: [
{ ownerId: c.gid, namespace: 'custom', key: 'faq', type: 'json', value: faqValueString },
{ ownerId: c.gid, namespace: 'custom', key: 'category', type: 'single_line_text_field', value: c.category },
],
};
mutations.push({ handle: c.handle, gid: c.gid, count: pairs.length, vars });
}
const MUT = `mutation SetAeoMetafields($metafields: [MetafieldsSetInput!]!) {
metafieldsSet(metafields: $metafields) {
metafields { key namespace ownerType type }
userErrors { field message }
}
}`;
// Emit a single shell file with one curl per collection (each carries its own variables).
const STORE = 'designer-laboratory-sandbox.myshopify.com';
let sh = `#!/usr/bin/env bash
# TK-20 GATED — populate custom.faq + custom.category on the 3 AEO collections.
# The live theme (sections/dw-collection-hero.liquid) renders these as a VISIBLE
# FAQ + emits FAQPage + CollectionPage JSON-LD. DO NOT RUN until Steve GO.
# Requires SHOPIFY_ADMIN_TOKEN with write_products scope (collection metafields).
set -euo pipefail
TOKEN="\${SHOPIFY_ADMIN_TOKEN:?export SHOPIFY_ADMIN_TOKEN first}"
STORE="${STORE}"
API="https://$STORE/admin/api/2024-10/graphql.json"
`;
const MUT_JSON = JSON.stringify(MUT);
for (const m of mutations) {
const body = JSON.stringify({ query: MUT, variables: m.vars });
fs.writeFileSync(path.join(OUTDIR, `${m.handle}.metafieldsSet.json`), body);
sh += `
echo "== ${m.handle} (${m.count} FAQ) =="
curl -s "$API" -H "X-Shopify-Access-Token: $TOKEN" -H "Content-Type: application/json" \\
--data-binary @"$(dirname "$0")/${m.handle}.metafieldsSet.json" | tee /tmp/aeo-mf-${m.handle}.json
`;
}
fs.writeFileSync(path.join(OUTDIR, 'APPLY-metafields.sh'), sh);
fs.chmodSync(path.join(OUTDIR, 'APPLY-metafields.sh'), 0o755);
console.log('wrote collection-metafields/ :',
fs.readdirSync(OUTDIR).join(', '));
console.log('FAQ counts:', mutations.map(m => `${m.handle}=${m.count}`).join(' '));