← back to Majilite Onboard
Publish all 160 Majilite + collection to ALL 13 sales channels
8889c9b6a5c0ba168495b8ae31765a44ac6eeff6 · 2026-08-10 11:46:05 -0700 · Steve Abrams
Files touched
A scripts/publish_all_channels.js
Diff
commit 8889c9b6a5c0ba168495b8ae31765a44ac6eeff6
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Mon Aug 10 11:46:05 2026 -0700
Publish all 160 Majilite + collection to ALL 13 sales channels
---
scripts/publish_all_channels.js | 31 +++++++++++++++++++++++++++++++
1 file changed, 31 insertions(+)
diff --git a/scripts/publish_all_channels.js b/scripts/publish_all_channels.js
new file mode 100644
index 0000000..8fceed7
--- /dev/null
+++ b/scripts/publish_all_channels.js
@@ -0,0 +1,31 @@
+const fs=require('fs'),path=require('path');
+const STORE='designer-laboratory-sandbox.myshopify.com';
+const TOKEN=(fs.readFileSync(path.join(process.env.HOME,'Projects/secrets-manager/.env'),'utf8').match(/^SHOPIFY_ADMIN_TOKEN=(.+)$/m)||[])[1].replace(/["']/g,'').trim();
+const GQL=`https://${STORE}/admin/api/2024-10/graphql.json`;
+const sleep=ms=>new Promise(r=>setTimeout(r,ms));
+async function gql(q,v){for(let a=0;a<6;a++){const r=await fetch(GQL,{method:'POST',headers:{'X-Shopify-Access-Token':TOKEN,'Content-Type':'application/json'},body:JSON.stringify({query:q,variables:v})});const j=await r.json();if(j.errors){if(JSON.stringify(j.errors).includes('THROTTLED')){await sleep(1500*(a+1));continue;}throw new Error(JSON.stringify(j.errors).slice(0,200));}return j.data;}throw new Error('throttled');}
+(async()=>{
+ const pd=await gql(`{ publications(first:40){ nodes{ id name } } }`);
+ const pubs=pd.publications.nodes;
+ console.log('ALL channels ('+pubs.length+'):', pubs.map(p=>p.name).join(', '));
+ const pubInput=pubs.map(p=>({publicationId:p.id}));
+ // collect Majilite products + the collection
+ let items=[]; let c=null;
+ do{const d=await gql(`query($c:String){ products(first:100, after:$c, query:"vendor:Majilite"){ pageInfo{hasNextPage endCursor} nodes{ id handle } } }`,{c});
+ items.push(...d.products.nodes); c=d.products.pageInfo.hasNextPage?d.products.pageInfo.endCursor:null;}while(c);
+ items.push({id:'gid://shopify/Collection/303540666419', handle:'(collection)'});
+ console.log(`publishing ${items.length} items to ${pubs.length} channels each…`);
+ const chanFail={}; let ok=0,err=0;
+ for(const it of items){
+ try{
+ const d=await gql(`mutation($id:ID!,$pubs:[PublicationInput!]!){ publishablePublish(id:$id, input:$pubs){ userErrors{field message} } }`,{id:it.id,pubs:pubInput});
+ const ue=d.publishablePublish.userErrors;
+ if(ue&&ue.length){ err++; ue.forEach(e=>{const k=(e.message||'').slice(0,60); chanFail[k]=(chanFail[k]||0)+1;}); if(err<=6)console.log(' ⚠',it.handle,JSON.stringify(ue).slice(0,120)); }
+ else ok++;
+ }catch(e){err++; if(err<=6)console.log(' ✗',it.handle,e.message.slice(0,80));}
+ if(ok%40===0&&ok)process.stdout.write(` …${ok} published to all channels\n`);
+ await sleep(180);
+ }
+ console.log(`\nDONE. items_ok=${ok} items_with_errors=${err}`);
+ if(Object.keys(chanFail).length) console.log('channel-level rejections (by msg):', JSON.stringify(chanFail,null,1));
+})();
← 4006a51 Dual-list Majilite: add Fabric + Wallcovering tags to all 16
·
back to Majilite Onboard
·
Draft Constant Contact campaign for Majilite Metallic Specia 8fafdaf →