API ReferenceGuides
Log In
API Reference

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:

  1. Find your product section file — Open templates/product.json and look for the type value in the "main" section:

    • Dawn: "type": "main-product" → edit sections/main-product.liquid
    • Horizon: "type": "product-information" → edit sections/product-information.liquid (or its snippet snippets/product-information-content.liquid)
    • Other themes: Check your product.json → find the section type → edit that section file
  2. Place the button Liquid near the buy buttons / add-to-cart area in that section file

  3. 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 sets window.SwymPageData with 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

  1. Product data is read from window.SwymPageData — set automatically by Swym's Liquid snippet on product pages (no data- attributes needed)
  2. On SDK ready, swat.fetch() gets all wishlisted items to set the initial state
  3. On click, toggles between swat.addToWishList() and swat.removeFromWishList()
  4. On variant change, swat.JSEvents.variantChanged fires on swat.evtLayer — the handler looks up the new variant data from window.SwymProductVariants[variantId] and re-checks wishlist state

Key Data Sources

SourceWhat it providesWhen it's available
window.SwymPageDataCurrent product: empi, epi, du, dt, iu, prOn every product page
window.SwymProductVariants[variantId]Variant-specific: epi, pr, iu, stkOn product pages with variants
swat.JSEvents.variantChangedEvent with new variant dataWhen 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

MethodPurpose
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