← back to Dw Yolo Loop
scripts/color-seo/push-color-seo.cjs
58 lines
const fs=require('fs');
const env=fs.readFileSync(process.env.HOME+'/Projects/secrets-manager/.env','utf8');
const get=k=>{const m=env.match(new RegExp('^'+k+'=(.*)$','m'));return m?m[1].trim():'';};
const TOKEN=get('SHOPIFY_ADMIN_TOKEN'); // write_products covers collections
const HOST='designer-laboratory-sandbox.myshopify.com';
const GQL=`https://${HOST}/admin/api/2025-01/graphql.json`;
const H={'X-Shopify-Access-Token':TOKEN,'Content-Type':'application/json'};
// 17 live color collections + a per-color editorial note (keeps each landing unique — no dup-content)
const COLORS=[
['black','Black','for dramatic, high-contrast interiors'],
['white-wallcoverings','White','for light, gallery-clean walls'],
['gray-wallcoverings','Gray','the versatile neutral that anchors any palette'],
['grey-wallcovering','Grey','the versatile neutral that anchors any palette'],
['blue-wallpaper','Blue','from serene powder to deep, inky tones'],
['navy-wallcoverings','Navy','rich, sophisticated, and timeless'],
['green-wallcoverings','Green','from restful sage to jewel-box emerald'],
['teal-wallcoverings','Teal','a confident blend of blue and green'],
['red-wallcoverings','Red','bold, warm, and unmistakably luxe'],
['pink-wallcoverings','Pink','from soft blush to vivid fuchsia'],
['purple','Purple','regal, moody, and modern'],
['yellow-wallcoverings','Yellow','sunlit and optimistic'],
['gold-wallcoverings','Gold','metallic warmth and quiet glamour'],
['orange','Orange','spice-warm and energizing'],
['brown-wallcoverings','Brown','earthy, grounding, and tactile'],
['beige-wallcoverings','Beige','the quiet-luxury neutral'],
['silver-wallcoverings','Silver','cool metallic shimmer'],
];
const BANNED=/wallquest|chesapeake|brewster|nextwall|seabrook|nicolette/i;
function copy(color,note){
const title=`${color} Wallcoverings & Wallpaper | Designer Wallcoverings`;
const desc=`Shop ${color.toLowerCase()} wallcoverings & wallpaper at Designer Wallcoverings — ${note}. Premier design houses, to the trade & retail.`.slice(0,160);
const body=`<p>${color} wallcoverings — ${note}. Designer Wallcoverings curates ${color.toLowerCase()} wallpaper and wallcoverings from the world's premier design houses: grasscloths, silks, flocks, metallics, and printed papers across every shade of ${color.toLowerCase()}. Order memo samples online; available to the trade and retail.</p>`;
return {title,desc,body};
}
async function gql(query,variables){const r=await fetch(GQL,{method:'POST',headers:H,body:JSON.stringify({query,variables})});return r.json();}
const ONLY=(process.argv.find(a=>a.startsWith('--only='))||'').split('=')[1];
(async()=>{
const targets=ONLY?COLORS.filter(c=>c[0]===ONLY):COLORS;
let ok=0,err=0;
for(const [handle,color,note] of targets){
const c=copy(color,note);
if(BANNED.test(c.title+c.desc+c.body)){console.log('ABORT leak',handle);continue;}
const find=await gql(`query($h:String!){collectionByHandle(handle:$h){id title}}`,{h:handle});
const id=find.data&&find.data.collectionByHandle&&find.data.collectionByHandle.id;
if(!id){console.log(' ?? no collection',handle,JSON.stringify(find.errors||'').slice(0,80));err++;continue;}
const m=await gql(`mutation($in:CollectionInput!){collectionUpdate(input:$in){collection{id handle} userErrors{field message}}}`,
{in:{id, descriptionHtml:c.body, seo:{title:c.title, description:c.desc}}});
const ue=m.data&&m.data.collectionUpdate&&m.data.collectionUpdate.userErrors;
if(ue&&ue.length){console.log(' ERR',handle,JSON.stringify(ue).slice(0,120));err++;}
else{console.log(' ✓',handle,'→ SEO title+desc+intro set');ok++;}
}
console.log(`\n[color-seo] updated=${ok} err=${err} of ${targets.length}`);
})();