← back to Dw Theme Hamburger
sections/product.liquid
718 lines
{% render 'breadcrumbs' %}
{% liquid
assign enable_zoom = section.settings.enable_zoom
assign enable_cart_redirection = section.settings.enable_cart_redirection
assign images_layout = section.settings.images_layout
assign enable_video_autoplay = section.settings.enable_video_autoplay
assign enable_video_looping = section.settings.enable_video_looping
assign enable_linked_options = true
assign show_vendor = settings.show_vendor
assign show_social_media_icons = section.settings.show_social_media_icons
assign show_payment_button = section.settings.show_payment_button
for block in section.blocks
if block.type == 'complementary_products'
assign product_recommendation_limit = block.settings.product_recommendation_limit
break
endif
endfor
%}
{% if images_layout == 'masonry' %}
{% comment %}Related products in masonry grid must be below product{% endcomment %}
{% assign related_products_position_right = false %}
{% endif %}
<script
type="application/json"
data-section-type="product"
data-section-id="{{ section.id }}"
data-section-data
>
{
"product": {{ product | json }},
"product_settings": {
"addToCartText": {{ 'products.product.add_to_cart' | t | json }},
"enableHistory": true,
"processingText": {{ 'products.product.processing' | t | json }},
"setQuantityText": {{ 'products.product.set_quantity' | t | json }},
"soldOutText": {{ 'products.product.sold_out' | t | json }},
"unavailableText": {{ 'products.product.unavailable' | t | json }}
},
"images_layout": {{ images_layout | json }},
"enable_zoom": {{ enable_zoom | json }},
"enable_video_autoplay": {{ enable_video_autoplay | json }},
"enable_video_looping": {{ enable_video_looping | json }},
"enable_cart_redirection": {{ enable_cart_redirection | json }},
"enable_fixed_positioning": true,
"product_recommendation_limit": {{ product_recommendation_limit | json }}
}
</script>
{% render 'product-success-labels' %}
<section class="product-container">
{%
render 'product',
product: product,
enable_zoom: enable_zoom,
images_layout: images_layout,
enable_linked_options: enable_linked_options,
show_vendor: show_vendor,
show_social_media_icons: show_social_media_icons,
show_payment_button: show_payment_button,
%}
{%- comment -%}
Design Coordinate v6 — Steve's spec:
• Catalog grid: 24 stripe/plaid/check coordinates that use the source palette
• Density slider 3-12 cols (default 8), localStorage-persisted
• AI Generated Coordinates: 24 SVG-poster placeholders seeded from palette
• Vendor picker: SW / DE / BM / F&B (default on) + Behr / PPG / RAL (opt-in)
• Each card shows palette dots + selected vendors' paint chips
Service: https://pairs.designerwallcoverings.com (commit history at ~/Projects/dw-pairs-well)
CSS namespace kept as .pairs-well__* — only the button TEXT is "Design Coordinate".
{%- endcomment -%}
<section
id="pairs-well-with"
class="dc-section"
data-pairs-endpoint="https://pairs.designerwallcoverings.com/api/pairs"
data-ai-endpoint="https://pairs.designerwallcoverings.com/api/ai-coordinates"
data-product-handle="{{ product.handle }}"
{%- comment -%}
2026-06-27 (vp-dw-commerce): data-product-sku must be the DW sku (the
shopify_products.dw_sku key), NOT custom.manufacturer_sku — the MFR sku
never matches the pairs DB and was returning "source not found",
breaking the Design Coordinate panel. Use the variant's DW sku (strip the
-Sample suffix); the pairs API also resolves by handle as a fallback.
{%- endcomment -%}
{%- assign dc_sku = product.selected_or_first_available_variant.sku | default: product.variants.first.sku | replace: '-Sample', '' | replace: '-SAMPLE', '' -%}
data-product-sku="{{ dc_sku | escape }}"
style="margin: 1.5em 0 2em; clear: both;"
hidden
>
<button type="button" class="pairs-well__cta" aria-expanded="false">
<span class="pairs-well__cta-text">Design Coordinate</span>
<span class="pairs-well__cta-icon" aria-hidden="true">+</span>
</button>
<div class="pairs-well__source-palette" id="pairs-well-source-palette" hidden></div>
<div class="pairs-well__vendor-picker" id="pairs-well-vendor-picker" hidden>
<h4>Paint brands</h4>
<div class="chips">
<label><input type="checkbox" value="sw" checked> Sherwin-Williams</label>
<label><input type="checkbox" value="de" checked> Dunn-Edwards</label>
<label><input type="checkbox" value="bm" checked> Benjamin Moore</label>
<label><input type="checkbox" value="fb" checked> Farrow & Ball</label>
<label><input type="checkbox" value="behr" > Behr</label>
<label><input type="checkbox" value="ppg" > PPG</label>
<label><input type="checkbox" value="ral" > RAL</label>
</div>
</div>
<div class="pairs-well__catalog" id="pairs-well-catalog" hidden>
<div class="pairs-well__panel-head">
<h3>Stripes & Plaids from our catalog <span class="count" id="pairs-well-catalog-count"></span></h3>
<div class="pairs-well__controls">
<label for="pairs-well-cols-catalog">Columns</label>
<input id="pairs-well-cols-catalog" type="range" min="3" max="12" value="8" step="1">
<span class="pairs-well__cols-val" id="pairs-well-cols-catalog-val">8</span>
</div>
</div>
<div id="pairs-well-grid" class="pairs-well__grid"></div>
</div>
<div class="pairs-well__ai" id="pairs-well-ai" hidden>
<div class="pairs-well__panel-head">
<h3>AI Generated Coordinates <span class="ai-badge">Preview · 24 options</span></h3>
<div class="pairs-well__controls">
<label for="pairs-well-cols-ai">Columns</label>
<input id="pairs-well-cols-ai" type="range" min="3" max="12" value="8" step="1">
<span class="pairs-well__cols-val" id="pairs-well-cols-ai-val">8</span>
</div>
</div>
<div id="pairs-well-ai-grid" class="pairs-well__grid pairs-well__grid--ai"></div>
</div>
</section>
<style>
#pairs-well-with { font-family: inherit; --cols-catalog: 8; --cols-ai: 8; }
.pairs-well__cta {
display: flex; align-items: center; justify-content: space-between;
width: 100%; padding: 18px 24px; margin: 0;
background: #111; color: #fff;
border: 0; border-radius: 999px;
font-size: 15px; font-weight: 500; letter-spacing: 0.06em;
text-transform: uppercase; cursor: pointer;
transition: background 160ms ease, transform 120ms ease;
}
.pairs-well__cta:hover { background: #2a2a2a; }
.pairs-well__cta:active { transform: scale(0.995); }
.pairs-well__cta[aria-expanded="true"] .pairs-well__cta-icon { transform: rotate(45deg); }
.pairs-well__cta-icon { display: inline-block; font-size: 22px; line-height: 1; transition: transform 200ms ease; }
.pairs-well__source-palette { margin: 18px 0 0; }
.pairs-well__source-palette h4 { margin: 0 0 8px; font-size: 11px; letter-spacing: 0.08em; text-transform: uppercase; color: #777; }
.pairs-well__source-palette table { border-collapse: collapse; width: 100%; font-size: 12px; }
.pairs-well__source-palette th, .pairs-well__source-palette td { text-align: left; padding: 6px 8px; border-bottom: 1px solid #f0ebe2; }
.pairs-well__source-palette th { font-weight: 500; color: #777; font-size: 11px; letter-spacing: 0.06em; text-transform: uppercase; }
.pairs-well__source-palette td.swatch { width: 28px; }
.pw-dot { display: inline-block; width: 18px; height: 18px; border-radius: 50%; border: 1px solid rgba(0,0,0,0.12); vertical-align: middle; }
.pw-square { display: inline-block; width: 13px; height: 13px; border-radius: 3px; border: 1px solid rgba(0,0,0,0.12); vertical-align: middle; margin-right: 4px; }
.pw-code { color: #888; font-variant-numeric: tabular-nums; font-size: 11px; }
.pairs-well__vendor-picker { margin: 18px 0 0; }
.pairs-well__vendor-picker h4 { margin: 0 0 8px; font-size: 11px; letter-spacing: 0.08em; text-transform: uppercase; color: #777; }
.pairs-well__vendor-picker .chips { display: flex; flex-wrap: wrap; gap: 6px; }
.pairs-well__vendor-picker label {
font-size: 12px; padding: 5px 10px; border: 1px solid #e7e7e7; border-radius: 999px;
cursor: pointer; background: #fff; user-select: none;
}
.pairs-well__vendor-picker label:has(input:checked) { background: #1a1a1a; color: #fff; border-color: #1a1a1a; }
.pairs-well__vendor-picker input { display: none; }
.pairs-well__panel-head {
display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap;
gap: 12px; margin: 24px 0 12px;
}
.pairs-well__panel-head h3 { margin: 0; font: 500 18px/1.2 ui-serif, Georgia, serif; }
.pairs-well__panel-head .count { color: #888; font-size: 12px; margin-left: 6px; font-family: -apple-system, sans-serif; font-weight: 400; }
.pairs-well__panel-head .ai-badge {
display: inline-block; padding: 3px 8px; background: #2a2a2a; color: #fff;
border-radius: 999px; font-size: 10px; letter-spacing: 0.08em; text-transform: uppercase;
margin-left: 8px; font-family: -apple-system, sans-serif; font-weight: 600;
}
.pairs-well__controls {
display: flex; align-items: center; gap: 10px;
font-size: 11px; color: #777; text-transform: uppercase; letter-spacing: 0.06em;
}
.pairs-well__controls input[type=range] { width: 160px; accent-color: #1a1a1a; }
.pairs-well__cols-val { font-variant-numeric: tabular-nums; color: #1a1a1a; min-width: 1.5em; text-align: right; font-weight: 600; }
.pairs-well__grid {
display: grid; gap: 14px; margin-top: 6px;
grid-template-columns: repeat(var(--cols-catalog), minmax(0, 1fr));
}
.pairs-well__grid--ai { grid-template-columns: repeat(var(--cols-ai), minmax(0, 1fr)); }
@media (max-width: 1100px) { .pairs-well__grid { grid-template-columns: repeat(min(6, var(--cols-catalog)), minmax(0, 1fr)); } .pairs-well__grid--ai { grid-template-columns: repeat(min(6, var(--cols-ai)), minmax(0, 1fr)); } }
@media (max-width: 900px) { .pairs-well__grid { grid-template-columns: repeat(min(4, var(--cols-catalog)), minmax(0, 1fr)); } .pairs-well__grid--ai { grid-template-columns: repeat(min(4, var(--cols-ai)), minmax(0, 1fr)); } }
@media (max-width: 600px) { .pairs-well__grid { grid-template-columns: repeat(min(2, var(--cols-catalog)), minmax(0, 1fr)); } .pairs-well__grid--ai { grid-template-columns: repeat(min(2, var(--cols-ai)), minmax(0, 1fr)); } }
.pairs-well__card {
display: block; text-decoration: none; color: inherit;
background: #fff; border: 1px solid #e7e7e7; border-radius: 6px;
overflow: hidden; transition: box-shadow 160ms ease, transform 160ms ease;
}
.pairs-well__card:hover { box-shadow: 0 6px 20px rgba(0,0,0,0.08); transform: translateY(-2px); }
.pairs-well__card--ai { border-style: dashed; border-color: #d9c7a8; }
.pairs-well__img-wrap { aspect-ratio: 1 / 1; background: #f4f4f4; overflow: hidden; }
.pairs-well__img { width: 100%; height: 100%; object-fit: cover; display: block; }
.pairs-well__meta { padding: 10px 12px 12px; }
.pairs-well__title { margin: 0 0 4px; font-size: 13px; font-weight: 600; line-height: 1.3; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.pairs-well__vendor { margin: 0 0 6px; font-size: 10px; color: #777; letter-spacing: 0.04em; text-transform: uppercase; }
.pairs-well__why { display: inline-block; padding: 2px 7px; background: #f4ede4; color: #5a4628; border-radius: 999px; font-size: 10px; line-height: 1.4; margin-bottom: 8px; }
.pairs-well__card--ai .pairs-well__why { background: #efe6f5; color: #5b3478; }
.pairs-well__palette { display: flex; gap: 3px; margin: 0 0 8px; flex-wrap: wrap; }
.pairs-well__palette .pw-dot { width: 12px; height: 12px; }
.pairs-well__paints { border-top: 1px dashed #ebe4d8; margin-top: 4px; padding-top: 6px; font-size: 10px; line-height: 1.5; color: #444; }
.pairs-well__paints .label { color: #888; font-weight: 600; margin-right: 4px; letter-spacing: 0.04em; }
.pairs-well__paints .row { display: block; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.pairs-well__skeleton { background: linear-gradient(90deg, #eee 0%, #f6f6f6 50%, #eee 100%); background-size: 200% 100%; animation: pwShim 1.2s linear infinite; aspect-ratio: 1 / 1; border-radius: 6px; }
@keyframes pwShim { 0% { background-position: 200% 0; } 100% { background-position: -200% 0; } }
.pairs-well__empty { padding: 18px; color: #777; font-size: 14px; grid-column: 1 / -1; }
</style>
<script>
(function () {
var root = document.getElementById('pairs-well-with');
if (!root) return;
var endpointPairs = root.getAttribute('data-pairs-endpoint');
var endpointAi = root.getAttribute('data-ai-endpoint');
var handle = root.getAttribute('data-product-handle');
var sku = root.getAttribute('data-product-sku');
if (!(sku && sku.length) && !(handle && handle.length)) return;
root.hidden = false;
var cta = root.querySelector('.pairs-well__cta');
var catalogPanel = document.getElementById('pairs-well-catalog');
var catalogGrid = document.getElementById('pairs-well-grid');
var catalogCols = document.getElementById('pairs-well-cols-catalog');
var catalogColsVal = document.getElementById('pairs-well-cols-catalog-val');
var catalogCount = document.getElementById('pairs-well-catalog-count');
var aiPanel = document.getElementById('pairs-well-ai');
var aiGrid = document.getElementById('pairs-well-ai-grid');
var aiCols = document.getElementById('pairs-well-cols-ai');
var aiColsVal = document.getElementById('pairs-well-cols-ai-val');
var sourcePalette = document.getElementById('pairs-well-source-palette');
var vendorPicker = document.getElementById('pairs-well-vendor-picker');
var vendorChecks = vendorPicker.querySelectorAll('input[type=checkbox]');
var loaded = false;
var cachedPairs = null, cachedAi = null, cachedSource = null;
var VENDOR_LABEL = { sw:'Sherwin-Williams', de:'Dunn-Edwards', bm:'Benjamin Moore', fb:'Farrow & Ball', behr:'Behr', ppg:'PPG', ral:'RAL' };
var VENDOR_SHORT = { sw:'SW', de:'DE', bm:'BM', fb:'F&B', behr:'Behr', ppg:'PPG', ral:'RAL' };
var DEFAULT_VENDORS = ['sw','de','bm','fb'];
function selectedVendors() {
var out = [];
vendorChecks.forEach(function (cb) { if (cb.checked) out.push(cb.value); });
return out.length ? out : DEFAULT_VENDORS.slice();
}
try {
var stored = JSON.parse(localStorage.getItem('pw.vendors') || 'null');
if (Array.isArray(stored) && stored.length) {
vendorChecks.forEach(function (cb) { cb.checked = stored.indexOf(cb.value) !== -1; });
}
} catch (_) {}
function persistVendors() {
try { localStorage.setItem('pw.vendors', JSON.stringify(selectedVendors())); } catch (_) {}
}
vendorChecks.forEach(function (cb) {
cb.addEventListener('change', function () {
persistVendors();
if (cachedSource) renderSourcePalette(cachedSource.palette);
if (cachedPairs && !catalogPanel.hidden) renderGrid(catalogGrid, cachedPairs, false);
});
});
function wireSlider(input, valEl, gridEl, varName, storageKey) {
function apply() {
var n = Math.max(3, Math.min(12, parseInt(input.value, 10) || 8));
valEl.textContent = n;
gridEl.parentNode.parentNode.style.setProperty('--' + varName, n);
root.style.setProperty('--' + varName, n);
try { localStorage.setItem(storageKey, n); } catch (_) {}
}
try {
var s = parseInt(localStorage.getItem(storageKey), 10);
if (!isNaN(s) && s >= 3 && s <= 12) input.value = s;
} catch (_) {}
input.addEventListener('input', apply);
apply();
}
wireSlider(catalogCols, catalogColsVal, catalogGrid, 'cols-catalog', 'pw.cols.catalog');
wireSlider(aiCols, aiColsVal, aiGrid, 'cols-ai', 'pw.cols.ai');
function esc(s) {
return String(s == null ? '' : s)
.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>')
.replace(/"/g, '"').replace(/'/g, ''');
}
function renderSkeletons(grid, n) {
var html = '';
for (var i = 0; i < n; i++) html += '<div class="pairs-well__skeleton"></div>';
grid.innerHTML = html;
}
function renderSourcePalette(palette) {
if (!palette || !palette.length) { sourcePalette.hidden = true; vendorPicker.hidden = true; return; }
var vendors = selectedVendors();
var head = '<th></th>' + vendors.map(function (v) { return '<th>' + esc(VENDOR_LABEL[v]) + '</th>'; }).join('');
var body = palette.map(function (c) {
var hex = typeof c === 'string' ? c : c.hex;
var cells = '<td class="swatch"><span class="pw-dot" style="background:' + esc(hex) + '"></span></td>';
vendors.forEach(function (v) {
var p = c && c.paints && c.paints[v];
cells += '<td>' + (p
? '<span class="pw-square" style="background:' + esc(p.hex) + '"></span>' + esc(p.name) + ' <span class="pw-code">' + esc(p.code) + '</span>'
: '—') + '</td>';
});
return '<tr>' + cells + '</tr>';
}).join('');
sourcePalette.innerHTML = '<h4>Color story</h4><table><thead><tr>' + head + '</tr></thead><tbody>' + body + '</tbody></table>';
sourcePalette.hidden = false;
vendorPicker.hidden = false;
}
function renderCard(p, isAi) {
var img = p.image_url ? esc(p.image_url) : '';
var why = (p.why && p.why[0]) ? esc(p.why[0]) : (p.motif ? 'AI ' + esc(p.motif) : '');
var palette = (p.palette || []).map(function (c) {
var hex = typeof c === 'string' ? c : c.hex;
var sw = c && c.paints && c.paints.sw, de = c && c.paints && c.paints.de;
var tip = (sw ? 'SW ' + sw.name + ' ' + sw.code : '') + (de ? ' · DE ' + de.name + ' ' + de.code : '');
return '<span class="pw-dot" style="background:' + esc(hex) + '" title="' + esc(tip) + '"></span>';
}).join('');
var dom = (p.palette && p.palette[0]) || null;
var paintsBlock = '';
if (dom && dom.paints) {
var vendors = selectedVendors();
var rows = vendors.map(function (v) {
var paint = dom.paints[v];
if (!paint) return '';
return '<span class="row"><span class="label">' + esc(VENDOR_SHORT[v]) + '</span>'
+ '<span class="pw-square" style="background:' + esc(paint.hex) + '"></span>'
+ esc(paint.name) + ' <span class="pw-code">' + esc(paint.code) + '</span></span>';
}).filter(Boolean).join('');
if (rows) paintsBlock = '<div class="pairs-well__paints">' + rows + '</div>';
}
var href = p.url ? esc(p.url) : (p.handle ? '/products/' + esc(p.handle) : '#');
return '<a class="pairs-well__card' + (isAi ? ' pairs-well__card--ai' : '') + '" href="' + href + '" title="' + esc((p.why || []).join(' · ')) + '">'
+ '<div class="pairs-well__img-wrap">' + (img ? '<img class="pairs-well__img" src="' + img + '" alt="' + esc(p.title) + '" loading="lazy">' : '') + '</div>'
+ '<div class="pairs-well__meta">'
+ '<p class="pairs-well__title">' + esc(p.title || '') + '</p>'
+ '<p class="pairs-well__vendor">' + esc(p.vendor || (isAi ? 'AI-Generated' : '')) + '</p>'
+ (why ? '<span class="pairs-well__why">' + why + '</span>' : '')
+ (palette ? '<div class="pairs-well__palette">' + palette + '</div>' : '')
+ paintsBlock
+ '</div>'
+ '</a>';
}
function renderGrid(grid, items, isAi) {
if (!items || !items.length) { grid.innerHTML = '<div class="pairs-well__empty">No coordinates found for this pattern.</div>'; return; }
grid.innerHTML = items.map(function (p) { return renderCard(p, isAi); }).join('');
}
function buildUrl(base, limit) {
var qs = [];
if (sku) qs.push('dw_sku=' + encodeURIComponent(sku));
if (handle) qs.push('handle=' + encodeURIComponent(handle));
if (limit) qs.push('limit=' + limit);
return base + '?' + qs.join('&');
}
function load() {
if (loaded) return Promise.resolve();
loaded = true;
renderSkeletons(catalogGrid, 12);
catalogPanel.hidden = false;
aiPanel.hidden = true; /* Option B (Steve 2026-07-12): hide AI-generated placeholder half */
var pairsPromise = fetch(buildUrl(endpointPairs, 24), { credentials: 'omit' })
.then(function (r) { return r.ok ? r.json() : Promise.reject(new Error('http ' + r.status)); })
.then(function (d) {
if (!d || d.ok === false) throw new Error((d && d.error) || 'bad payload');
cachedSource = d.source || null;
cachedPairs = d.pairs || [];
if (cachedSource) renderSourcePalette(cachedSource.palette || []);
renderGrid(catalogGrid, cachedPairs, false);
catalogCount.textContent = '(' + cachedPairs.length + ')';
if (!cachedPairs.length && (!cachedSource || !cachedSource.palette || !cachedSource.palette.length)) {
root.hidden = true;
}
})
.catch(function () { catalogGrid.innerHTML = '<div class="pairs-well__empty">Could not load coordinates right now.</div>'; });
/* Option B (Steve 2026-07-12): AI-generated coordinate half removed from the customer PDP.
Those cards were generated SVG placeholders with url:null -> dead href="#" (~50% of the
grid = the reported "no images / bad links"). Only REAL catalog coordinates (/api/pairs,
actual products with images + working links) render now. */
return pairsPromise;
}
cta.addEventListener('click', function () {
var open = cta.getAttribute('aria-expanded') === 'true';
if (open) {
cta.setAttribute('aria-expanded', 'false');
sourcePalette.hidden = true;
vendorPicker.hidden = true;
catalogPanel.hidden = true;
aiPanel.hidden = true;
return;
}
cta.setAttribute('aria-expanded', 'true');
load();
});
})();
</script>
<div
class="product-recommendations-wrapper--right"
data-product-recommendations-right
>
</div>
</section>
{% schema %}
{
"name": "Product pages",
"settings": [
{
"type": "checkbox",
"id": "enable_cart_redirection",
"label": "Enable cart redirection",
"info": "Automatically sends users to the Cart page after adding a product.",
"default": false
},
{
"type": "checkbox",
"id": "show_payment_button",
"label": "Show dynamic checkout button",
"info": "Each customer will see their preferred payment method from those available on your store, such as PayPal or Apple Pay. [Learn more](https://help.shopify.com/manual/using-themes/change-the-layout/dynamic-checkout)",
"default": true
},
{
"type": "header",
"content": "Media"
},
{
"type": "paragraph",
"content": "Learn more about [media types](https://help.shopify.com/en/manual/products/product-media/product-media-types)"
},
{
"type": "select",
"id": "images_layout",
"label": "Layout",
"options": [
{
"label": "Slideshow",
"value": "slideshow"
},
{
"label": "List",
"value": "list"
},
{
"label": "Masonry",
"value": "masonry"
}
],
"default": "slideshow"
},
{
"type": "checkbox",
"id": "enable_zoom",
"label": "Enable image zoom",
"info": "Zoom only works with the slideshow image layout"
},
{
"type": "checkbox",
"id": "enable_video_autoplay",
"label": "Enable video autoplay",
"default": true
},
{
"type": "checkbox",
"id": "enable_video_looping",
"label": "Enable video looping"
}
],
"blocks": [
{
"type": "@app"
},
{
"type": "collapsible-tab",
"name": "Collapsible tab",
"settings": [
{
"type": "text",
"id": "collapsible_tab_heading",
"label": "Heading",
"default": "Collapsible tab"
},
{
"type": "richtext",
"id": "collapsible_tab_text",
"label": "Text",
"default": "<p>Use this text to share information about your product.</p>"
}
]
},
{
"type": "custom-liquid",
"name": "Custom liquid",
"settings": [
{
"type": "liquid",
"id": "custom_liquid",
"label": "Custom liquid",
"info": "Add app snippets or other Liquid code to create advanced customizations."
}
]
},
{
"type": "tabs",
"name": "Tabs",
"limit": 1,
"settings": [
{
"type": "checkbox",
"id": "show_product_description",
"label": "Show product description",
"default": false
},
{
"type": "header",
"content": "Tab"
},
{
"type": "text",
"id": "tab_heading_1",
"label": "Heading",
"default": "Tab 1"
},
{
"type": "richtext",
"id": "tab_text_1",
"label": "Text",
"default": "<p>Tab 1 content goes here.</p>"
},
{
"type": "header",
"content": "Tab"
},
{
"type": "text",
"id": "tab_heading_2",
"label": "Heading",
"default": "Tab 2"
},
{
"type": "richtext",
"id": "tab_text_2",
"label": "Text",
"default": "<p>Tab 2 content goes here.</p>"
},
{
"type": "header",
"content": "Tab"
},
{
"type": "text",
"id": "tab_heading_3",
"label": "Heading",
"default": "Tab 3"
},
{
"type": "richtext",
"id": "tab_text_3",
"label": "Text",
"default": "<p>Tab 3 content goes here.</p>"
}
]
},
{
"type": "title",
"name": "Title",
"limit": 1
},
{
"type": "vendor",
"name": "Vendor",
"limit": 1
},
{
"type": "social",
"name": "Social",
"limit": 1
},
{
"type": "description",
"name": "Description",
"limit": 1
},
{
"type": "price",
"name": "Price",
"limit": 1
},
{
"type": "form",
"name": "Form",
"limit": 1,
"settings": [
{
"type": "paragraph",
"content": "Customize form features for the product in the products portion of the theme settings."
},
{
"type": "checkbox",
"id": "show_gift_card_recipient_form",
"label": "t:sections.product.blocks.form.show_gift_card_recipient_form.label",
"info": "t:sections.product.blocks.form.show_gift_card_recipient_form.info",
"default": false
}
]
},
{
"type": "rating",
"name": "Product rating",
"limit": 1,
"settings": [
{
"type": "paragraph",
"content": "To display a rating, add a product rating app. [Learn more](https://apps.shopify.com/product-reviews)"
}
]
},
{
"type": "complementary_products",
"name": "Complementary products",
"limit": 1,
"settings": [
{
"type": "paragraph",
"content": "To select complementary products, add the Search & Discovery app. [Learn more](https:\/\/shopify.dev\/themes\/product-merchandising\/recommendations)"
},
{
"type": "text",
"id": "heading",
"label": "Heading",
"default": "Pairs well with"
},
{
"type": "range",
"id": "product_recommendation_limit",
"label": "Maximum products to show",
"min": 1,
"max": 10,
"default": 5
},
{
"type": "range",
"id": "products_per_slide",
"label": "Number of products per page",
"min": 1,
"max": 3,
"default": 2
}
]
}
]
}
{% endschema %}
<div class="keywords-desktop" style="padding-left: 0ch; max-width: 80ch; line-height: 1.6;">
<h4 style="padding-left: 3ch; margin-bottom: 0;">KEYWORDS:</h4>
<div style="padding-left: 3ch;">
{% assign line = "" %}
{% assign char_limit = 96 %}
{% assign separator = ", " %}
{% assign plain_line = "" %}
{% for tag in product.tags %}
{% unless tag == "display_variant" %}
{% assign tag_link = '<a href="/search?q=' | append: tag | append: '">' | append: tag | append: '</a>' %}
{% assign tag_text = tag | append: separator %}
{% assign test_line = plain_line | append: tag_text %}
{% assign test_size = test_line | size %}
{% if test_size > char_limit %}
{{ line }}<br>
{% assign line = tag_link | append: separator %}
{% assign plain_line = tag_text %}
{% else %}
{% assign line = line | append: tag_link | append: separator %}
{% assign plain_line = test_line %}
{% endif %}
{% endunless %}
{% endfor %}
{{ line }}
</div>
</div>
{% comment %} More Wallcoverings Like This — relocated 2026-07-13 from the palette
column to the PDP bottom, directly above Recently Viewed (Steve's spec). {% endcomment %}
{% render 'more-wallcoverings-like-this' %}
{% comment %} Recently Viewed Products — tracks current product; sits UNDER
"More Wallcoverings Like This" at the very bottom (Steve 2026-07-13). {% endcomment %}
{% if settings.dw_enable_recently_viewed %}
{% render 'recently-viewed' %}
{% endif %}