> ## Knowledge Base Index
> Fetch the complete knowledge base index at: https://regiostech.crisp.help/sitemap.xml
> Use this file to discover available pages before exploring further.
> Pure-Markdown content can be obtained by appending a '.md' suffix to the content URLs listed in the sitemap (without the trailing slash).

# DOPP API: Theme Interop Tutorial


### Introduction:
This tutorial demonstrates how to dynamically update prices and display discounts in custom product grids and containers using the [DOPP API](/en/article/dopp-api-reference-1gvya0h/)’s theme interop features.

**We highly recommend downloading the "Public API TypeScript Definition" mentioned in the "DOPP API Reference" article. You can feed this into ChatGPT/Copilot/Cursor etc. for assistance when writing your integration code.**

### Use Case/Context:
Let's say you have a wishlist page, where customers can view a list of items they have personally curated. Our app does not support wishlists out of the box, as there is too much potential variation.

The DOPP API’s `themeInterop` API makes it possible for you to easily display discount strikethrough prices in your wishlist.

### Assumptions:
Before you start, make sure:
- You understand basic HTML, JavaScript, and Shopify’s Liquid syntax.
- The "Discounts Embed" app embed is enabled.
- You can modify Shopify theme files.
- Your products are displayed within a product grid element, with the ID `wishlist-root`.
- You have a `wishlist_items` Liquid variable, of type `product_list`.

### Step 1: Converting Your Products to `DOPPPublicApiProduct`
First, prepare your products in the `DOPPPublicApiProduct` format using this Liquid snippet:

```javascript
window.wishlistItems = [
  {% for dopp_product in wishlist_items %}
    {%- liquid
      assign current_variant = dopp_product.selected_or_first_available_variant
      assign target = dopp_product.selected_or_first_available_variant
      assign compare_at_price = target.compare_at_price
      assign price = target.price
    -%}
    {
      // Required fields
      productId: {{ dopp_product.id | json }},
      regularPriceInCents: {{ price | json }},
      variantId: {{ current_variant.id | json }},

      // Optional fields, but if your discount depends on any of these, they
      // must be included
      collectionIds: {{ dopp_product.collections | map: "id" | json }},
      compareAtPriceInCents: {{ compare_at_price | json }},
      handle: {{ dopp_product.handle | json }},
      tags: {{ dopp_product.tags | json }},
      url: {{ dopp_product.url | json }},
      vendor: {{ dopp_product.vendor | json }},

      variants: [
        {% for variant in dopp_product.variants %}
        {
          id: {{ variant.id | json }},
          title: {{ variant.title | json }},
          priceInCents: {{ variant.price | json }},
          compareAtPriceInCents: {{ variant.compare_at_price | json }}
        }{% unless forloop.last %},{% endunless %}
        {% endfor %}
      ]
    }{% unless forloop.last %},{% endunless %}
  {% endfor %}
];
```

### Step 2: Waiting for the API to Initialize
You may have multiple apps and scripts on your site. This makes it a challenge to predict exactly when the "Discounts Embed" will load, and therefore, it's hard to know when `window.RegiosDOPP.api.v0` will be available. Use the following snippet to reliably wait to run your integration code until the API is initialized:

```javascript 
const updateWishlistPrices = (api) => {
  console.log("DOPP API initialized", { api });
  // TODO: Add your code here...
};

if (window.RegiosDOPP?.api?.v0) {
  updateWishlistPrices(window.RegiosDOPP.api.v0);
} else {
  window.addEventListener("regios-dopp:api-initialized", (e) => {
    updateWishlistPrices(e.detail.api);
  });
}
```

### Step 3: Using Theme Interop API to Detect Product Grid Cells
Use `themeInterop.findProductGridCells` to detect product elements within `#wishlist-root` and correlate them with `DOPPPublicApiProduct` data. This function is ideal for product grids like wishlists or collections.

```javascript
const gridCells = await api.themeInterop.findProductGridCells(document.querySelector('#wishlist-root'), wishlistItems, 'COLLECTION_PAGE');
```

If this doesn't work, you might be trying to detect elements in a product grid that our app doesn't understand the structure of. If so, use `findProductGridCellsByUrl` instead, which will find cells by searching for links to a given product's PDP.

```javascript
// Assuming that each product grid cell in your grid has the class name `wishlist-card`
const gridCells = await api.themeInterop.findProductGridCellsByUrl(document.querySelector('#wishlist-root'), wishlistItems, [".wishlist-card"]);
```

### Step 4: Updating On-Page Prices Using Theme Interop API
Apply the `themeInterop.updateOnPagePrices` method to dynamically update displayed prices. While this method is used here following `findProductGridCells`, it can independently update prices for any product displayed within a given container, such as a single featured product.

```javascript
for (const cell of gridCells) {
  await api.themeInterop.updateOnPagePrices(cell.element, 'COLLECTION_PAGE', cell.product);
}
```

### Putting It All Together
Here’s how to integrate these steps into your Shopify theme to ensure dynamic price updates:

```javascript
window.wishlistItems = [
  {% for dopp_product in wishlist_items %}
  {%- liquid
    assign current_variant = dopp_product.selected_or_first_available_variant
    assign target = dopp_product.selected_or_first_available_variant
    assign compare_at_price = target.compare_at_price
    assign price = target.price
  -%}
  {
    // Required fields
    productId: {{ dopp_product.id | json }},
    regularPriceInCents: {{ price | json }},
    variantId: {{ current_variant.id | json }},

    // Optional fields, but if your discount depends on any of these, they
    // must be included
    collectionIds: {{ dopp_product.collections | map: "id" | json }},
    compareAtPriceInCents: {{ compare_at_price | json }},
    handle: {{ dopp_product.handle | json }},
    tags: {{ dopp_product.tags | json }},
    url: {{ dopp_product.url | json }},
    vendor: {{ dopp_product.vendor | json }},

    variants: [
      {% for variant in dopp_product.variants %}
      {
        id: {{ variant.id | json }},
        title: {{ variant.title | json }},
        priceInCents: {{ variant.price | json }},
        compareAtPriceInCents: {{ variant.compare_at_price | json }},
      }{% unless forloop.last %},{% endunless %}
      {% endfor %}
    ]
  }{% unless forloop.last %},{% endunless %}
  {% endfor %}
];

/**
 * Initializes the process to update prices on the wishlist page.
 * This function handles both immediate initialization and setting up
 * event listeners for when the API becomes available.
 */
function initWishlistPrices() {
  /**
   * Updates prices on the wishlist page using the DOPP API.
   * @param {object} api - The DOPP API interface provided by the window object.
   */
  const updateWishlistPrices = async (api) => {
    const wishlistRoot = document.querySelector('#wishlist-root');
    const gridCells = await api.themeInterop.findProductGridCells(wishlistRoot, window.wishlistItems, 'COLLECTION_PAGE');

    for (const cell of gridCells) {
      await api.themeInterop.updateOnPagePrices(cell.element, 'COLLECTION_PAGE', cell.product);
    }
  }

  if (window.RegiosDOPP?.api?.v0) {
    updateWishlistPrices(window.RegiosDOPP.api.v0);
  } else {
    window.addEventListener("regios-dopp:api-initialized", (e) => {
      updateWishlistPrices(e.detail.api);
    });
  }
}

// Checks if the document has been fully parsed and initializes the wishlist prices,
// otherwise waits for the DOM to be fully loaded.
if (document.readyState !== "loading") {
  initWishlistPrices();
} else {
  document.addEventListener("DOMContentLoaded", initWishlistPrices);
}
```

### Your Feedback Matters
Your review helps keep this small business running. Please [leave one](https://apps.shopify.com/regios-automatic-discounts#modal-show=ReviewListingModal) on the Shopify App Store.