Template Editor
The Template Editor allows customization of Template Editor templates (TETemplates).
TETemplates are sent with response data from the Slice API and used to render the Frontend App components.
At the moment, the number/names of TETemplates fixed. However, the system could easily be extended to support arbitrary TETemplate configurations.
Current TETemplates:
- Layout /
layout
- Header /
collection_header
- Pagination /
pagination
- Filters /
filters
- Filter /
filter
- Filter /
- Sort /
sort
- Views /
templates
- Products /
products
- Header /
Writing TETemplates
TETemplates are written in HTML with VueJS bindings.
Every TETemplate has access to the entirety of App.DataModel
(see Frontend App for more info).
App.DataModel
The App.DataModel
data structure looks like this:
{
loading: boolean,
api: {
version: integer,
urls: {
withId: string,
withDomain: string,
styles: string,
}
},
responseErrors: {
code: integer "code identifying the error cause",
message: string "human-readable error information",
fatal: boolean "if true, the app should exit / no allow more user input",
showSetupHelp: boolean "if true, this error is probably setup-related"
},
site: {
id: integer "EscNavindexer Site/Project ID",
domain: string "shop's myshopify domain"
},
components: {
"key-value pairs indicating VueJS model-template mappings"
},
header: {
collection: {
title: string "collection context title",
description: string "collection context description"
}
},
context: {
collection: string "collection context handle",
search: string "search context terms"
},
filters: [
"contextual filters. see Filters section",
],
pagination: {
total_products: integer "the total number of results",
current_page: integer "current page. may be zero if no results",
total_pages: integer "total number of pages",
page_size: integer "current number of results per page",
options: [
"list of page size options"
{ page_size: integer, default: boolean },
]
},
products: [
"results. see Products section"
],
templates: {
active: 'default' "the current set of templates active",
all: [
{
key: 'default',
components: [
"template data"
]
}
]
},
sort: {
active: string "the current sort option",
default: string "the default sort option",
all: [
"list of sort options. see Sort section",
],
},
debug: [
"list of debug messages"
],
errors: [
"list of error messages"
],
autofilters: [
"list of autofilters"
],
state: {
"arbitary metadata. see State section"
}
}
Filters
Filters are defined in App.DataModel
as the array filters
. Each element of the array represents one filter:
{
condition: string "how the filter is applied to the query",
context: {
"hash of contextual information about how this filter is applied"
},
id: integer "filter ID",
label: string "the human-readable label for this filter",
metadata: {
"arbitary data"
},
mode: string "how this filter should be displayed",
selection: [
"array of currently selected values"
],
type: string "the field this filter is applied against",
values: [
"array of available filter values"
]
}
The metadata
property can hold arbitary data that will not be lost when filters are reloaded. You can use this, for example, to implement collapsable filters:
<div :class="{ filter: true, collapsed: filter.metadata.collapsed }">
<label>
{{ filter.label }}
<button @click="filter.metadata.collapsed = !filter.metadata.collapsed">
{{ filter.metadata.collapsed ? '+' : '-' }}
</button>
</label>
<ul>
...
</ul>
</div>
Sorting
Available sorting methods are defined in App.DataModel
as the array sort.all
. Each element of the array represents one sort option:
{
custom_label: string "a custom label for this method. May be empty",
default: boolean "true if this is the default sorting method",
enabled: true "should always be true for available sorting methods",
key: string "the key for this method. App.DataModel.sort.active should be set to this",
label: string "the boring name for this sorting method. try to use custom_label if it exists"
}
Example usage:
<select v-model="sort.active">
<option v-for="option in sort.all" :value="option.key">
{{ option.custom_label || option.label }}
</option>
</select>
Products
Product results are defined in App.DataModel
as the array products
. Each element of the array represents one product:
{
created_at: string "timestamp",
handle: string,
has_stock: boolean "indicates if any variant of this product is in-stock",
id: integer "EscNavindexer product ID",
images: [
"array of product images"
{
created_at: string "timestamp",
id: integer "EscNavindexer image ID",
image_created_at: string "Shopify timestamp",
image_id: string "Shopify ID",
image_updated_at: string "Shopify timestamp",
position: integer,
product_id: string "Shopify product ID",
shop_id: "EscNavindexer Site/Project ID",
src: string,
updated_at: string "timestamp"
}
]
"max_price_units": integer "price of the most expensive variant",
"min_price_units": integer "price of the least expensive variant",
option1: string "name of option1",
option2: string "name of option2",
option3: string "name of option3",
product_created_at: string "Shopify timestamp",
product_id: string "Shopify ID",
product_published_at: string "Shopify timestamp",
product_type: string,
product_updated_at: string "Shopify timestamp",
published_scripe: string,
shop_id: integer "EscNavindexer Site/Project ID",
tags: string "Product tags joined by ', '",
title: string,
updated_at: string "timestamp",
variants: [
"array of variant information",
{
barcode: string,
compare_at_price_units: integer "compare at price",
created_at: string "timestamp",
fulfillment_service: string,
grams: integer,
has_stock: boolean "indicates if the variant is considered in-stock",
inventory_managment: string,
inventory_policy: string,
inventory_quantity: integer,
option1: string "option1 value",
option1_label: string "option1 label",
option2: string "option2 value",
option2_label: string "option2 label",
option3: string "option3 value",
option3_label: string "option3 label",
position: integer,
price_units: integer "price",
product_id: string "Shopify product ID",
requires_shipping: boolean,
shop_id: integer "EscNavindexer Site/Project ID",
sku: string,
title: string,
updated_at: string "timestamp",
variant_created_at: string "Shopify timestamp",
variant_id: string "Shopify variant ID",
variant_updated_at: string "Shopify timestamp",
weight: integer,
weight_unit: string
}
],
vendor: string
}
App VueJS filters
You can use the following VueJS filters anywhere in a TETemplate:
Money
Formats a value as money.
{{ 13921 | money }}
{{ product.price_units | money }}
£139.21
£139.21
Filter Option Format
Automatically decides how to format a filter option.
<ul>
<li v-for="option in filter.values">
<label>
<input type="checkbox" v-model="filter.selection" :value="option">
{{ option | filter_option_format filter }}
</label>
</li>
</ul>
<ul>
<li>
<label>
<input type="checkbox">
£32.10
</label>
</li>
</ul>
Filter Option Format Array
Automatically decides how to format an array of filter options. Useful when you need a string of selected options.
<p>Selected: {{ filter.selected | filter_option_format_array filter }}</p>
<p>Selected: £40, £45, £50</p>
Styles
The Template Editor has a section called Styles. This is not a TETemplate.
The SCSS-format stylesheet provided will be compiled to CSS and served at https://navindexer.eastsideco.io/api/v1/styles.css?shop={myshopify_domain}
, which is loaded automatically by the Frontend App.