CMS Integration
Dopple Visual is designed to be CMS-agnostic and unopinionated, to give developers the freedom to integrate into any website regardless of the CMS or tech stack used.
Official integrations
To help simplify and speed up development, Dopple provides CMS-specific integrations for the following platforms:
Note
Don’t see your CMS listed above? Don’t worry! The Visual Component and Visual API both still provide all the features necessary to easily create custom integrations.
Custom integrations
For websites that require an integration that isn’t covered by the ones listed above, a custom integration can still be built by following a few key concepts:
- Edit your page or theme’s template to include either:
- the
<atlatl-visual>
element if using the Visual Component; or - a
<canvas>
element if using the Visual API directly.
- the
- Include the
<script>
tags for Dopple Visual on your page. - Connecting the configuration options on your page (buttons, dropdown menus, etc.) to Dopple Visual.
Keep in mind that the specifics of how you implement each of these concepts may vary depending on your CMS and theme.
Adding <atlatl-visual>
or <canvas>
to your page template
Since Dopple Visual will look for a <canvas>
element on your page to render the 3D product onto, edit your page or theme’s HTML template to include either a <canvas>
element (if using the Visual API) or the <atlatl-visual>
element (if using the Visual Component, which contains a <canvas>
inside of it).
Typically, the 3D product will be placed similar to where other product media goes (such as static images, videos, or thumbnails).
Example: Shopify
Shopify sites will commonly use Liquid templates to define the markup for each page and component across the site.
If, for example, your Shopify theme uses a product-template.liquid
file, the <canvas>
or <atlatl-visual>
tags may be added here.
- Visual API
- Visual Component
<h1>{{ product.title }} - ${{ product.price }}</h1>
<div class="dopple-visual-container">
<canvas id="dopple-visual" touch-action="none"></canvas>
</div>
<h1>{{ product.title }} - ${{ product.price }}</h1>
<div class="dopple-visual-container">
<atlatl-visual client-id="a1a1a1a1-b2b2-c3c3-d4d4-e5e5e5e5e5e5">
<av-product namespace="my_namespace" name="my_product_name"></av-product>
</atlatl-visual>
</div>
Example: WooCommerce
WooCommerce sites will commonly use PHP templates to define the markup for each page and component across the site.
The example below uses a fictional my-custom-template.php
file that outputs the product title and Dopple Visual, which can be used as a starting point for your own custom template. In practice, your page template may be named differently, and may be much more complex.
- Visual API
- Visual Component
<?php
/**
* Template Name: Page with Dopple (Visual API)
*/
get_header();
?>
<h1><?php the_title() ?></h1>
<div class="dopple-visual-container">
<canvas id="dopple-visual" touch-action="none"></canvas>
</div>
<?php
/**
* Template Name: Page with Dopple (Visual Component)
*/
get_header();
?>
<h1><?php the_title() ?></h1>
<div class="dopple-visual-container">
<atlatl-visual client-id="<?php dopple_client_id() ?>">
<av-product namespace="<?php dopple_product_namespace() ?>" name="<?php dopple_product_name() ?>"></av-product>
</atlatl-visual>
</div>
Example: Webflow
Webflow allows you to embed custom code onto your pages, which may be used to add the <canvas>
or <atlatl-visual>
tags to be placed anywhere in your template.
For a detailed walkthrough, see the official Webflow Custom Code Embed guide.
Adding the <script>
tags to your page
Next, in order for Dopple to load on your page, you must include a link to Dopple Visual’s scripts, and either use the defer
attribute or place the script after the <atlatl-visual>
or <canvas>
tag, such as before the closing </body>
tag on your page.
If using the Visual API directly, this script will be:
<script src="https://builds.dopple.io/atlatl-visual-api/releases/current/index.js" defer></script>
If using the Visual Component, this script will be:
<script src="https://builds.dopple.io/atlatl-visual-component/releases/current/index.js" defer></script>
For instance, in the Shopify example above, your <script>
may be added directly after the Dopple Visual tag:
- Visual API
- Visual Component
<h1>{{ product.title }} - ${{ product.price }}</h1>
<div class="dopple-visual-container">
<canvas id="dopple-visual" touch-action="none"></canvas>
<script src="https://builds.dopple.io/atlatl-visual-api/releases/current/index.js" defer></script>
</div>
<h1>{{ product.title }} - ${{ product.price }}</h1>
<div class="dopple-visual-container">
<atlatl-visual client-id="a1a1a1a1-b2b2-c3c3-d4d4-e5e5e5e5e5e5">
<av-product namespace="my_namespace" name="my_product_name"></av-product>
</atlatl-visual>
<script src="https://builds.dopple.io/atlatl-visual-component/releases/current/index.js" defer></script>
</div>
Connecting the configuration options
Different ecommerce platforms will have different ways of defining variable products (i.e. products that have different variants or configurable options, such as color or size, that may be configured).
For most ecommerce sites, it is easier to set up your product page’s configuration options without binding them to the 3D product at first. At this stage, the goal is to build a basic working page (without 3D) and ensure the selection options for each variant are working correctly with your site’s backend, such as successfully adding the configured product to the cart when the user clicks Add To Cart.
Once the selection options are working correctly, you can then bind them to control the page’s 3D product. Two common approaches are:
- Mapping the properties to whole product variants
- Mapping the properties to individual variant options
Mapping properties to product variants
One common method to setup your conifguration bindings is to used a JSON mapping connecting each variant to the corresponding properties and values on the 3D product. This JSON mapping can be stored in a <script>
tag on your page, and then referenced by the <atlatl-visual>
or <canvas>
tag.
For example, let’s say you have a product with two configurable options: color
and size
. The color
option has three possible values: red
, green
, and blue
, and the size
option has two possible values: small
and large
. This would result in a total of six possible variants for this product:
- Red / small
- Red / large
- Green / small
- Green / large
- Blue / small
- Blue / large
tip
Be sure to reference your product’s configurability matrix to determine the possible options and variants for your product.
Example:
Dopple Property | Dopple Value | Description |
---|---|---|
color | red | Sets the product's color to red |
color | green | Sets the product's color to green |
color | blue | Sets the product's color to blue |
size | small | Changes the product's size to small |
size | large | Changes the product's size to large |
The JSON mapping for this product could then look like this:
const productJsonMap = {
"red-small": {
"color": "red",
"size": "small"
},
"red-large": {
"color": "red",
"size": "large"
},
"green-small": {
"color": "green",
"size": "small"
},
"green-large": {
"color": "green",
"size": "large"
},
"blue-small": {
"color": "blue",
"size": "small"
},
"blue-large": {
"color": "blue",
"size": "large"
}
}
As a simple example, your page’s HTML may display the options as <select>
dropdowns:
<h2>Select your color:</h2>
<select id="product-color">
<option value="red">Red</option>
<option value="green">Green</option>
<option value="blue">Blue</option>
</select>
<h2>Select your size:</h2>
<select id="product-size">
<option value="small">Small</option>
<option value="large">Large</option>
</select>
Then, if the user selects the red
color and small
size, you would use this JSON mapping to find the corresponding variant, and then call setValue()
on the 3D product for each of the properties on that variant.
This approach is particularly useful for platforms like Shopify that assign a unique ID to each variant (the key in the JSON mapping above) and trigger a variantChange
event with that ID whenever a new configuration option is selected.
- Visual API
- Visual Component
// Be sure to globally define your `product` variable when initializing Dopple Visual, before this event listener below
document.addEventListener('variant:change', event => {
const variantId = event.detail.variant.id
const variant = productJsonMap[variantId]
if (variant) {
// For each property/value pair, set the 3D product's properties to match the current variant
Object.keys(variant).forEach(key => {
product.setValue(key, variant[key])
})
}
})
const myProduct = document.querySelector('av-product')
document.addEventListener('variant:change', event => {
const variantId = event.detail.variant.id
const variant = productJsonMap[variantId]
if (variant) {
// For each property/value pair, set the 3D product's properties to match the current variant
Object.keys(variant).forEach(key => {
myProduct.product.setValue(key, variant[key])
})
}
})
Binding the configuration options to the 3D product
Another approach is to break your product’s configuration options into categories, and then bind them manually to their respective controls in your page’s UI.
For example, using the same example as above with the three color
options and two size
options, your configuration options object may be set up like this:
const configOptions = [
{
// The Dopple-given name of the property on the 3D product that will be updated
property: 'color',
// The Dopple-given values for the property on the 3D product
values: {
// For each of these key/value pairs:
// - Key = any identifier used in the DOM, e.g. the `value` attribute the <option> element
// - Value = the name of the Dopple-given value for that property
'r': 'red',
'g': 'green',
'b': 'blue'
}
},
{
property: 'size',
values: {
'sm': 'small',
'lg': 'large'
}
}
]
Then, you can call setValue()
on the 3D product each time a new option is selected with that option’s property and value name:
- Visual API
- Visual Component
<!-- The canvas for Dopple Visual to render the product onto -->
<canvas id="dopple"></canvas>
<!-- Product color options -->
<select id="product-colors">
<option value="r">Red</option>
<option value="g">Green</option>
<option value="b">Blue</option>
</select>
<!-- Product size options -->
<div id="product-sizes">
<label >
<input type="radio" name="product-size" value="sm" checked />
Small
</label>
<label >
<input type="radio" name="product-size" value="lg" />
Large
</label>
</div>
const configOptions = [
{
property: 'color',
values: {'r': 'red', 'g': 'green', 'b': 'blue'}
},
{
property: 'size',
values: {'sm': 'small', 'lg': 'large'}
}
]
// Listen for changes to the Product Color dropdown menu
const colorsSelect = document.getElementById('product-colors')
colorsSelect.addEventListener('change', event => {
// Get the item from the configOptions array for the product color options
const options = configOptions.find(option => option.property === 'color')
// Get the `value` attribute of the selected <option> element, e.g. 'r' if Red was selected
const colorKey = event.target.value
// Get the Dopple-given value for that key, e.g. 'red'
const color = options.values[colorKey]
// Set the 3D product's color to the selected value
// Make sure your `product` instance was globally defined when initializing Dopple Visual
product.setValue('color', color)
})
// Listen for changes on each of the Product Size radio buttons
const sizesDiv = document.getElementById('product-sizes')
const sizeInputs = sizesDiv.querySelectorAll('input')
sizeInputs.forEach(input => {
input.addEventListener('change', event => {
// Same logic flow as above: set the product's based on the selected radio's `value` attribute
const options = configOptions.find(option => option.property === 'size')
const sizeKey = event.target.value
const size = options.values[sizeKey]
product.setValue('size', size)
})
})
<!-- The Visual Component -->
<atlatl-visual client-id="a1a1a1a1-b2b2-c3c3-d4d4-e5e5e5e5e5e5">
<av-product namespace="my_namespace" name="my_product_name"></av-product>
</atlatl-visual>
<!-- Product color options -->
<select id="product-colors">
<option value="r">Red</option>
<option value="g">Green</option>
<option value="b">Blue</option>
</select>
<!-- Product size options -->
<div id="product-sizes">
<label >
<input type="radio" name="product-size" value="sm" checked />
Small
</label>
<label >
<input type="radio" name="product-size" value="lg" />
Large
</label>
</div>
const configOptions = [
{
property: 'color',
values: {'r': 'red', 'g': 'green', 'b': 'blue'}
},
{
property: 'size',
values: {'sm': 'small', 'lg': 'large'}
}
]
// Get the Dopple product instance
const myProduct = document.querySelector('av-product')
// Listen for changes to the Product Color dropdown menu
const colorsSelect = document.getElementById('product-colors')
colorsSelect.addEventListener('change', event => {
// Get the item from the configOptions array for the product color options
const options = configOptions.find(option => option.property === 'color')
// Get the `value` attribute of the selected <option> element, e.g. 'r' if Red was selected
const colorKey = event.target.value
// Get the Dopple-given value for that key, e.g. 'red'
const color = options.values[colorKey]
// Set the 3D product's color to the selected value
myProduct.product.setValue('color', color)
})
// Listen for changes on each of the Product Size radio buttons
const sizesDiv = document.getElementById('product-sizes')
const sizeInputs = sizesDiv.querySelectorAll('input')
sizeInputs.forEach(input => {
input.addEventListener('change', event => {
// Same logic flow as above: set the product's based on the selected radio's `value` attribute
const options = configOptions.find(option => option.property === 'size')
const sizeKey = event.target.value
const size = options.values[sizeKey]
myProduct.product.setValue('size', size)
})
})
info
This is especially useful when you might not have control over how your platform outputs the value
or id
attributes on your configuration options in the final HTML.
For example, some platforms may automatically set an <option>
’s value
attribute to some arbitrary internal ID, such as <option value="foo-dc8b1ff5">Red</option>
. In cases like this, simply update your configOptions
array to use the internal ID as the key, and the Dopple-given value as the value:
const configOptions = [
{
property: 'color',
values: {
// Replace these keys with your CMS's generated values
// The values remain the same Dopple-given values on the 3D product
'foo-dc8b1ff5': 'red',
'foo-4c98ad23': 'green',
'foo-39ef16c0': 'blue'
}
},
]
Your event listeners on those inputs would then take that internal ID (e.g. foo-dc8b1ff5
), find the corresponding Dopple value for it (e.g. red
), and set the product’s property to that value.