← back to Designer Wallcoverings
auto-save: 2026-06-22T23:18:24 (7 files) — shopify/theme-5.0-duplicate/assets/boost-sd-custom.css shopify/theme-5.0-duplicate/assets/dw-pdp-size-pills.js shopify/theme-5.0-duplicate/assets/theme.css.liquid shopify/theme-5.0-duplicate/sections/collection.liquid shopify/theme-5.0-duplicate/snippets/product-description-meta.liquid
4c6dcdefb92470299bcbe162fa23fd8b53edee0c · 2026-06-22 23:18:29 -0700 · Steve Abrams
Files touched
A shopify/push-collection-header-bg.shA shopify/scripts/strip-tres-tintas-embedded-specs.jsM shopify/theme-5.0-duplicate/assets/boost-sd-custom.cssM shopify/theme-5.0-duplicate/assets/dw-pdp-size-pills.jsM shopify/theme-5.0-duplicate/assets/theme.css.liquidM shopify/theme-5.0-duplicate/sections/collection.liquidM shopify/theme-5.0-duplicate/snippets/product-description-meta.liquid
Diff
commit 4c6dcdefb92470299bcbe162fa23fd8b53edee0c
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Mon Jun 22 23:18:29 2026 -0700
auto-save: 2026-06-22T23:18:24 (7 files) — shopify/theme-5.0-duplicate/assets/boost-sd-custom.css shopify/theme-5.0-duplicate/assets/dw-pdp-size-pills.js shopify/theme-5.0-duplicate/assets/theme.css.liquid shopify/theme-5.0-duplicate/sections/collection.liquid shopify/theme-5.0-duplicate/snippets/product-description-meta.liquid
---
shopify/push-collection-header-bg.sh | 72 ++++++++
.../scripts/strip-tres-tintas-embedded-specs.js | 198 +++++++++++++++++++++
.../theme-5.0-duplicate/assets/boost-sd-custom.css | 22 +++
.../assets/dw-pdp-size-pills.js | 23 +++
.../theme-5.0-duplicate/assets/theme.css.liquid | 37 +++-
.../theme-5.0-duplicate/sections/collection.liquid | 2 +-
.../snippets/product-description-meta.liquid | 6 +-
7 files changed, 353 insertions(+), 7 deletions(-)
diff --git a/shopify/push-collection-header-bg.sh b/shopify/push-collection-header-bg.sh
new file mode 100644
index 00000000..e7a39502
--- /dev/null
+++ b/shopify/push-collection-header-bg.sh
@@ -0,0 +1,72 @@
+#!/usr/bin/env bash
+# Push collection-header readability fix to Shopify LIVE theme
+# - .page-title / .breadcrumbs / .collection-description: inline-block → block + fit-content
+# (fixes disappearing headers: auto-margins now center, dark box always paints)
+# - sections/collection.liquid: server-side description display:inline-block → block + fit-content
+set -euo pipefail
+cd "$(dirname "$0")"
+
+STORE="designer-laboratory-sandbox.myshopify.com"
+API="2024-10"
+SECRETS="$HOME/Projects/secrets-manager/.env"
+
+TOK="${THEME_TOKEN:-$(grep -hE '^SHOPIFY_THEME_TOKEN=' "$SECRETS" 2>/dev/null | head -1 | cut -d= -f2- | tr -d '"'"'"' ')}"
+[ -z "$TOK" ] && { echo "❌ No theme token. Get SHOPIFY_THEME_TOKEN from secrets"; exit 1; }
+echo "✓ token …${TOK: -4}"
+mkdir -p theme-backups
+
+python3 - "$STORE" "$API" "$TOK" <<'PY'
+import sys, json, urllib.request, urllib.error, os.path, datetime
+
+store, api, tok = sys.argv[1:4]
+H = {"X-Shopify-Access-Token": tok, "Content-Type": "application/json"}
+stamp = datetime.datetime.now().strftime("%Y%m%d-%H%M%S")
+
+def api_get(url):
+ try:
+ return json.load(urllib.request.urlopen(urllib.request.Request(url, headers=H)))
+ except urllib.error.HTTPError as e:
+ print(f"❌ API GET failed: {e.code} {e.read().decode()[:200]}"); sys.exit(1)
+
+def api_put(url, data):
+ try:
+ req = urllib.request.Request(url, data=json.dumps(data).encode(), headers=H, method='PUT')
+ return json.load(urllib.request.urlopen(req))
+ except urllib.error.HTTPError as e:
+ print(f"❌ API PUT failed: {e.code} {e.read().decode()[:400]}"); sys.exit(1)
+
+themes = api_get(f"https://{store}/admin/api/{api}/themes.json")["themes"]
+live = [t for t in themes if t["role"] == "main"][0]
+tid = live["id"]
+print(f"✓ LIVE theme: {live['name']} (ID: {tid})")
+
+files = {
+ "assets/theme.css.liquid": "theme-5.0-duplicate/assets/theme.css.liquid",
+ "sections/collection.liquid": "theme-5.0-duplicate/sections/collection.liquid",
+}
+
+for key, local in files.items():
+ if not os.path.isfile(local):
+ print(f"❌ missing: {local}"); sys.exit(1)
+ content = open(local).read()
+ # backup current live version
+ try:
+ cur = api_get(f"https://{store}/admin/api/{api}/themes/{tid}/assets.json?asset[key]={key}")["asset"]["value"]
+ bk = f"theme-backups/{key.replace('/','__')}.{tid}.{stamp}.bak"
+ open(bk, "w").write(cur)
+ print(f" backup → {bk} ({len(cur)} bytes)")
+ except Exception as e:
+ print(f" backup skip: {e}")
+ print(f"📝 PUT {key} ({len(content)} bytes)...")
+ r = api_put(f"https://{store}/admin/api/{api}/themes/{tid}/assets.json",
+ {"asset": {"key": key, "value": content}})
+ if "asset" not in r:
+ print(f" ❌ failed: {r}"); sys.exit(1)
+ # spot-verify
+ chk = api_get(f"https://{store}/admin/api/{api}/themes/{tid}/assets.json?asset[key]={key}")["asset"]["value"]
+ fc = chk.count("fit-content")
+ print(f" ✓ uploaded — 'fit-content' occurrences live: {fc}")
+
+print("\n✅ LIVE: collection headers now block+fit-content (centered, dark box always visible)")
+print("Verify: https://www.designerwallcoverings.com/collections/baroque-wallpaper")
+PY
diff --git a/shopify/scripts/strip-tres-tintas-embedded-specs.js b/shopify/scripts/strip-tres-tintas-embedded-specs.js
new file mode 100644
index 00000000..9eb7596f
--- /dev/null
+++ b/shopify/scripts/strip-tres-tintas-embedded-specs.js
@@ -0,0 +1,198 @@
+#!/usr/bin/env node
+/**
+ * strip-tres-tintas-embedded-specs.js
+ *
+ * Tres Tintas products carry the vendor spec table baked into body_html, while
+ * the theme also renders a metafield-driven `dw-specs` block — so specs show
+ * TWICE (the "doubling" regression). This sweep, per Steve's rule "add the 3 as
+ * metafields FIRST, then strip", does for each affected product:
+ *
+ * 1. Parse the embedded <table> (label -> value).
+ * 2. Backfill any spec the dw-specs block needs but lacks as a metafield —
+ * specifically Weight -> custom.product_weight, Care -> global.Cleaning,
+ * Origin -> global.Country (the consistent gap; Width/Length/Repeat/
+ * Material/Fire already render from existing metafields). Pattern ref ->
+ * a `pattern-<ref>` tag (never lost), per the earlier single-product rule.
+ * 3. Strip the <h3>Specifications</h3>…</table> block from body_html,
+ * keeping the prose intro. Original body_html is backed up to disk.
+ *
+ * Idempotent: a product whose body_html no longer has the table is skipped.
+ * DRY RUN by default — set APPLY=1 to write. Backs up every original.
+ *
+ * node strip-tres-tintas-embedded-specs.js # dry run (no writes)
+ * APPLY=1 node strip-tres-tintas-embedded-specs.js # execute
+ * LIMIT=3 node strip-tres-tintas-embedded-specs.js # only first N (testing)
+ */
+const fs = require('fs');
+const path = require('path');
+
+const STORE = 'designer-laboratory-sandbox.myshopify.com';
+const APPLY = process.env.APPLY === '1';
+const LIMIT = process.env.LIMIT ? parseInt(process.env.LIMIT, 10) : Infinity;
+const API = '2024-01';
+
+// Token: SHOPIFY_DRAFT_TOKEN (proven read+write_products scope this session)
+function token() {
+ const env = fs.readFileSync(path.join(process.env.HOME, 'Projects/secrets-manager/.env'), 'utf8');
+ const m = env.match(/^SHOPIFY_DRAFT_TOKEN=["']?([^"'\n]+)/m);
+ if (!m) throw new Error('SHOPIFY_DRAFT_TOKEN not found');
+ return m[1].trim();
+}
+const TOKEN = token();
+const H = { 'X-Shopify-Access-Token': TOKEN, 'Content-Type': 'application/json' };
+
+const BACKUP_DIR = path.join(__dirname, '..', 'tres-tintas-strip-backups');
+fs.mkdirSync(BACKUP_DIR, { recursive: true });
+
+const sleep = (ms) => new Promise(r => setTimeout(r, ms));
+
+async function gql(query, variables) {
+ const res = await fetch(`https://${STORE}/admin/api/${API}/graphql.json`, {
+ method: 'POST', headers: H, body: JSON.stringify({ query, variables }),
+ });
+ const j = await res.json();
+ if (j.errors) throw new Error(JSON.stringify(j.errors));
+ return j.data;
+}
+
+// Parse <th>Label</th><td>Value</td> rows from the embedded table.
+function parseTable(html) {
+ const rows = {};
+ const re = /<th[^>]*>\s*([^<]+?)\s*<\/th>\s*<td[^>]*>\s*([^<]*?)\s*<\/td>/gi;
+ let m;
+ while ((m = re.exec(html)) !== null) {
+ rows[m[1].trim()] = m[2].trim();
+ }
+ return rows;
+}
+
+// Strip the <h3>Specifications</h3> … </table> block.
+function stripTable(html) {
+ return html
+ .replace(/\s*<h3>\s*Specifications\s*<\/h3>[\s\S]*?<\/table>/i, '')
+ .replace(/\n\s*\n/g, '\n');
+}
+
+// Map embedded-table label -> { namespace, key } for the gap fields.
+const GAP_MAP = {
+ 'Weight': { namespace: 'custom', key: 'product_weight' },
+ 'Care Instructions': { namespace: 'global', key: 'Cleaning' },
+ 'Care': { namespace: 'global', key: 'Cleaning' },
+ 'Origin': { namespace: 'global', key: 'Country' },
+};
+
+async function getMetafields(numericId) {
+ const res = await fetch(`https://${STORE}/admin/api/${API}/products/${numericId}/metafields.json`, { headers: H });
+ const j = await res.json();
+ const set = new Set();
+ for (const mf of (j.metafields || [])) set.add(`${mf.namespace}.${mf.key}`);
+ return set;
+}
+
+async function setMetafield(numericId, namespace, key, value) {
+ const res = await fetch(`https://${STORE}/admin/api/${API}/products/${numericId}/metafields.json`, {
+ method: 'POST', headers: H,
+ body: JSON.stringify({ metafield: { namespace, key, value, type: 'single_line_text_field' } }),
+ });
+ const j = await res.json();
+ if (!j.metafield) throw new Error(`metafield ${namespace}.${key}: ${JSON.stringify(j.errors || j)}`);
+ return j.metafield.id;
+}
+
+async function putBody(numericId, body_html) {
+ const res = await fetch(`https://${STORE}/admin/api/${API}/products/${numericId}.json`, {
+ method: 'PUT', headers: H,
+ body: JSON.stringify({ product: { id: Number(numericId), body_html } }),
+ });
+ const j = await res.json();
+ if (!j.product) throw new Error(`put body: ${JSON.stringify(j.errors || j)}`);
+ return j.product.body_html;
+}
+
+async function main() {
+ console.log(`MODE: ${APPLY ? 'APPLY (writing live)' : 'DRY RUN (no writes)'}${LIMIT !== Infinity ? ` LIMIT=${LIMIT}` : ''}`);
+ const q = `query($cursor:String){ products(first:100, query:"vendor:'Tres Tintas'", after:$cursor){
+ pageInfo{ hasNextPage endCursor } edges{ node{ id title descriptionHtml tags } } } }`;
+
+ let cursor = null, scanned = 0, affected = 0, processed = 0;
+ const mfWouldSet = {}; // tally of gap metafields that would be backfilled
+ const done = [];
+
+ outer:
+ while (true) {
+ const data = await gql(q, { cursor });
+ const conn = data.products;
+ for (const e of conn.edges) {
+ const n = e.node;
+ scanned++;
+ const d = n.descriptionHtml || '';
+ if (!(/<h3>\s*Specifications\s*<\/h3>/i.test(d) && /<table/i.test(d))) continue;
+ affected++;
+ if (processed >= LIMIT) continue;
+
+ const numericId = n.id.split('/').pop();
+ const rows = parseTable(d);
+ const stripped = stripTable(d);
+ if (stripped === d || /<table/i.test(stripped)) {
+ console.log(` !! ${numericId} ${n.title.slice(0,40)} — strip failed, SKIP`);
+ continue;
+ }
+
+ // Which gap metafields are missing?
+ const existing = APPLY ? await getMetafields(numericId) : null;
+ const toSet = [];
+ for (const [label, dest] of Object.entries(GAP_MAP)) {
+ if (rows[label] == null || rows[label] === '') continue;
+ const dotted = `${dest.namespace}.${dest.key}`;
+ if (existing && existing.has(dotted)) continue; // already set, skip
+ toSet.push({ ...dest, value: rows[label], label });
+ mfWouldSet[dotted] = (mfWouldSet[dotted] || 0) + 1;
+ }
+ // Pattern ref -> tag
+ const pref = rows['Pattern ref.'] || rows['Pattern Ref.'] || rows['Pattern Reference'];
+ const tags = (n.tags || []);
+ const prefTag = pref ? `pattern-ref-${pref}` : null;
+ const needPrefTag = prefTag && !tags.includes(prefTag);
+
+ processed++;
+ if (processed <= 5 || !APPLY && processed <= 12) {
+ console.log(` ${numericId} ${n.title.slice(0,42)}`);
+ console.log(` table fields: ${Object.keys(rows).join(', ')}`);
+ console.log(` backfill: ${toSet.map(t => `${t.namespace}.${t.key}="${t.value}"`).join('; ') || '(none — all present)'}`);
+ if (needPrefTag) console.log(` +tag: ${prefTag}`);
+ }
+
+ if (APPLY) {
+ // Backup original body_html
+ fs.writeFileSync(path.join(BACKUP_DIR, `${numericId}.body_html.bak`), d);
+ for (const t of toSet) {
+ try { await setMetafield(numericId, t.namespace, t.key, t.value); }
+ catch (err) { console.log(` metafield err ${t.namespace}.${t.key}: ${err.message}`); }
+ await sleep(120);
+ }
+ if (needPrefTag) {
+ await fetch(`https://${STORE}/admin/api/${API}/products/${numericId}.json`, {
+ method: 'PUT', headers: H,
+ body: JSON.stringify({ product: { id: Number(numericId), tags: tags.concat(prefTag).join(', ') } }),
+ });
+ await sleep(120);
+ }
+ await putBody(numericId, stripped);
+ await sleep(150);
+ done.push(numericId);
+ }
+ }
+ if (conn.pageInfo.hasNextPage && processed < LIMIT) cursor = conn.pageInfo.endCursor;
+ else break;
+ }
+
+ console.log(`\n--- SUMMARY ---`);
+ console.log(`scanned: ${scanned}`);
+ console.log(`affected: ${affected} (have embedded table)`);
+ console.log(`processed: ${processed}${APPLY ? ` (written: ${done.length})` : ' (dry run — nothing written)'}`);
+ console.log(`metafield backfills ${APPLY ? 'set' : 'that WOULD be set'}:`);
+ for (const [k, c] of Object.entries(mfWouldSet)) console.log(` ${k}: ${c}`);
+ if (APPLY) console.log(`backups -> ${BACKUP_DIR}`);
+}
+
+main().catch(e => { console.error(e); process.exit(1); });
diff --git a/shopify/theme-5.0-duplicate/assets/boost-sd-custom.css b/shopify/theme-5.0-duplicate/assets/boost-sd-custom.css
index f6db9da1..00645bff 100644
--- a/shopify/theme-5.0-duplicate/assets/boost-sd-custom.css
+++ b/shopify/theme-5.0-duplicate/assets/boost-sd-custom.css
@@ -92,3 +92,25 @@ s.money,
.dw-vendor-link {
text-align: center !important;
}
+
+/* ── Collection header readability (Steve 2026-06-22) ──────────────────
+ Boost renders the collection title + description overlaid on the hero
+ background image. Put the text on a 50% opaque dark panel so it stays
+ readable over any image, and center it. One cohesive box behind both
+ the title and the description. */
+.boost-sd__header-main-2-content {
+ background-color: rgba(0, 0, 0, 0.5) !important;
+ padding: 26px 36px !important;
+ border-radius: 6px !important;
+ display: inline-block !important;
+ width: -webkit-fit-content !important;
+ width: fit-content !important;
+ max-width: 92% !important;
+}
+.boost-sd__header-title,
+.boost-sd__header-description,
+.boost-sd__header-description *,
+.boost-sd__header-main-2-content .collection-description,
+.boost-sd__header-main-2-content .collection-description * {
+ color: #ffffff !important;
+}
diff --git a/shopify/theme-5.0-duplicate/assets/dw-pdp-size-pills.js b/shopify/theme-5.0-duplicate/assets/dw-pdp-size-pills.js
index 8a96effc..ec1860c3 100644
--- a/shopify/theme-5.0-duplicate/assets/dw-pdp-size-pills.js
+++ b/shopify/theme-5.0-duplicate/assets/dw-pdp-size-pills.js
@@ -85,12 +85,35 @@
anchor.parentNode.insertBefore(wrap, anchor);
}
+ // Move the Spec Sheet button up to sit next to the SAMPLE pill
+ // (Steve, 2026-06-22: "move spec sheet next to the sample pill").
+ addSpecSheetPill(wrap);
+
// Keep pills in sync if the select changes from any other source.
select.addEventListener('change', function () {
syncActive(wrap, select);
});
}
+ // Relocate the existing CTA-row "Spec Sheet" link into the size-pill row as a
+ // matching outlined pill, immediately after the size options (ROLL / SAMPLE).
+ // Reuses the original link's href (already carries the product handle) and
+ // removes the CTA-row duplicate so it appears once, beside the SAMPLE pill.
+ function addSpecSheetPill(wrap) {
+ if (!wrap || document.querySelector('.dw-spec-pill')) return; // one per page
+ var src = document.querySelector('.spec-sheet-btn');
+ if (!src || !src.getAttribute('href')) return; // no spec sheet → skip
+ var pill = document.createElement('a');
+ pill.className = 'dw-size-pill dw-spec-pill';
+ pill.setAttribute('role', 'link');
+ pill.href = src.getAttribute('href');
+ pill.target = '_blank';
+ pill.rel = 'noopener';
+ pill.textContent = 'Spec Sheet';
+ wrap.appendChild(pill);
+ if (src.parentNode) { src.parentNode.removeChild(src); } // drop CTA-row dup
+ }
+
function syncActive(wrap, select) {
var val = select.value;
Array.prototype.forEach.call(wrap.querySelectorAll('.dw-size-pill'), function (b) {
diff --git a/shopify/theme-5.0-duplicate/assets/theme.css.liquid b/shopify/theme-5.0-duplicate/assets/theme.css.liquid
index 7a14144b..c85addc6 100644
--- a/shopify/theme-5.0-duplicate/assets/theme.css.liquid
+++ b/shopify/theme-5.0-duplicate/assets/theme.css.liquid
@@ -1798,7 +1798,9 @@ h6 {
background-color: rgba(0, 0, 0, 0.5);
color: #ffffff;
border-radius: 4px;
- display: inline-block;
+ display: block;
+ width: -webkit-fit-content;
+ width: fit-content;
max-width: 90%;
margin-left: auto;
margin-right: auto;
@@ -3481,13 +3483,40 @@ iframe {
color: #ffffff;
padding: 20px 30px;
border-radius: 4px;
- display: inline-block;
+ display: block;
+ width: -webkit-fit-content;
+ width: fit-content;
max-width: 90%;
}
.collection-header-alternate .collection-description {
max-width: 90%;
}
+/* Boost AI Search & Discovery collection header: the title + description are
+ overlaid on the hero background image. Put each text block on its own 50%
+ opaque dark panel so it stays readable over any image (Steve 2026-06-22).
+ Per-element (not the wrapper) — the wrapper's width collapses and won't
+ cover the wider description text. */
+.boost-sd__header-title {
+ display: inline-block !important;
+ background-color: rgba(0, 0, 0, 0.55) !important;
+ color: #ffffff !important;
+ padding: 10px 24px !important;
+ border-radius: 6px !important;
+}
+.boost-sd__header-description {
+ display: inline-block !important;
+ background-color: rgba(0, 0, 0, 0.55) !important;
+ color: #ffffff !important;
+ padding: 16px 28px !important;
+ border-radius: 6px !important;
+ max-width: 92% !important;
+ margin-top: 10px !important;
+}
+.boost-sd__header-description * {
+ color: #ffffff !important;
+}
+
@media (min-width: 770px) {
.collection-sorting__wrapper:only-child {
margin-right: 0;
@@ -8411,7 +8440,9 @@ shopify-payment-terms {
font-size: 1rem;
background-color: rgba(0, 0, 0, 0.5);
border-radius: 4px;
- display: inline-block;
+ display: block;
+ width: -webkit-fit-content;
+ width: fit-content;
max-width: 90%;
}
.breadcrumbs a {
diff --git a/shopify/theme-5.0-duplicate/sections/collection.liquid b/shopify/theme-5.0-duplicate/sections/collection.liquid
index c73a9bdd..c63ae7fe 100644
--- a/shopify/theme-5.0-duplicate/sections/collection.liquid
+++ b/shopify/theme-5.0-duplicate/sections/collection.liquid
@@ -1,6 +1,6 @@
{%- comment -%} DW: render the collection description server-side (theme JS never did). Respects the existing show_description setting; reversible. {%- endcomment -%}
{%- if section.settings.show_description and collection.description != blank -%}
- <div class="dw-collection-description rte" style="max-width:880px;margin:30px auto;padding:30px 40px;line-height:1.7;color:#ffffff;background-color:rgba(0,0,0,0.5);border-radius:4px;display:inline-block;">
+ <div class="dw-collection-description rte" style="max-width:880px;width:-webkit-fit-content;width:fit-content;margin:30px auto;padding:30px 40px;line-height:1.7;color:#ffffff;background-color:rgba(0,0,0,0.5);border-radius:4px;display:block;">
{{ collection.description }}
</div>
{%- endif -%}
diff --git a/shopify/theme-5.0-duplicate/snippets/product-description-meta.liquid b/shopify/theme-5.0-duplicate/snippets/product-description-meta.liquid
index 2b7c4150..457d1661 100644
--- a/shopify/theme-5.0-duplicate/snippets/product-description-meta.liquid
+++ b/shopify/theme-5.0-duplicate/snippets/product-description-meta.liquid
@@ -15,20 +15,20 @@
{% assign col = product.metafields.custom.collection_name | default: product.metafields.specs.collection | default: product.metafields.global.Collection %}
{% assign rep = product.metafields.custom.pattern_repeat | default: product.metafields.global.repeat | default: product.metafields.global['Vert-Rpt'] %}
{% assign fin = product.metafields.custom.finish | default: product.metafields.specs.finish | default: product.metafields.global.Finish | default: product.metafields.global.FINISH %}
-{% assign care = product.metafields.custom.care | default: product.metafields.specs.care | default: product.metafields.global.Cleaning | default: product.metafields.global['Clean-Code'] | default: product.metafields.global['Cleaning-Code'] %}
+{% assign care = product.metafields.custom.care | default: product.metafields.specs.care | default: product.metafields.global.Cleaning | default: product.metafields.global.cleaning | default: product.metafields.global['Clean-Code'] | default: product.metafields.global['Cleaning-Code'] %}
{% assign fire = product.metafields.custom.fire_rating | default: product.metafields.specs.fire_rating | default: product.metafields.global.fire_rating | default: product.metafields.global.FLAMMABILITY %}
{% assign match = product.metafields.custom.match_type | default: product.metafields.specs.match_type | default: product.metafields.global.MATCH | default: product.metafields.global.Match %}
{% assign app = product.metafields.custom.application | default: product.metafields.specs.application | default: product.metafields.global.application %}
{% assign len = product.metafields.custom.length | default: product.metafields.global.length | default: product.metafields.global.Length %}
{% assign pkg = product.metafields.custom.packaging | default: product.metafields.global.packaged | default: product.metafields.global.Packaged %}
{% assign uom = product.metafields.custom.unit_of_measure | default: product.metafields.global.unit_of_measure %}
-{% assign coo = product.metafields.custom.origin | default: product.metafields.global.Country | default: product.metafields.global['Country-of-Origin'] %}
+{% assign coo = product.metafields.custom.origin | default: product.metafields.global.Country | default: product.metafields.global.country | default: product.metafields.global['Country-of-Origin'] %}
{% assign dur = product.metafields.custom.wyzenbeek | default: product.metafields.global['Wyzenbeek-#'] %}
{% assign mart = product.metafields.custom.martindale | default: product.metafields.global['Martindale-#'] %}
{% assign abr = product.metafields.custom.abrasion | default: product.metafields.specs.abrasion %}
{% assign bk = product.metafields.custom.backing | default: product.metafields.specs.backing | default: product.metafields.global.Substrate | default: product.metafields.global.substrate %}
{% assign brand = product.metafields.custom.brand | default: product.metafields.global.Brand %}
-{% assign wt = product.metafields.custom.product_weight | default: product.metafields.global.Weight %}
+{% assign wt = product.metafields.custom.product_weight | default: product.metafields.global.Weight | default: product.metafields.global.weight %}
{% if w != blank or mat != blank or col != blank %}{% assign has_specs = true %}{% endif %}
← 28aef168 auto-save: 2026-06-22T22:48:18 (1 files) — shopify/theme-5.0
·
back to Designer Wallcoverings
·
auto-save: 2026-06-23T00:18:39 (3 files) — shopify/scripts/d f6663c20 →