Wishlist Button (PDP)
Add a wishlist toggle button to your product detail pages using the Swym JS SDK.
Wishlist Button (Product Page)
A toggle button on the product detail page that adds/removes the current product from the wishlist.
Where to Add the Code
Shopify OS 2.0 themes use JSON templates (templates/product.json) that reference sections. You don't edit product.json directly — instead:
-
Find your product section file — Open
templates/product.jsonand look for thetypevalue in the"main"section:- Dawn:
"type": "main-product"→ editsections/main-product.liquid - Horizon:
"type": "product-information"→ editsections/product-information.liquid(or its snippetsnippets/product-information-content.liquid) - Other themes: Check your
product.json→ find the section type → edit that section file
- Dawn:
-
Place the button Liquid near the buy buttons / add-to-cart area in that section file
-
Add the JavaScript as a theme asset file (Assets > Add new asset >
swym-wishlist-button.js) and include it with<script src="{{ 'swym-wishlist-button.js' | asset_url }}" defer></script>in your section
Tip: In Dawn, app blocks render inline via
{%- when '@app' -%} {% render block %}— so the button appears wherever you drag it in the theme editor. In Horizon, app blocks render after the product details area via{{ additional_blocks }}. For precise placement, add the Liquid directly inside the section.
Theme Architecture: Liquid vs JavaScript Injection
After finding your section file, check if it uses block-based rendering:
- Block-based themes (Ritual, Prestige, Impact, Symmetry): The product form is inside
{% for block in section.blocks %}loops. Adding a<button>in the Liquid will render it outside the product grid — it won't appear near the buy buttons. Use the JavaScript injection approach below. - Template-based themes (Dawn, Craft, Colorblock): Product info renders inline. Use the Liquid approach.
To check: run
grep -c "for block in section.blocks" sections/YOUR-SECTION.liquid— if count > 0, use JS injection.
Liquid
{% comment %} Swym Wishlist Button — SDK-Only Mode {% endcomment %}
<button
id="swym-pdp-wishlist-btn"
aria-label="Add to wishlist"
type="button">
{% comment %} Add your icon here (heart SVG, image, or text) {% endcomment %}
Add to Wishlist
</button>Note: No
data-attributes needed. The SDK automatically setswindow.SwymPageDatawith the current product's data on product pages.
JavaScript Injection (Block-Based Themes)
For themes like Ritual where Liquid placement doesn't work, inject the button via JavaScript. Create assets/swym-wishlist-button.js and load it at the bottom of your product section:
<script src="{{ 'swym-wishlist-button.js' | asset_url }}" defer></script>The JavaScript below handles both approaches — it first looks for a button placed via Liquid, and if not found, injects one via JS near the buy buttons:
// Anchor selectors — tries each in order to find the buy buttons container
var ANCHOR_SELECTORS = [
'.buy-buttons-block', // Ritual
'.product-form__buttons', // Dawn variants
'.product-form__submit', // Generic
'[name="add"]', // Add to Cart button fallback
'.shopify-payment-button' // Dynamic checkout fallback
];
function findAnchor() {
for (var i = 0; i < ANCHOR_SELECTORS.length; i++) {
var el = document.querySelector(ANCHOR_SELECTORS[i]);
if (el) return el;
}
return null;
}The full JavaScript in the next section handles this automatically — if #swym-pdp-wishlist-btn doesn't exist in the DOM, it creates and injects it.
JavaScript
(function() {
'use strict';
var ANCHOR_SELECTORS = [
'.buy-buttons-block',
'.product-form__buttons',
'.product-form__submit',
'[name="add"]',
'.shopify-payment-button'
];
function findAnchor() {
for (var i = 0; i < ANCHOR_SELECTORS.length; i++) {
var el = document.querySelector(ANCHOR_SELECTORS[i]);
if (el) return el;
}
return null;
}
function initWishlistButton(swat) {
var btn = document.querySelector('#swym-pdp-wishlist-btn');
// JS injection for block-based themes (Ritual, Prestige, etc.)
if (!btn) {
var anchor = findAnchor();
if (!anchor) return;
btn = document.createElement('button');
btn.id = 'swym-pdp-wishlist-btn';
btn.type = 'button';
btn.setAttribute('aria-label', 'Add to wishlist');
btn.textContent = 'Add to Wishlist';
anchor.parentNode.insertBefore(btn, anchor.nextSibling);
}
// Use SwymPageData — set automatically by Swym's Liquid snippet on product pages
var pageData = window.SwymPageData;
if (!pageData || pageData.et !== 1) return; // et=1 means product page
var product = {
epi: pageData.epi,
empi: pageData.empi,
du: pageData.du,
dt: pageData.dt,
iu: pageData.iu,
pr: pageData.pr
};
// Check if already wishlisted and set initial state
checkState(swat, btn, product);
// Toggle wishlist on click
btn.addEventListener('click', function() {
if (btn.classList.contains('swym-added')) {
swat.removeFromWishList(product, function() {
updateButtonState(btn, false);
});
} else {
swat.addToWishList(product, function() {
updateButtonState(btn, true);
});
}
});
// Handle variant changes via Swym's own event (works across all themes)
swat.evtLayer.addEventListener(swat.JSEvents.variantChanged, function(evt) {
var variantData = evt && evt.detail && evt.detail.d;
if (!variantData) return;
var newVariantId = variantData.variant ? variantData.variant.id : null;
if (!newVariantId) return;
// Look up variant data from SwymProductVariants
var variantInfo = window.SwymProductVariants && window.SwymProductVariants[newVariantId];
if (variantInfo) {
product.epi = variantInfo.epi;
product.pr = variantInfo.pr;
product.iu = variantInfo.iu || product.iu;
} else {
product.epi = newVariantId;
}
// Re-check wishlist state for the new variant
checkState(swat, btn, product);
});
}
function checkState(swat, btn, product) {
swat.fetch(function(wishlisted) {
var found = wishlisted.some(function(item) {
return item.empi === product.empi && item.epi === product.epi;
});
updateButtonState(btn, found);
});
}
function updateButtonState(btn, isWishlisted) {
if (!btn) return;
btn.classList.toggle('swym-added', isWishlisted);
btn.setAttribute('aria-label', isWishlisted ? 'Remove from wishlist' : 'Add to wishlist');
}
window.SwymCallbacks = window.SwymCallbacks || [];
window.SwymCallbacks.push(initWishlistButton);
})();How It Works
- Product data is read from
window.SwymPageData— set automatically by Swym's Liquid snippet on product pages (nodata-attributes needed) - On SDK ready,
swat.fetch()gets all wishlisted items to set the initial state - On click, toggles between
swat.addToWishList()andswat.removeFromWishList() - On variant change,
swat.JSEvents.variantChangedfires onswat.evtLayer— the handler looks up the new variant data fromwindow.SwymProductVariants[variantId]and re-checks wishlist state
Key Data Sources
| Source | What it provides | When it's available |
|---|---|---|
window.SwymPageData | Current product: empi, epi, du, dt, iu, pr | On every product page |
window.SwymProductVariants[variantId] | Variant-specific: epi, pr, iu, stk | On product pages with variants |
swat.JSEvents.variantChanged | Event with new variant data | When user selects a different variant |
Styling
The button gets the class swym-added when the product is wishlisted. Use this class to toggle your icon (filled vs outline heart, color change, etc.). All styling is up to you.
API Methods Used
| Method | Purpose |
|---|---|
swat.fetch(callback) | Get all wishlisted products to check initial state |
swat.addToWishList(product, callback) | Add product to default wishlist |
swat.removeFromWishList(product, callback) | Remove product from default wishlist |
Updated about 8 hours ago