# The Oz- App Swatches
Custom multidimensional swatches for The Oz
# Documentation
Here is the documentation for adding custom multidimensional swatches on a client's website.
## 0. Create metafields definitions
In Shopify BO, go to *Settings > Metafields > Products > Add definition*.
There are two possible types of swatches: **text** or **color**.
For a **text swatch**, create the following metafields definitions (**i** stands for the number of the swatch):
1. Swatch text
- **Name**: Swatch i - text
- **Namespace and key**: `swatch_i.text`
- **Description**: Product swatch text
- **Type**: Single-line text
- **Maximum length**: 25
2. Swatch related products
- **Name**: Swatch i - related products
- **Namespace and key**: `swatch_i.products`
- **Description**: Swatch related products
- **Type**: Product (List)
**Lastly**, make sure the **Definition pinned** option (the orange drawing pin) is selected for all metafields, so that they appear directly on product pages.
End result should look like this:
![Swatch text metafields](/img/swatch-text-metafields.png)
For a **color swatch**, create the following metafields definitions (**i** stands for the number of the swatch):
1. Swatch image
- **Name**: Swatch i - image
- **Namespace and key**: `swatch_i.image`
- **Description**: Product swatch image
- **Type**: url
2. Swatch color
- **Name**: Swatch i - color
- **Namespace and key**: `swatch_i.color`
- **Description**: Product swatch color (won't be displayed if a "Swatch Image" is selected)
- **Type**: color
3. Swatch color
- **Name**: Swatch i - base64 image
- **Namespace and key**: `swatch_i.base64_image`
- **Description**: Product swatch color (won't be displayed if a "Swatch Image" or a "Swatch Color" is selected)
- **Type**: Single-line text
4. Swatch name
- **Name**: Swatch i - label
- **Namespace and key**: `swatch_i.label`
- **Description**: *(optional)* Product swatch label
- **Type**: Single-line text
- **Maximum length**: 25
5. Swatch related products
- **Name**: Swatch i - related products
- **Namespace and key**: `swatch_i.products`
- **Description**: Swatch related products
- **Type**: Product (List)
**Lastly**, make sure the **Definition pinned** option (the orange drawing pin) is selected for all metafields, so that they appear directly on product pages.
End result should look like this:
![Swatch color metafields](/img/swatch-color-metafields.png)
## 1. Include the custom swatches script to the project
1. Run `npm run build` in this `app_swatches` project to generate the `oz-app-swatches.xxxxxx.js` file _(note: the file name will differ for each `build`)_.
2. Copy and paste the content of the `oz-app-swatches.xxxxxx.js` file (from the [dist folder](/dist) folder) into a file named `index.js` that you place in the `assets` folder of the destination site.
3. Include `index.js`in the `
` of `theme.liquid`:
```html
{% if settings.enable_custom_related_products_swatches %}
{% endif %}
```
## 2. Add CSS file
Copy and paste the CSS file [swatches.scss](/doc/shopify/swatches.scss) into the destination site.
## 3. Add Swatch-related settings in `settings_schema.json`
In `settings_schema.json`, add [the following settings](/doc/shopify/settings_schema.json).
## 4. Add custom swatches on the product page
1. Add [oz-related-products-swatches.liquid](/doc/shopify/oz-related-products-swatches.liquid) to your `snippets` folder
2. Locate the liquid file where your product options are currently displayed (usually `product-form.liquid` or `product-template.liquid`)
3. Add this variable at the top of the file `{% assign custom_related_product_swatches_enabled = settings.enable_custom_related_products_swatches %}`
4. Add this line where you want your swatches to be displayed:
```html
{% if custom_related_product_swatches_enabled %}{% render 'oz-related-products-swatches', current_product: product %}{% endif %}
```
5. *(optional)* Use the `custom_related_product_swatches_enabled` variable to hide natively displayed color options (necessary if color options are present in the product BO)
Example :
```html
{% assign custom_related_product_swatches_enabled = settings.enable_custom_related_products_swatches %} // STEP 1
{% assign color_option_labels = 'color,colour,couleur,colore,farbe,색,色,färg,farve' %} // necessary if color options are present in BO
[...]
```
## 5. Update some test products in BO
We're now ready to start playing around with swatches on the product pages in the BO!
Head to some product pages in the BO and fill-in swatches-related metafields to start seeing it in action.
For **Swatch i - related products** metafields, please make sure to add the product from the current BO product page.
Example :
![Product list metafield](/img/product-list-metafield.png)
## 6. Add custom swatches on collection, search pages and cross-sells
Make sure to **also** follow the steps in **8. Integration with USF** for the collection and search pages if USF is installed and active on the theme.
### 6.1. Create a product search template
1. In `templates`, add [search.oz-related-product-block-html.liquid](/doc/shopify/search.oz-related-product-block-html.liquid).
2. Locate the snippet where your product block on the collection page is defined (usually `product-thumbnail.liquid`, `product-block.liquid` or `product-grid-item.liquid`)
2. In [search.oz-related-product-block-html.liquid](/doc/shopify/search.oz-related-product-block-html.liquid), replace `product-thumbnail` with the right product block snippet name.
### 6.2. Add HTML elements to product block
1. At the top of your product block snippet file (`product-thumbnail.liquid` or else), add this variable:
```html
{% assign custom_related_product_swatches_enabled = settings.enable_custom_related_products_swatches %}
```
2. Add the `cs-product-container` class to the very top HTML container of the product block.
3. Add this line where you want your swatches to be displayed:
```html
{% if custom_related_product_swatches_enabled %}{% render 'oz-related-products-swatches', current_product: product %}{% endif %}
```
### 6.3. Make relevant parameters accessible
With this app, the product will be loaded through an independent HTTP request from [this alternative search template](/doc/shopify/search.oz-related-product-block-html.liquid) so **outside** of the context of any section. This means that variables passed to the product block will need to be made available differently.
The only parameters we already have at this stage are the `product` and the `collection`.
```html
{% include 'product-thumbnail', product: product, collection: collection %}
```
1. In the hierarchy just above that **product block** file, locate where your snippet is called (usually `collection.liquid` and `search.liquid` for eg.) and whether it comes with parameters.
Example:
```html
{% include 'product-thumbnail', product: product, collection: collection, sidebar: sidebar, display_secondary_image: display_secondary_image %}
```
2. Parameters that come from general settings (ex: `settings.my_variable`) are accessible in every liquid file, so we can simply pass their values along in our [alternative search template](/doc/shopify/search.oz-related-product-block-html.liquid).
Example for `display_secondary_image`:
```html
{% include 'product-thumbnail', display_secondary_image: settings.collection_secondary_image, product: product %}
```
3. Parameters that are calculated in previous sections or snippets won't be accessible, and the same goes for parameters that come from section settings (ex: `section.settings.my_variable`).
For those, in the product block snippet (`product-thumbnail.liquid` for eg.), in the same HTML element we added the `cs-product-container` class, chain those remaining parameters in an attribute called `data-cs-params`. Parameters should be separated by a `|`. The first one is **mandatory** and should always be the `collection.handle`.
Example:
```html
```
4. Retrieve those parameters
In `search.related-product-block-html`, these parameters will be available from the URL, in the `query_params` variable.
They will all be in a String format.
Unchain them and pass them onto the product snippet. The first one will always already be used for the product handle, used to retrieve the `product`.
*Note 1:* Booleans should be interpreted as below as they arrive in this template as Strings.
*Note 2:* The order in which params are listed in `data-cs-params` matter.
Example :
```html
{%- layout none -%}
{% assign query_params = search.terms | split: '|' %}
{% assign product_handle = query_params[0] | strip %} // PARAMETER 0 is the product handle
{% assign collection_handle = query_params[1] | strip %}
{% assign product = all_products[product_handle] %}
{% assign collection = collections[collection_handle] %}
{% assign products_per_row = query_params[2] | plus: 0 %} // CUSTOM PARAMETER 1 (the 'plus: 0' transforms the String into and Integer)
{% assign sidebar = false %} // CUSTOM PARAMETER 2 (Booleans arrive as String so also need to be converted)
{% if query_params[3] == 'true' %}
{% assign sidebar = true %}
{% endif %}
{% comment %}
PARAMETERS (example from PDS)
- comes from section.settings
- comes from collection-template and is calculated in liquid
- comes from section.settings
{% endcomment %}
{%- capture swatch_block_html -%}
{% include 'product-thumbnail', product: product, collection: collection, products_per_row: products_per_row, sidebar: sidebar, display_secondary_image: settings.collection_secondary_image %}
{%- endcapture -%}
{
"product_block": {{ swatch_block_html | json }}
}
```
## 7. Input the number of swatches to display in the settings of the theme
![Swatches number setting](/img/swatches-number-setting.png)
## 8. Add custom swatches on collection page - Integration with USF
### 8.1. Make relevant product data available to USF
1. In `templates`, add [search.oz-usf-related-products-json.liquid](/doc/usf/search.oz-usf-related-products-json.liquid).
2. In `snippets`, add [search-oz-usf-related-product-json.liquid](/doc/usf/search-oz-usf-related-product-json.liquid).
### 8.2. Insert Custom Components
In `theme.liquid`, add a `usesCustomRelatedProductsSwatches` property in `window.theme.settings`.
```html
```
### 8.3. Define swatch custom components
**Important**: make sure `npm run dev` is not running for these (-:
In _Apps > Ultimate Search > Customization_, select the correct theme and insert the [custom components](/doc/usf/components.js) between the opening and closing tags of the function created in here: `usf.event.add`.
(`usf.event.add('init', function () { PLACE THEM IN HERE });`).
### 8.4. Call custom swatch component with relevant flags
In `searchResultsGridViewItem` and `searchResultsListViewItem`, add the following element where the swatches need to be.
```html
```
Several flags most likely need be added to that `` line to ensure the custom component works seamlessly with available features in the theme.
### Flag list:
| Type | Default value | Name | Description |
| :--: | :-----------: | ------------------------------------- | ---------------------------------------------------------------------- |
| prop | `false` | `canHaveVideo` | If product can have a video as media |
| prop | `false` | `showAvailableSizes` | Shows available sizes but doesn't have quick add to cart functionality |
| prop | `false` | `hasInternalSlidehow` | If product item on collection page has slideshow |
| prop | `false` | `hasSmartWishlist` | If the Smart Wishlist app is installed and used on collection page |
| prop | `false` | `hasQuickShop` | If product has quick shop |
| prop | `false` | `hasQuickView` | If product has quick view |
Examples:
```html
```
### 8.5. Add relevant classes in USF components/templates
1. In `searchResultsGridViewItem`:
1. Add the `oz-cs-product-title` **class** to the HTML element that contains the **product title**.
2. Add the `oz-cs-product-link` **class** to all `` elements that contain a **link to the product page**.
3. Add the `oz-cs-product-price-container` **class** to to the HTML element that contains the **product price** (goes next to `vp-original-prices` if VPs are installed).
4. In the `updateAvailabilityCurrentItem` function, add the right value for 'wording'. It needs to point to the translation of "sold out".
5. _(optional)_ **If product doesn't have internal slideshow but has first and second image (on hover):**
- Add the `oz-cs-featured-image` **class** to the `` element that contains the **featured image**.
- Add the `oz-cs-hover-image` **class** to the `` element that contains the **hover image**.
6. _(optional)_ **If product shows available sizes left:**
- Add the `oz-cs-available-sizes-container` **class** to to the HTML element that contains the **available sizes**.
-> If HTML element doesn't exist yet, add the [oz-product-sizes](/doc/usf/oz-product-sizes.js) component.
7. _(optional)_ **If product has internal slideshow:**
- Add the `oz-cs-slideshow-images` **class** to to the HTML element that contains the **slideshow images**.
- Add the `oz-cs-slideshow-current-image` **class** to to the HTML element that contains the first **slideshow image**.
8. **If product can have videos displayed in collection page**
- Add the `oz-cs-media-container` class to to the HTML element that contains the **product video**.
- Add the `oz-cs-mmedia-container` class to the HTML element that contains the **product images or slideshow**.
2. _(optional)_ **If product has a quick shop feature:**
- Add the `oz-cs-quickshop-container` **class** to to the HTML element that contains all **quickshop-related elements**, (which should be situated in the **quick-shop** component).
**SUMMARY**
| Type | Condition | Name | To be placed in |
| :--: | :-----------: | ------------------------------------- | ---------------------------------------------------------------------- |
| class | *Mandatory* | `oz-cs-product-title` | the product title
| class | *Mandatory* | `oz-cs-product-link` | all `` elements that contain a link to the product page |
| class | *Mandatory* | `oz-cs-product-price-container` | the product price (min. 2x if VPs) |
| class | no slideshow | `oz-cs-featured-image` | the `` that contains the main image (when there's no slideshow) |
| class | no slideshow | `oz-cs-hover-image` | the `` that contains the second image (when there's no slideshow) |
| class | shows available sizes + no quickAddToCart | `oz-cs-available-sizes-container` | the wrapper of available sizes |
| class | has slideshow | `oz-cs-slideshow-images` | the wrapper of slideshow images |
| class | has slideshow | `oz-cs-slideshow-current-image` | the wrapper of the first slideshow image |
| class | has quickshop | `oz-cs-quickshop-container` | the wrapper of the quickshop |
| class | can have video | `oz-cs-media-container` | the wrapper of the video |
**EXAMPLES**
1. Example for `oz-cs-media-container`:
```html
```
2. Example for `oz-cs-quickshop-container`:
```html
```
### 8.6. Add proper HTML for price
In `updateProductPrice()` in `usf-custom.js`, update the value of `template` to reflect the current site's look.
*Note 1:* don't forget to handle the `vp-prices`!
*Note 2:* don't forget to handle any custom product tags
*Note 3:* don't forget to handle the case where the product price can vary (`product.price_varies`)
### 8.7. Add proper HTML for price
In `initialiseInternalSlideshow()` in `usf-custom.js`, adapt the value of `template` to reflect the current site's look.
### 8.8. Handle available sizes
If product item displays available sizes, when a swatch is clicked, an `oz-swatch-swapped` event is emitted. This need to be listened to in the USF component that manages available sizes.
In the USF-made `product-sizes` component, handle the `oz-swatch-swapped` event in the `mounted()` function.
Example:
```javascript
RVue.component('product-sizes', {
// (props, data)
mounted() {
this.$parent.$on('oz-swatch-swapped', data => {
if(data.sizes.length > 0) {
this.sizes = data.sizes;
this.hasSizes = true;
} else {
this.hasSizes = false;
}
});
}
// (methods, template)
});
```
Full component code example [can be found here](/doc/usf/productSizesComponent.js).
## 9. (optional) Refresh swatches logic on collection page when needed
In some cases (filtering, sorting, infinite scrolling,...) where products are dynamically changing on the page, the swatch logic needs to be re-rendered.
Calling `document.dispatchEvent(new Event('cs-rerender'));` will go over all the non-initialised swatches.
## 10. (optional) Refresh uninitialised elements after swatches has been refreshed
Some elements on the collection and search pages or on the cross-selles need to be manually initialised when the product block content is loaded (ex: the heart widget in Smart Wishlist).
For those cases, we can listen to the `cs-rerendered` event, which is dispatched when the HTML of a product block has been replaced with the new product's content.
Example:
```javascript
export function onSwatchClickedReinitSmarwishlist() {
document.addEventListener('cs-rerendered', reloadSmartWishlist);
}
```
## 11. Make sure to remove any legacy swatch code!
Or to make old version administrable, according to site's needs.
## Notes
- It is possible to deactivate the entire module from the settings of the theme.
![Deactivate module](/img/deactivateModule.png)
- Give names to swatches
![Options names setting](/img/options-names-setting.png)
- Choose which swatches to display in product page
![Options to display in product page setting](/img/options-to-display-in-product-page-setting.png)
- Choose which swatches to display in collection page and cross-sell sections
![Options to display elsewhere setting](/img/options-to-display-elsewhere-setting.png)
- If something is not working properly, make sure jquery is available
*(note: soon-to-be-deprecated-as-all-of-jquery-will-be-removed-very-very-soon :-) )*
```javascript
import jquery from 'jquery';
window.$ = window.jQuery = jquery;
```