Project portfolio Browse selected work

Shopify Plus Upgrade Monthly Fee Reduction + Up to $4800 Development Fee Credit - Exclusive WesWoo Offer

Developer modules / Product detail and combined purchases

Product detail and combined purchases

Synchronize model and variant facts before media, accessories and specifications.

Compatible accessories and explicit selection

Take compatibility from reviewed model data and expose purchasable accessory destinations. Before a combined add, confirm main and accessory variant IDs and quantities, then update from the actual cart response.

Data and dependencies

  • custom.compatible_accessories: list.product_reference.
  • Record variant-specific compatibility separately.

Interaction logic

  • Revalidate accessory choices after the model changes.
  • Prevent duplicate submissions and avoid automatic mutation retries.
Example code · snippets/ww-accessories.liquid
Liquid · WESWOO
{% assign accessories = product.metafields.custom.compatible_accessories.value %}
{% if accessories != blank %}
  <section aria-labelledby="Accessories-{{ section.id }}">
    <h2 id="Accessories-{{ section.id }}">Accessories for this model</h2>
    <ul>
      {% for accessory in accessories %}
        <li>
          <a href="{{ accessory.url | escape }}">{{ accessory.title | escape }}</a>
          <span>{{ accessory.price | money_with_currency }}</span>
        </li>
      {% endfor %}
    </ul>
  </section>
{% endif %}

Example code · assets/ww-add-selection.js
JavaScript · WESWOO
export async function addSelection(root, items) {
  if (!root.startsWith('/') || root.startsWith('//')) throw new Error('Invalid store route');
  if (!items.length || items.some(item => !Number.isSafeInteger(item.id) || item.id <= 0 ||
      !Number.isSafeInteger(item.quantity) || item.quantity <= 0)) {
    throw new Error('Select valid variants and quantities');
  }
  const response = await fetch(`${root}cart/add.js`, {
    method: 'POST',
    headers: {'Content-Type': 'application/json', 'Accept': 'application/json'},
    body: JSON.stringify({items})
  });
  const result = await response.json();
  if (!response.ok) throw new Error(result.description || 'The selection could not be added');
  return result;
}
// Pass window.Shopify.routes.root from a Shopify theme.
// Disable repeat submission while pending, then refresh actual cart state.
// A network error must not trigger an automatic second add request.

Acceptance checks

  • Test incompatible items, unavailable variants and quantities.
  • Read the cart after success or failure to confirm actual lines.

Recommendations do not prove compatibility. The list does not add items itself; integrate the Ajax function with real routes and status feedback.

Read it, integrate it, verify it

  1. Choose a module and confirm the data contract.
  2. Connect the fragment to the current theme or framework.
  3. Check real variants, markets and recovery states.

Examples target Shopify Online Store 2.0 themes. Headless has separate data and version boundaries. Integrate fragments with actual fields, theme components and locale files.

Architecture references

Original educational examples with Shopify documentation and pinned upstream references. Follow the applicable license when adopting repository code.

Shopify/dawn · Licensecommit 3e9ee2281dc4 · Shopify-integration theme license; architecture reference without copying the implementation.
Shopify/hydrogen · Licensecommit 9e358a2462ba · MIT; retain copyright and license when using substantial code.

References checked 2026-11-12