← back to Dw Sarah Rowland Searchfix
auto-save: 2026-07-30T09:16:33 (8 files) — build-titles.mjs color-map.tsv dump-skus.mjs generic-skus.txt inspect-titles.mjs
4f76e346f29fbf2d82f3f8c98bfe68652d1952e8 · 2026-07-30 09:16:38 -0700 · Steve Abrams
Files touched
A build-titles.mjsA color-map.tsvA dump-skus.mjsA generic-skus.txtA inspect-titles.mjsA list-collections.mjsA title-plan.jsonA vendor-of-collections.mjs
Diff
commit 4f76e346f29fbf2d82f3f8c98bfe68652d1952e8
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Thu Jul 30 09:16:38 2026 -0700
auto-save: 2026-07-30T09:16:33 (8 files) — build-titles.mjs color-map.tsv dump-skus.mjs generic-skus.txt inspect-titles.mjs
---
build-titles.mjs | 23 +++++
color-map.tsv | 35 ++++++++
dump-skus.mjs | 10 +++
generic-skus.txt | 37 ++++++++
inspect-titles.mjs | 21 +++++
list-collections.mjs | 12 +++
title-plan.json | 224 ++++++++++++++++++++++++++++++++++++++++++++++
vendor-of-collections.mjs | 15 ++++
8 files changed, 377 insertions(+)
diff --git a/build-titles.mjs b/build-titles.mjs
new file mode 100644
index 0000000..c4ee977
--- /dev/null
+++ b/build-titles.mjs
@@ -0,0 +1,23 @@
+import { gql } from './lib.mjs'; import fs from 'node:fs';
+const products=JSON.parse(fs.readFileSync(new URL('./products.json',import.meta.url)));
+const generic=products.filter(p=>p.title.trim()==='Wallcovering | Architectural Wallcoverings');
+const colorMap=Object.fromEntries(fs.readFileSync(new URL('./color-map.tsv',import.meta.url),'utf8')
+ .trim().split('\n').filter(Boolean).map(l=>l.split('\t')));
+const titleCase=(s)=>s.split(' ').map(w=>w?w[0].toUpperCase()+w.slice(1):w).join(' ');
+const plan=[];
+for(const p of generic){
+ const d=(await gql(`query($id:ID!){product(id:$id){handle variants(first:1){nodes{sku}}}}`,{id:p.id})).product;
+ const sku=d.variants.nodes[0]?.sku;
+ // handle -> pattern+colorway: strip prefix up to 'sarah-rowland-' and trailing '-srd-xxx-NN'
+ let mid=d.handle.replace(/^.*sarah-rowland-/,'').replace(/-srd-[a-z0-9]+-\d+.*$/,'').replace(/-(sample|architectural-wallcoverings).*$/,'');
+ const name=titleCase(mid.replace(/-/g,' ').trim());
+ const fam=colorMap[sku]||'';
+ const title = fam ? `${name} - ${fam} Commercial Wallcovering | Koroseal`
+ : `${name} Commercial Wallcovering | Koroseal`;
+ plan.push({id:p.id, sku, handle:d.handle, title});
+}
+fs.writeFileSync(new URL('./title-plan.json',import.meta.url), JSON.stringify(plan,null,2));
+console.log(`Proposed titles (${plan.length}):\n`);
+plan.forEach(x=>console.log(` ${x.sku} ${x.title}`));
+const noFam=plan.filter(x=>!/ - /.test(x.title));
+if(noFam.length) console.log(`\n⚠ ${noFam.length} without a color family (no DB color_name): ${noFam.map(x=>x.sku).join(', ')}`);
diff --git a/color-map.tsv b/color-map.tsv
new file mode 100644
index 0000000..6f5cd76
--- /dev/null
+++ b/color-map.tsv
@@ -0,0 +1,35 @@
+DWK-302550 Off-White
+DWK-302560 Taupe
+DWK-302570 Black
+DWK-302580 Pale Green
+DWK-302600 Light Gray
+DWK-302670 Off-White
+DWK-302671 Sage Green
+DWK-302680 Off-White
+DWK-302720 Off-White
+DWK-302730 Pale Beige
+DWK-302750 White
+DWK-302760 Off-White
+DWK-302780 White
+DWK-302840 Pale Blue
+DWK-302860 Dark Slate Gray
+DWK-302880 Light Gray
+DWK-302890 Light Gray
+DWK-302900 Pale Yellow
+DWK-302910 Pale Olive
+DWK-302920 Gray
+DWK-302930 Off-White
+DWK-302940 White
+DWK-302960 Taupe
+DWK-302970 White
+DWK-302980 Khaki
+DWK-303010 Gray
+DWK-303020 Pale Beige
+DWK-303040 Steel Blue
+DWK-303050 Off-White
+DWK-303070 Light Gray
+DWK-303080 White
+DWK-303090 Beige
+DWK-303100 Light Gray
+DWK-303120 Beige
+DWK-303172 White
diff --git a/dump-skus.mjs b/dump-skus.mjs
new file mode 100644
index 0000000..6eaca8c
--- /dev/null
+++ b/dump-skus.mjs
@@ -0,0 +1,10 @@
+import { gql } from './lib.mjs'; import fs from 'node:fs';
+const products=JSON.parse(fs.readFileSync(new URL('./products.json',import.meta.url)));
+const generic=products.filter(p=>p.title.trim()==='Wallcovering | Architectural Wallcoverings');
+const out=[];
+for(const p of generic){
+ const d=(await gql(`query($id:ID!){product(id:$id){variants(first:1){nodes{sku}}}}`,{id:p.id})).product;
+ out.push(d.variants.nodes[0]?.sku);
+}
+fs.writeFileSync(new URL('./generic-skus.txt',import.meta.url), out.filter(Boolean).join('\n'));
+console.log('wrote', out.length, 'skus');
diff --git a/generic-skus.txt b/generic-skus.txt
new file mode 100644
index 0000000..352bbeb
--- /dev/null
+++ b/generic-skus.txt
@@ -0,0 +1,37 @@
+DWK-302940
+DWK-303100
+DWK-303050
+DWK-303020
+DWK-302920
+DWK-302860
+DWK-303172
+DWK-302580
+DWK-303120
+DWK-302680
+DWK-303090
+DWK-303080
+DWK-303070
+DWK-302570
+DWK-303040
+DWK-303010
+DWK-302970
+DWK-302671
+DWK-302670
+DWK-302980
+DWK-302930
+DWK-302900
+DWK-302890
+DWK-302910
+DWK-302960
+DWK-302600
+DWK-302880
+DWK-302840
+DWK-302560
+DWK-302550
+DWK-302780
+DWK-302760
+DWK-302730
+DWK-302750
+DWK-302720
+DWK-302540-Sample
+DWK-302700-Sample
\ No newline at end of file
diff --git a/inspect-titles.mjs b/inspect-titles.mjs
new file mode 100644
index 0000000..bf795cd
--- /dev/null
+++ b/inspect-titles.mjs
@@ -0,0 +1,21 @@
+import { gql } from './lib.mjs';
+import fs from 'node:fs';
+const products=JSON.parse(fs.readFileSync(new URL('./products.json',import.meta.url)));
+const generic=products.filter(p=>/^Wallcovering \| Architectural Wallcoverings\s*$/.test(p.title.trim()) || p.title.trim()==='Wallcovering | Architectural Wallcoverings');
+console.log(`Bare-title products: ${generic.length} of ${products.length}\n`);
+// what naming data exists? sample the first 6
+const Q=`query($id:ID!){ product(id:$id){ handle title
+ pat:metafield(namespace:"custom",key:"pattern_name"){value}
+ patD:metafield(namespace:"dwc",key:"pattern_name"){value}
+ col:metafield(namespace:"custom",key:"color"){value}
+ colway:metafield(namespace:"custom",key:"color_way"){value}
+ mfrpat:metafield(namespace:"custom",key:"mfr_pattern_number"){value}
+ sku:variants(first:1){nodes{sku}} } }`;
+for(const p of generic.slice(0,6)){
+ const d=(await gql(Q,{id:p.id})).product;
+ console.log(`handle: ${d.handle}`);
+ console.log(` pattern_name(custom)=${d.pat?.value??'∅'} pattern_name(dwc)=${d.patD?.value??'∅'} color=${d.col?.value??'∅'} color_way=${d.colway?.value??'∅'} sku=${d.sku.nodes[0]?.sku??'∅'}`);
+}
+// also show 3 well-formed siblings for the naming CONVENTION
+console.log('\n— well-formed sibling titles for reference —');
+products.filter(p=>/ - .*Wallcovering/i.test(p.title)).slice(0,4).forEach(p=>console.log(' ',p.title));
diff --git a/list-collections.mjs b/list-collections.mjs
new file mode 100644
index 0000000..1baeba9
--- /dev/null
+++ b/list-collections.mjs
@@ -0,0 +1,12 @@
+import { gql } from './lib.mjs';
+const Q=`query($c:String){ collections(first:250, after:$c){ pageInfo{hasNextPage endCursor}
+ nodes{ id title handle productsCount{count} } } }`;
+let cur=null, all=[];
+do{ const d=await gql(Q,{c:cur}); all.push(...d.collections.nodes);
+ cur=d.collections.pageInfo.hasNextPage?d.collections.pageInfo.endCursor:null; }while(cur);
+console.log('total collections:', all.length);
+// heuristic: designer lines often end in "Collection" or "Wallcovering Collection"
+const cand=all.filter(c=>/collection/i.test(c.title) && c.productsCount.count>0)
+ .sort((a,b)=>a.title.localeCompare(b.title));
+console.log('\ncandidate designer/named collections:');
+cand.forEach(c=>console.log(` ${String(c.productsCount.count).padStart(4)} ${c.title} [${c.handle}]`));
diff --git a/title-plan.json b/title-plan.json
new file mode 100644
index 0000000..c45c405
--- /dev/null
+++ b/title-plan.json
@@ -0,0 +1,224 @@
+[
+ {
+ "id": "gid://shopify/Product/7634022137907",
+ "sku": "DWK-302940",
+ "handle": "dwk-302940-koroseal-sarah-rowland-lilly-black-white-srd-ll3-01",
+ "title": "Lilly Black White - White Commercial Wallcovering | Koroseal"
+ },
+ {
+ "id": "gid://shopify/Product/7634023940147",
+ "sku": "DWK-303100",
+ "handle": "dwk-303100-koroseal-sarah-rowland-ruby-bubblegum-ruby-dark-chocolate-srd-rub-01",
+ "title": "Ruby Bubblegum Ruby Dark Chocolate - Light Gray Commercial Wallcovering | Koroseal"
+ },
+ {
+ "id": "gid://shopify/Product/7634023383091",
+ "sku": "DWK-303050",
+ "handle": "dwk-303050-koroseal-sarah-rowland-molly-indigo-srd-mo1-01",
+ "title": "Molly Indigo - Off-White Commercial Wallcovering | Koroseal"
+ },
+ {
+ "id": "gid://shopify/Product/7634023317555",
+ "sku": "DWK-303020",
+ "handle": "dwk-303020-koroseal-sarah-rowland-mary-margaret-taupe-srd-mma-01",
+ "title": "Mary Margaret Taupe - Pale Beige Commercial Wallcovering | Koroseal"
+ },
+ {
+ "id": "gid://shopify/Product/7634022072371",
+ "sku": "DWK-302920",
+ "handle": "dwk-302920-koroseal-sarah-rowland-leo-black-gray-srd-leo-03",
+ "title": "Leo Black Gray - Gray Commercial Wallcovering | Koroseal"
+ },
+ {
+ "id": "gid://shopify/Product/7634020040755",
+ "sku": "DWK-302860",
+ "handle": "dwk-302860-koroseal-sarah-rowland-harry-midnight-bark-srd-har-03",
+ "title": "Harry Midnight Bark - Dark Slate Gray Commercial Wallcovering | Koroseal"
+ },
+ {
+ "id": "gid://shopify/Product/7634025480243",
+ "sku": "DWK-303172",
+ "handle": "dwk-303172-koroseal-sarah-rowland-zak-black-white-srd-zak-04",
+ "title": "Zak Black White - White Commercial Wallcovering | Koroseal"
+ },
+ {
+ "id": "gid://shopify/Product/7634024693811",
+ "sku": "DWK-302580",
+ "handle": "dwk-302580-koroseal-sarah-rowland-scarlett-mary-margaret-green-srd-smm-01",
+ "title": "Scarlett Mary Margaret Green - Pale Green Commercial Wallcovering | Koroseal"
+ },
+ {
+ "id": "gid://shopify/Product/7634024005683",
+ "sku": "DWK-303120",
+ "handle": "dwk-303120-koroseal-sarah-rowland-sasha-2-taupe-soft-blue-srd-sa2-01",
+ "title": "Sasha 2 Taupe Soft Blue - Beige Commercial Wallcovering | Koroseal"
+ },
+ {
+ "id": "gid://shopify/Product/7634023907379",
+ "sku": "DWK-302680",
+ "handle": "dwk-302680-koroseal-sarah-rowland-roo-2-orange-srd-ro2-01",
+ "title": "Roo 2 Orange - Off-White Commercial Wallcovering | Koroseal"
+ },
+ {
+ "id": "gid://shopify/Product/7634023841843",
+ "sku": "DWK-303090",
+ "handle": "dwk-303090-koroseal-sarah-rowland-roo-1-bone-srd-ro1-01",
+ "title": "Roo 1 Bone - Beige Commercial Wallcovering | Koroseal"
+ },
+ {
+ "id": "gid://shopify/Product/7634023710771",
+ "sku": "DWK-303080",
+ "handle": "dwk-303080-koroseal-sarah-rowland-renata-orange-blue-srd-ren-02",
+ "title": "Renata Orange Blue - White Commercial Wallcovering | Koroseal"
+ },
+ {
+ "id": "gid://shopify/Product/7634023481395",
+ "sku": "DWK-303070",
+ "handle": "dwk-303070-koroseal-sarah-rowland-plato-spring-bone-srd-pla-03",
+ "title": "Plato Spring Bone - Light Gray Commercial Wallcovering | Koroseal"
+ },
+ {
+ "id": "gid://shopify/Product/7634023448627",
+ "sku": "DWK-302570",
+ "handle": "dwk-302570-koroseal-sarah-rowland-napoleon-edward-black-srd-npe-01",
+ "title": "Napoleon Edward Black - Black Commercial Wallcovering | Koroseal"
+ },
+ {
+ "id": "gid://shopify/Product/7634023055411",
+ "sku": "DWK-303040",
+ "handle": "dwk-303040-koroseal-sarah-rowland-medium-chloe-storm-srd-mch-03",
+ "title": "Medium Chloe Storm - Steel Blue Commercial Wallcovering | Koroseal"
+ },
+ {
+ "id": "gid://shopify/Product/7634022858803",
+ "sku": "DWK-303010",
+ "handle": "dwk-303010-koroseal-sarah-rowland-maria-gray-gold-srd-mar-05",
+ "title": "Maria Gray Gold - Gray Commercial Wallcovering | Koroseal"
+ },
+ {
+ "id": "gid://shopify/Product/7634022596659",
+ "sku": "DWK-302970",
+ "handle": "dwk-302970-koroseal-sarah-rowland-littlhesta-squash-srd-lth-01",
+ "title": "Littlhesta Squash - White Commercial Wallcovering | Koroseal"
+ },
+ {
+ "id": "gid://shopify/Product/7634022334515",
+ "sku": "DWK-302671",
+ "handle": "dwk-302671-koroseal-sarah-rowland-linus-stripe-green-srd-lnu-02",
+ "title": "Linus Stripe Green - Sage Green Commercial Wallcovering | Koroseal"
+ },
+ {
+ "id": "gid://shopify/Product/7634022268979",
+ "sku": "DWK-302670",
+ "handle": "dwk-302670-koroseal-sarah-rowland-linus-stripe-neutral-srd-lns-01",
+ "title": "Linus Stripe Neutral - Off-White Commercial Wallcovering | Koroseal"
+ },
+ {
+ "id": "gid://shopify/Product/7634022170675",
+ "sku": "DWK-302980",
+ "handle": "dwk-302980-koroseal-sarah-rowland-little-nora-buff-srd-lno-03",
+ "title": "Little Nora Buff - Khaki Commercial Wallcovering | Koroseal"
+ },
+ {
+ "id": "gid://shopify/Product/7634022105139",
+ "sku": "DWK-302930",
+ "handle": "dwk-302930-koroseal-sarah-rowland-lilly-white-srd-ll1-01",
+ "title": "Lilly White - Off-White Commercial Wallcovering | Koroseal"
+ },
+ {
+ "id": "gid://shopify/Product/7634022039603",
+ "sku": "DWK-302900",
+ "handle": "dwk-302900-koroseal-sarah-rowland-leif-5-denim-srd-le5-01",
+ "title": "Leif 5 Denim - Pale Yellow Commercial Wallcovering | Koroseal"
+ },
+ {
+ "id": "gid://shopify/Product/7634021941299",
+ "sku": "DWK-302890",
+ "handle": "dwk-302890-koroseal-sarah-rowland-leif-3-mud-srd-le3-01",
+ "title": "Leif 3 Mud - Light Gray Commercial Wallcovering | Koroseal"
+ },
+ {
+ "id": "gid://shopify/Product/7634021842995",
+ "sku": "DWK-302910",
+ "handle": "dwk-302910-koroseal-sarah-rowland-leif-dottie-gray-bone-srd-ldo-01",
+ "title": "Leif Dottie Gray Bone - Pale Olive Commercial Wallcovering | Koroseal"
+ },
+ {
+ "id": "gid://shopify/Product/7634021711923",
+ "sku": "DWK-302960",
+ "handle": "dwk-302960-koroseal-sarah-rowland-littlbeb-bone-charcoal-srd-lbe-04",
+ "title": "Littlbeb Bone Charcoal - Taupe Commercial Wallcovering | Koroseal"
+ },
+ {
+ "id": "gid://shopify/Product/7634020532275",
+ "sku": "DWK-302600",
+ "handle": "dwk-302600-koroseal-sarah-rowland-haze-2-taupe-srd-hz2-01",
+ "title": "Haze 2 Taupe - Light Gray Commercial Wallcovering | Koroseal"
+ },
+ {
+ "id": "gid://shopify/Product/7634020368435",
+ "sku": "DWK-302880",
+ "handle": "dwk-302880-koroseal-sarah-rowland-haz-1-taupe-srd-hz1-01",
+ "title": "Haz 1 Taupe - Light Gray Commercial Wallcovering | Koroseal"
+ },
+ {
+ "id": "gid://shopify/Product/7634019778611",
+ "sku": "DWK-302840",
+ "handle": "dwk-302840-koroseal-sarah-rowland-graham-pumice-white-srd-gra-04",
+ "title": "Graham Pumice White - Pale Blue Commercial Wallcovering | Koroseal"
+ },
+ {
+ "id": "gid://shopify/Product/7634019582003",
+ "sku": "DWK-302560",
+ "handle": "dwk-302560-koroseal-sarah-rowland-felix-birdicement-srd-flb-02",
+ "title": "Felix Birdicement - Taupe Commercial Wallcovering | Koroseal"
+ },
+ {
+ "id": "gid://shopify/Product/7634018926643",
+ "sku": "DWK-302550",
+ "handle": "dwk-302550-koroseal-sarah-rowland-celin-linus-orange-green-srd-cln-03",
+ "title": "Celin Linus Orange Green - Off-White Commercial Wallcovering | Koroseal"
+ },
+ {
+ "id": "gid://shopify/Product/7634018598963",
+ "sku": "DWK-302780",
+ "handle": "dwk-302780-koroseal-sarah-rowland-chess-1-pink-yellow-srd-ch1-03",
+ "title": "Chess 1 Pink Yellow - White Commercial Wallcovering | Koroseal"
+ },
+ {
+ "id": "gid://shopify/Product/7634018238515",
+ "sku": "DWK-302760",
+ "handle": "dwk-302760-koroseal-sarah-rowland-celine-orange-green-srd-ce1-01",
+ "title": "Celine Orange Green - Off-White Commercial Wallcovering | Koroseal"
+ },
+ {
+ "id": "gid://shopify/Product/7634018205747",
+ "sku": "DWK-302730",
+ "handle": "dwk-302730-koroseal-sarah-rowland-big-nora-clay-srd-bno-01",
+ "title": "Big Nora Clay - Pale Beige Commercial Wallcovering | Koroseal"
+ },
+ {
+ "id": "gid://shopify/Product/7634018140211",
+ "sku": "DWK-302750",
+ "handle": "dwk-302750-koroseal-sarah-rowland-brent-red-pink-srd-be1-01",
+ "title": "Brent Red Pink - White Commercial Wallcovering | Koroseal"
+ },
+ {
+ "id": "gid://shopify/Product/7634018107443",
+ "sku": "DWK-302720",
+ "handle": "dwk-302720-koroseal-sarah-rowland-big-chloe-bone-srd-bch-01",
+ "title": "Big Chloe Bone - Off-White Commercial Wallcovering | Koroseal"
+ },
+ {
+ "id": "gid://shopify/Product/7634017878067",
+ "sku": "DWK-302540-Sample",
+ "handle": "aunt-jane-graham-bone-wallpaper-srd-ajg-05-sarah-rowland-sample-architectural-wallcoverings",
+ "title": "Sample Commercial Wallcovering | Koroseal"
+ },
+ {
+ "id": "gid://shopify/Product/7634017845299",
+ "sku": "DWK-302700-Sample",
+ "handle": "aunt-jane-black-wallpaper-srd-aja-01-sarah-rowland-sample-architectural-wallcoverings",
+ "title": "Sample Commercial Wallcovering | Koroseal"
+ }
+]
\ No newline at end of file
diff --git a/vendor-of-collections.mjs b/vendor-of-collections.mjs
new file mode 100644
index 0000000..70ab11a
--- /dev/null
+++ b/vendor-of-collections.mjs
@@ -0,0 +1,15 @@
+import { gql } from './lib.mjs';
+const handles=['barclay-butera-collection-1','candice-olson-collection','candice-olson-collection-1',
+ 'sarah-rowland-wallpaper-collection','kelly-wearstler-collections','the-kelly-wearstler-collection',
+ 'lorenzo-castillo-collection','emma-shipley-wallpaper-collection','paolo-moschino-collections',
+ 'papis-lovejoy','fornasetti','brand-mckenzie-wallpaper-collection','the-graduate-collection',
+ 'steve-abrams-whimsy','hollywood-sunset-collection','the-equestrian-collection','equestrian-collection'];
+const Q=`query($h:String!){ collectionByHandle(handle:$h){ title products(first:60){nodes{vendor}} } }`;
+for(const h of handles){
+ const c=(await gql(Q,{h})).collectionByHandle;
+ if(!c){ console.log(`${h}: (not found)`); continue; }
+ const hist={}; c.products.nodes.forEach(p=>hist[p.vendor||'∅']=(hist[p.vendor||'∅']||0)+1);
+ const top=Object.entries(hist).sort((a,b)=>b[1]-a[1]);
+ const koro=top.find(v=>/koroseal/i.test(v[0]));
+ console.log(`${koro?'★KOROSEAL':' '} ${c.title.padEnd(42)} vendors: ${top.map(([v,n])=>`${v}:${n}`).join(', ').slice(0,80)}`);
+}
← 6257f36 TK-10037: wire PDP Designer row to prefer custom.designer (l
·
back to Dw Sarah Rowland Searchfix
·
TK-10037: add Sarah Rowland designer photo+bio block to coll 26fabe4 →