← 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}`);
})();