← back to Designer Wallcoverings
TK-11240: repoint Other Colorways module off title-match onto custom.pattern_name
2e8e01e530ec68c882426fb83c90ba17dcdf1290 · 2026-09-11 08:35:52 -0700 · Steve
Live theme 145556635699 (main). Adds templates/search.colorways.liquid (JSON view
emitting each sibling custom.pattern_name+custom.color, paginated) and rewrites
snippets/colorway-siblings.liquid to group by exact pattern_name (title fallback),
drop the 10/24 truncation (verified 60 vs 10 siblings live on Faux Leaf Squares),
label from custom.color w/ SKU fallback (never 'View'). Part B (versa_catalog
backfill) DROPPED by Steve at CLARIFY gate: source proven ~89% wrong vs live.
Undo: restore snippet from theme-backups + delete the search.colorways template.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Y6Dz4NMwA1ekVm591JgfPT
Files touched
M shopify/theme-files/snippets/colorway-siblings.liquidA shopify/theme-files/templates/search.colorways.liquid
Diff
commit 2e8e01e530ec68c882426fb83c90ba17dcdf1290
Author: Steve <steve@designerwallcoverings.com>
Date: Fri Sep 11 08:35:52 2026 -0700
TK-11240: repoint Other Colorways module off title-match onto custom.pattern_name
Live theme 145556635699 (main). Adds templates/search.colorways.liquid (JSON view
emitting each sibling custom.pattern_name+custom.color, paginated) and rewrites
snippets/colorway-siblings.liquid to group by exact pattern_name (title fallback),
drop the 10/24 truncation (verified 60 vs 10 siblings live on Faux Leaf Squares),
label from custom.color w/ SKU fallback (never 'View'). Part B (versa_catalog
backfill) DROPPED by Steve at CLARIFY gate: source proven ~89% wrong vs live.
Undo: restore snippet from theme-backups + delete the search.colorways template.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Y6Dz4NMwA1ekVm591JgfPT
---
.../theme-files/snippets/colorway-siblings.liquid | 189 ++++++++++++---------
.../theme-files/templates/search.colorways.liquid | 23 +++
2 files changed, 130 insertions(+), 82 deletions(-)
diff --git a/shopify/theme-files/snippets/colorway-siblings.liquid b/shopify/theme-files/snippets/colorway-siblings.liquid
index 40613792..fc681da6 100644
--- a/shopify/theme-files/snippets/colorway-siblings.liquid
+++ b/shopify/theme-files/snippets/colorway-siblings.liquid
@@ -1,9 +1,12 @@
{% comment %}
- Colorway Siblings — shows other colors of the same pattern as clickable thumbnails
- Uses dwc.pattern_name metafield or parses from title
+ Colorway Siblings — shows other colors of the same pattern as clickable thumbnails.
+ TK-11240 rewrite: groups by the custom.pattern_name metafield (title-prefix fallback),
+ reads the full sibling set via the `colorways` search JSON view (no 10/24 truncation),
+ and labels each swatch from custom.color / dwc.color (title- or SKU-derived fallback),
+ never the literal string "View". Fails safe: any error just hides the section.
{% endcomment %}
-{%- assign pattern_name = product.metafields.custom.pattern_name.value | default: product.metafields.dwc.pattern_name.value | default: product.metafields.custom.design_name.value -%}
+{%- assign pattern_name = product.metafields.custom.pattern_name.value | default: product.metafields.dwc.pattern_name.value | default: product.metafields.global.pattern_name.value | default: product.metafields.custom.design_name.value -%}
{%- unless pattern_name != blank -%}
{%- assign pattern_parts = product.title | split: " - " -%}
@@ -34,84 +37,106 @@
(function() {
var currentHandle = {{ product.handle | json }};
var currentVendor = {{ product.vendor | json }};
- var searchTerm = {{ pattern_name | json }};
- if (!searchTerm || searchTerm.length < 3) return;
-
- fetch('/search/suggest.json?q=' + encodeURIComponent(searchTerm) + '&resources[type]=product&resources[limit]=24', { credentials: 'same-origin' })
- .then(function(r) { return r.ok ? r.json() : null; })
- .then(function(data) {
- if (!data || !data.resources || !data.resources.results) return;
- var products = data.resources.results.products || [];
- var matchLower = searchTerm.toLowerCase();
- var container = document.getElementById('dw-colorway-thumbs');
- var section = document.getElementById('dw-colorway-siblings');
- if (!container || !section) return;
-
- var siblings = [];
- for (var i = 0; i < products.length; i++) {
- var p = products[i];
- /* Skip current product */
- if (p.handle === currentHandle) continue;
- /* Must match pattern name in title */
- if ((p.title || '').toLowerCase().indexOf(matchLower) < 0) continue;
- /* Must match vendor to avoid cross-vendor contamination */
- if (currentVendor && (p.vendor || '').toLowerCase() !== currentVendor.toLowerCase()) continue;
- /* Must have an image */
- if (!p.image && !(p.featured_image && p.featured_image.url)) continue;
-
- var imgUrl = (p.featured_image && p.featured_image.url) ? p.featured_image.url : p.image;
-
- /* Extract color: remove pattern name and vendor */
- var label = (p.title || '');
- var pipeIdx = label.indexOf(' | ');
- if (pipeIdx > 0) label = label.substring(0, pipeIdx);
- var dashIdx = label.indexOf(' - ');
- if (dashIdx > 0) {
- label = label.substring(dashIdx + 3).trim();
- } else {
- var pLower = label.toLowerCase().indexOf(matchLower);
- if (pLower === 0) label = label.substring(searchTerm.length).trim();
- }
- label = label.replace(/\s*(Wallcoverings?|Fabrics?|Murals?|Commercial)\s*/gi, '').trim();
- if (!label) label = 'View';
-
- siblings.push({ color: label, image: imgUrl, url: p.url || ('/products/' + p.handle) });
- }
-
- if (siblings.length === 0) return;
- siblings.sort(function(a, b) { return a.color.localeCompare(b.color); });
-
- for (var j = 0; j < siblings.length; j++) {
- var s = siblings[j];
- var a = document.createElement('a');
- a.href = s.url;
- a.title = s.color;
- a.style.cssText = 'display:flex;flex-direction:column;align-items:center;gap:4px;text-decoration:none;width:72px;';
-
- var wrap = document.createElement('div');
- wrap.style.cssText = 'width:64px;height:64px;border-radius:8px;overflow:hidden;border:2px solid #e5e2dc;transition:border-color 0.15s,box-shadow 0.15s;';
- a.onmouseover = function() { this.firstChild.style.borderColor = '#3D4246'; this.firstChild.style.boxShadow = '0 2px 8px rgba(0,0,0,0.1)'; };
- a.onmouseout = function() { this.firstChild.style.borderColor = '#e5e2dc'; this.firstChild.style.boxShadow = 'none'; };
-
- var img = document.createElement('img');
- img.src = s.image;
- img.alt = s.color;
- img.loading = 'lazy';
- img.style.cssText = 'width:100%;height:100%;object-fit:cover;';
- wrap.appendChild(img);
- a.appendChild(wrap);
-
- var nameSpan = document.createElement('span');
- nameSpan.textContent = s.color;
- nameSpan.style.cssText = 'font-size:10px;color:#666;line-height:1.2;max-width:72px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;display:block;text-align:center;';
- a.appendChild(nameSpan);
-
- container.appendChild(a);
- }
-
- section.style.display = '';
- })
- .catch(function() {});
+ var patternName = {{ pattern_name | json }};
+ if (!patternName || patternName.length < 3) return;
+
+ function norm(s){ return (s||'').toString().replace(/\s+/g,' ').trim().toLowerCase(); }
+
+ /* Pattern name from a sibling's title when it has no metafield (the ~234 legacy set). */
+ function titlePattern(t){
+ t = t || '';
+ var seps = [' - ', ' – ', ' | '];
+ for (var i=0;i<seps.length;i++){ var ix=t.indexOf(seps[i]); if (ix>0) return t.substring(0,ix).trim(); }
+ return t.trim();
+ }
+
+ /* Human colour label — never the literal "View". */
+ function colorLabel(p){
+ if (p.color && p.color.trim()) return p.color.trim();
+ var t = p.title || '';
+ var pipe = t.indexOf(' | '); if (pipe>0) t = t.substring(0,pipe);
+ var lbl = '';
+ var dash = t.indexOf(' - ');
+ if (dash>0) { lbl = t.substring(dash+3).trim(); }
+ else {
+ var pi = norm(t).indexOf(norm(patternName));
+ if (pi===0) lbl = t.substring(patternName.length).trim();
+ }
+ lbl = lbl.replace(/\s*(Wallcoverings?|Fabrics?|Murals?|Commercial)\s*/gi,'').trim();
+ if (lbl) return lbl;
+ /* SKU colour-code fallback (base SKU, strip -yard/-sample) */
+ if (p.sku){ var base = p.sku.replace(/-(yard|sample)$/i,''); if (base) return base; }
+ return (p.title || '').trim() || patternName;
+ }
+
+ var wantPattern = norm(patternName);
+ var wantVendor = norm(currentVendor);
+ var MAX_PAGES = 8; /* 8*50 = 400 siblings ceiling; no pattern is that large */
+
+ function fetchPage(q, n){
+ var url = '/search?type=product&view=colorways&page=' + n + '&q=' + encodeURIComponent(q);
+ return fetch(url, { credentials:'same-origin' })
+ .then(function(r){ return r.ok ? r.text() : null; })
+ .then(function(txt){ if(!txt) return null; try { return JSON.parse(txt); } catch(e){ return null; } });
+ }
+
+ /* Quoted phrase keeps the exact-pattern siblings clustered in the top pages
+ (unquoted spreads them across ~20 relevance-ranked pages). Fall back to
+ unquoted only if the quoted phrase returns nothing. */
+ fetchPage('"' + patternName + '"', 1).then(function(first){
+ if (first && first.products && first.products.length) return { q:'"'+patternName+'"', first:first };
+ return fetchPage(patternName, 1).then(function(f2){ return { q:patternName, first:f2 }; });
+ }).then(function(ctx){
+ var first = ctx.first;
+ if (!first || !first.products) return null;
+ var pages = Math.min(first.pages || 1, MAX_PAGES);
+ if (pages <= 1) return [first];
+ var rest = [];
+ for (var n=2; n<=pages; n++) rest.push(fetchPage(ctx.q, n));
+ return Promise.all(rest).then(function(more){ return [first].concat(more.filter(Boolean)); });
+ }).then(function(pageObjs){
+ if (!pageObjs) return;
+ var seen = {}, siblings = [];
+ pageObjs.forEach(function(pg){
+ (pg.products || []).forEach(function(p){
+ if (!p || !p.handle || seen[p.handle]) return;
+ if (p.handle === currentHandle) return;
+ if (!p.image) return;
+ if (wantVendor && norm(p.vendor) !== wantVendor) return;
+ var sibPattern = norm(p.pattern_name) || norm(titlePattern(p.title));
+ if (sibPattern !== wantPattern) return;
+ seen[p.handle] = true;
+ siblings.push({ color: colorLabel(p), image: p.image, url: p.url || ('/products/' + p.handle) });
+ });
+ });
+ if (!siblings.length) return;
+ siblings.sort(function(a,b){ return a.color.localeCompare(b.color); });
+
+ var container = document.getElementById('dw-colorway-thumbs');
+ var section = document.getElementById('dw-colorway-siblings');
+ if (!container || !section) return;
+
+ for (var j=0; j<siblings.length; j++){
+ var s = siblings[j];
+ var a = document.createElement('a');
+ a.href = s.url; a.title = s.color;
+ a.style.cssText = 'display:flex;flex-direction:column;align-items:center;gap:4px;text-decoration:none;width:72px;';
+ var wrap = document.createElement('div');
+ wrap.style.cssText = 'width:64px;height:64px;border-radius:8px;overflow:hidden;border:2px solid #e5e2dc;transition:border-color 0.15s,box-shadow 0.15s;';
+ a.onmouseover = function(){ this.firstChild.style.borderColor='#3D4246'; this.firstChild.style.boxShadow='0 2px 8px rgba(0,0,0,0.1)'; };
+ a.onmouseout = function(){ this.firstChild.style.borderColor='#e5e2dc'; this.firstChild.style.boxShadow='none'; };
+ var img = document.createElement('img');
+ img.src = s.image; img.alt = s.color; img.loading='lazy';
+ img.style.cssText = 'width:100%;height:100%;object-fit:cover;';
+ wrap.appendChild(img); a.appendChild(wrap);
+ var nameSpan = document.createElement('span');
+ nameSpan.textContent = s.color;
+ nameSpan.style.cssText = 'font-size:10px;color:#666;line-height:1.2;max-width:72px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;display:block;text-align:center;';
+ a.appendChild(nameSpan);
+ container.appendChild(a);
+ }
+ section.style.display = '';
+ }).catch(function(){});
})();
</script>
-{%- endif -%}
\ No newline at end of file
+{%- endif -%}
diff --git a/shopify/theme-files/templates/search.colorways.liquid b/shopify/theme-files/templates/search.colorways.liquid
new file mode 100644
index 00000000..d96eb36b
--- /dev/null
+++ b/shopify/theme-files/templates/search.colorways.liquid
@@ -0,0 +1,23 @@
+{% comment %}
+ TK-11240 — Colorways search JSON view.
+ Emits sibling products for the "Other Colorways" module WITH their real metafields
+ (custom.pattern_name / custom.color) so the module can group by pattern_name exactly
+ and label swatches by color — neither of which /search/suggest.json exposes.
+ Fetched by snippets/colorway-siblings.liquid as:
+ /search?q=<pattern>&type=product&view=colorways&page=N
+ Paginated (50/page) so the full sibling set is reachable (no 10/24 truncation).
+{% endcomment %}
+{%- layout none -%}
+{%- paginate search.results by 50 -%}
+{"page":{{ paginate.current_page }},"pages":{{ paginate.pages }},"total":{{ search.results_count | default: 0 }},"products":[
+{%- assign first = true -%}
+{%- for item in search.results -%}
+ {%- if item.object_type == 'product' -%}
+ {%- unless first %},{% endunless -%}{%- assign first = false -%}
+ {%- assign pn = item.metafields.custom.pattern_name.value | default: item.metafields.dwc.pattern_name.value | default: item.metafields.global.pattern_name.value -%}
+ {%- assign cl = item.metafields.custom.color.value | default: item.metafields.dwc.color.value -%}
+ {"handle":{{ item.handle | json }},"url":{{ item.url | json }},"title":{{ item.title | json }},"vendor":{{ item.vendor | json }},"image":{%- if item.featured_image -%}{{ item.featured_image | image_url: width: 200 | json }}{%- else -%}null{%- endif -%},"pattern_name":{{ pn | json }},"color":{{ cl | json }},"sku":{{ item.variants.first.sku | json }}}
+ {%- endif -%}
+{%- endfor -%}
+]}
+{%- endpaginate -%}
← 480c254a Stock new cadence drafts with verified inventory and scoped
·
back to Designer Wallcoverings
·
auto-data-snapshot: 2026-09-11T08:57:34 (21 data files) — DW eca00056 →