The Solid template language is the language you will be using to quickly build custom templates for your store. There is no need to learn or know PHP, Ruby or any other programming language, although you will be using simple programming concepts like "loops" in your templates.
For those that already are familiar with simple PHP, ASP.NET, Ruby or any other programming language, our syntax will be super simple. For those new to programming we have kept everything as simple as possible and we are keeping documentation up to date at any time to make building templates a fun and easy to learn process.
If you need help, shoot us a message on Twitter, Facebook or via email.
You'll be up in running in no time once you know the basics of how themes are structured. Take a look at any of the available themes under the "Design" tab of your store. You will see a list of available template files once you click "customize" on a theme.
We have structured our documentation in the same way that your themes are structured. The following template files can be found in any theme. When searching for help for a specific template, you can find the necessary information grouped in the same way in these help files.
| Template File | Usage |
|---|---|
| cart | Your shopping cart |
| category | Show products by category |
| index | This is the homepage of your store |
| page | Template to display page details |
| product | Template to display details about a product |
| search | Search results |
The best way to start building custom themes for your store is by skimming through our syntax examples.
This example will render an unordered list with all categories you
have in your webshop like "dvd series", "movies", "dvd-r", ... We can
use this same loop technique whenever we want to display multiple items
like products or pages.
You can use comments within the template language, to clarify the code you have written. Use {# ... #} for that.
The SolidShops template language makes a difference between setting a variable and getting the contents from a variable. In the example below, we first declare a variable named "myname" and put the value 'Earl' in it (the quotes are just there to mark the variable as being a string.
On the second line, we print the value of variable myname by using curly braces. Note the difference in syntax when declaring a variable and when reading it out.
If you want, you can also put whole chunks of HTML in a variable.
A variable can also contain attributes, just like an array in any programming language. To access attributes of a variable use a dot (.).
As we said earlier, the curly braces in the example above are only there to print out the variable, they are not part of the variable name itself.
Arrays can be created as follows:
If you want to create a multi-dimensional array, you can do that as well:
To control the flow of your templates, you can use conditionals or loops. Control structures are always placed inside {% ... %} blocks.
To loop over each item in a collection or array, use a for loop.
Example: loop over numbers
Example: loop over letters
Inside a for loop, you can make use of special variables if you need them. The following variables are available:
| Variable | Description |
|---|---|
| loop.index | The current iteration of the loop. (1 indexed) |
| loop.index0 | The current iteration of the loop. (0 indexed) |
| loop.revindex | The number of iterations from the end of the loop (1 indexed)) |
| loop.revindex0 | The number of iterations from the end of the loop (0 indexed) |
| loop.first | True if first iteration |
| loop.last | True if last iteration |
| loop.length | The number of items in the sequence |
| loop.parent | The parent context |
If there are no elements to loop over, you can show alternative content by using an "else" block.
Use the "if" structure to check a variable against a given value.
Use "if" to check if a variable is available, not empty or not false.
You can combine multiple expressions in if statements or for structures:
and: Returns true if the left and the right operands are both true.or: Returns true if the left or the right operand is true.not: Negates a statement.The following is a list of built-in tests that you can use:
divisibleby: checks if a variable is divisible by a numbereven: checks if a variable is an even numberodd: checks if a variable is an odd numberdefined: checks if a variable is definedempty: checks if a variable is null, false or an empty stringExpressions can be used just like you would use them in PHP or similar languages. The following expressions are available:
Filters and functions are useful when you want to manipulate variables or values in a certain way. Examples can be converting text to UPPERCASE or formatting a date to a certain format. The following filters can be used in your templates:
Convert the first letter of the string to uppercase. All other letters are lowercase.
Limit the number of characters to print from a given variable.
Format a number to a currency format of your liking.
The currency filter has several formats that you can use:
Use the cycle function to cycle between values in an array, based on a counter.
The array can contain as much values as you like:
Note that it can be easier to just loop over an array the standard way:
Format a date to a given format.
The escape or e filter converts occurences of characters &, <, >, ', and " in strings to their HTML-safe equivalents.
Convert a string into an array based on a delimiter
If a user has used the "insert more break" button to define an excerpt in a product or page description, we can show only the excerpt instead of the full description by using the excerpt filter.
Convert a data object into Javascript Object Notation (JSON)
Returns the length of a string or the number of items in a sequence or collection (of products for example).
You can use this in many situations such as counting the number of images a product has in an IF-statement:
Convert the string to lowercase.
Generate a random number (between two numbers).
Revert an array.
Sorts an array.
The string_replace function replaces all occurences of a string with a new string.
Strips the html and xml tags from a string.
Strips all excess whitespace (new lines, tabs, double spaces) from a string.
Convert the first letter of every word to uppercase. All other letters are lowercase.
Convert the string to uppercase.
Encode a given URL
Format a weight to a format of your liking.
returns a string without the whitespaces at the beginning and end
The Solid template language lets you access all data segments in a given URL. Let's take a look at the following URL:
By segments we mean everything that appears after your domain name, in this case "category" and "computers". Accessing these segments can be done as follows:
That will get you "category", the first segment after the domain name. To grab "computers" from the url, you simply do the following:
First, create a CSS file by clicking on the "add new file" button.
Once you have created and populated a CSS file, you can link it in your theme by using solid.css() as follows:
The function above will generate the following result in your template:
The solid.css() function takes two arguments:
| Argument | Value | Description |
|---|---|---|
| 1 | filename(s) | the filename(s) you are loading |
| 2 | media | standard css media types like "screen" or "print" |
Example 1: generate stylesheet link for screen.css.
Example 2: load file reset.css and screen.css (in that order) and put the media attribute to "screen"
An alternative way to link CSS files is by uploading them with the "assets manager" and just linking them with normal CSS code as you would normally do in HTML.
If you want to upload CSS files (or other files) e.g. when using a jQuery plugin that has a uses a number of files, you can do so like this:
After clicking the "manage my assets" button on the right side of your screen, you can organize your assets in any way you want. Create subfolders for CSS, Js, images, ... if you want and upload the files to the location of your preference. In this example, we'll just upload a CSS file in a folder called CSS.
Now that you have uploaded an asset to your assets folder, you can link to it in the same way you are used to build html templates. Just make sure you include a reference to your assets folder {{ solid.assets_url }}.
Loading JavaScript files works in a similar way as loading css files. Call the function solid.js() and pass in the name of the file you want to load as a parameter, like this:
| Argument | Value | Description |
|---|---|---|
| 1 | filename(s) | the filename(s) you are loading |
This will result in the following in your template:
Example: load multiple js-files at once
This will output two links to your javascript files:
If you rather want to upload your JavaScript files to your assets folder and link to them, please read the section above about loading CSS-files. The process for linking JavaScript (or any other file) is the same as described above.
When you are creating templates, you will probably be repeating yourself over time. For example, it's common to have the same footer or header on every template. You can save yourself some work by creating an include file for pieces of your code that are repeated in more than one template.
If you want to create a footer and include it in your templates, do the following:
First, create a partial called "footer", which will include a little copyright notice that we want to reuse in all our templates.
Next, put some content in the footer partial and save the file.
Now you have created a partial that you can re-use anywhere in your templates. For example, we'll want to re-use the footer in our index template, our homepage.
At the bottom of our index page, we'll load or include the partial we just created.
You are not limited to use this for footers or header. We use the embed() method to embed the same CSS file in all templates or to use the Google Font API in all our pages. Be creative!
The products template can be used to display details about a single product. The product tag can be used to access all information about your products or about one single product.
You can get the following data from any product in your store:
| Attribute | Description | ||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| always_available | returns true if you have indicated that users can buy this product when it's out of stock, otherwise false. Also returns true if you are not tracking stock |
||||||||||||||
| id | the unique ID of your product | ||||||||||||||
| description | the product description | ||||||||||||||
| date_modified | the date you last saved a product | ||||||||||||||
| name | the name/title of your product | ||||||||||||||
| nicename | the unique name of your product | ||||||||||||||
| price | the price of the product | ||||||||||||||
| stock | the actual stock count for this product, empty if stock tracking is disabled | ||||||||||||||
| tags | the tags your entered for a product | ||||||||||||||
| thumbnail | the thumbnail image of your product | ||||||||||||||
| track_stock | returns 0 if you have disabled stock tracking , 1 if stock is tracked on product level, 2 when stock is tracked on variant level |
||||||||||||||
| url | the url to point to the detail page of this one product (system template "product") | ||||||||||||||
| weight | the weight your entered for a product | ||||||||||||||
| categories | a loopable collection of all categories that are linked to a product Each category contains the following attributes:
|
||||||||||||||
| variants | a loopable collection of all variants that are linked to a product Each variant contains the following attributes:
|
||||||||||||||
| variant_combinations | a loopable collection of all variants combinations that are used in the product Each variant combination contains the following attributes:
|
||||||||||||||
| images | a loopable collection of all images for the current product Each image object contains the following attributes:
|
Take a look at the following example. product.getList() will load all your products, after which you can loop over them.
Note the use of {{product.url}} in the example above. When displaying a listing of products in your store, you can use the "url" property to get a URL in the following format: http://www.myshop.com/product/46/ipad/. This will link a product to its detail page. See the next chapter for more about loading a single product.
To display the details of a single product, you need to edit the "product" template and get the current product details. This can easily be accomplished as follows:
Instead of .name, you can now use any of the available product attributes.
Please note that the product.get() function normally requires a "nicename" parameter. When you are on the product template, on a url like http://demostore.solidshops.com/product/productname, we will automatically read out the nicename "productname" from your url.
If you want to, you can pass in the nicename of a product in the function product.get(nicename) like so:
It's possible to limit the products that are loaded, to only products that are e.g. in a certain category or that have a specific id. You can define filters or options like this:
Then call the getProducts() function as usual, but pass the options, like this:
Available filter attributes
| Filter | Description |
|---|---|
| cat | filter by category name or nicename - example: "cat":"apple" or "cat":"apples|bananas" |
| count | the number of products on your screen or per page (if pagination is set to true) - example: "count":"10" |
| id | get one or more products by id: example: "id":"1" or "id":"1|5|3" |
| nicename | filter by product nicename - example: "nicename":"coffeecup" or "nicename":"coffeecup|cappucinocup" |
| tag | filter by product tags - example: "tag":"red" or "tag":"red|green|blue" or "tag":"red,green , blue" |
| order | id, name, price, datemodified, random - example: "order":"name", "order":"name:asc|datemodified:desc" or "order":"random" |
| pagination | whether you want pagination or not - example: "pagination":"true" or "pagination":"false" |
| search | filter by any give search term - example: "search":"pizza" |
You can add custom fields to your products. See our documentation here for details on how to easily add custom fields to your products.
To read out custom product data in your store templates, you can do the following. Please note that the examples below will only work if you already have a field group with custom fields linked to your products.
Load a product, just like you would normally do. Then, you can loop over all custom fields that are linked to a product, like so:
This will loop over all available custom fields and fields in a standard Key-Value array loop. The following screenshot gives you a visual representation of how the custom fields are structured.
If you don't want to loop over all your custom fields but need quick access to just one of your custom product fields, you can do the following:
If you don't want the value but the field label, use .label:
If you have e.g. 50 products in your store and want to show them per 10 on a page you can use the pagination object. For pagination to work, you need to set the "pagination" parameter to "true" when you load products. See the getProducts() function just above for that.
The pagination object has the following attributes that you can use.
| Attribute | Description | ||||||
|---|---|---|---|---|---|---|---|
| pagination.pages |
A loopable collection of all pages in the pagination object.
This collection contains the following attributes:
|
||||||
| pagination.previous | The number of the previous page. This variable is empty if there is no previous page. | ||||||
| pagination.previous_url | The url to link to the previous page | ||||||
| pagination.next | The number of the next page. This variable is empty if there is no next page. | ||||||
| pagination.next_url | The url to link to the next page |
To add a product to your shopping cart, we need to create a small form tag with a submit button, per product. This concept can be used in the "page" system template for one product or even in a list of products.
The following is necessary to add a product to a shopping cart:
1. form with action="/cart/add/{{product.id}}
2. a submit button within that form
Please notice the reference to the product id you want to add to the cart. In the following example we have added a text field named 'quantity' to allow a user to select the quantity to add. If you don't add the quantity text field, 1 will be the default quantity to add to the cart.
The product id is available when loading products using either the product.getList() or the product.get() method.
When adding products that contain variants to your cart, you have to make sure you give your users the chance to select a certain variant. You could build select boxes automatically for your products variants using the following code:
The name of your select box is important. The name value should be in the format variant_1 where 1 is the id of the variant type.
The pages tag can be used to access all information about your pages or about one single page. You can get the following data from any page in your store:
| Attribute | Description |
|---|---|
| id | the unique ID of your page |
| nicename | the unique name of your product, often used in url's |
| name | the name/title of your page |
| content | the content of your page |
| date_modified | the date you last saved a page |
| url | the url to point to the detail page of this one page (system template "page") |
Take a look at the following example. page.getList() will load all your pages, after which you can loop over them.
Note the use of {{page.url}} in the example above. When linking to a page, you can use the "url" property to get a URL in the following format: http://www.myshop.com/pages/46/my-page-title/. This will link a page to its detail page. See the next chapter for more about loading a single page.
To display the details of a single page, you need to edit the "page" template and get the current page details. This can easily be accomplished as follows:
Instead of .name, you can now use any of the available page attributes.
Please note that the page.get() function normally requires a "nicename" parameter. When you are on the page template, on a url like http://demostore.solidshops.com/page/pagename, we will automatically read out the nicename "pagename" from your url. If you want to, you can pass in the nicename of a page in the function page.get(nicename), like so:
Filter attributes It's possible to limit the pages that are loaded, by limiting the amount of pages loaded or by limiting them by ID. You can define filters or options like this:
Then call the getPages() function as usual, but pass the options, like this:
Available filter attributes
| Filter | Description |
|---|---|
| nicename | limit the pages you load based on nicename(s): "nicename": "about" or "nicename":"about|contactus" |
| count | limit the number of pages you want to load: "count":"5" |
| order | id, name, datemodified, random- example: "order":"name", "order":"name:asc|datemodified:desc" or "order":"random" |
| id | get one or more pages by id: example: "id":"1" or "id":"1|5|3" |
| Attribute | Description |
|---|---|
| id | the id of your category |
| parent_id | the id of the higher category |
| name | the name of your category |
| nicename | the url friendly nicename of the category |
| url | the url to point to the detail page of this one category (system template "category") |
| subcategories | a loopable collection of "category" objects |
Available filter attributes
| Filter | Description |
|---|---|
| id | limit the categories you load based on id(s): "id": "1" or "id":"1|4" |
| nicename | limit the categories you load based on nicename(s): "nicename": "about" or "nicename":"about|contactus" |
| order | id, name, random - example: "order":"name", "order":"name:asc|id:desc" or "order":"random" |
Here's an example to get you on your feet quickly when looping over all your existing product categories. The following example could be useful when building a navigation menu.
If you are using subcategories, you can render these out as well, like so:
A much used technique is the following: image you have a "category" template where you show an overview of products in a certain category or subcategory. You can load the current category your user is browsing by adding the following line to your template:
We will automatically populate the category object with the details of that category, even when it's a subcategory. When you are browsing a subcategory "shirts", you can easily print out something like:
That's great, but for search engine rankings it can be a good idea to show the breadcrumb structure with the parent category info added to it as well, like this:
To display the details of a single category, you need to edit the "category" template and get the current category details. This can easily be accomplished as follows:
Instead of .name, you can now use any of the available category attributes.
Please note that the category.get() function normally requires a "nicename" parameter. When you are on the category template, on a url like http://demostore.solidshops.com/category/categoryname, we will automatically read out the nicename "categoryname" from your url. If you want to, you can pass in the nicename of a category in the function category.get(nicename)
The order variables are mostly used when customizing email templates to send out with every new order that comes in. See the code sample below for an example of how to use these variables.
| Attribute | Description | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| id | the order ID | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| date_created | the date at which the order was created | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| date_paid | the date at which the order was paid, empty if the order is not paid yet | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| items_quantity | the number of products in the order | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| items_subtotal | sum of all product prices, excluding shipping and taxes | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| items_tax | total taxes | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| items_total | sum of all product prices, including taxes, excluding shipping | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| shipping_cost | shipping cost for the order, excluding taxes on shipping costs | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| shipping_tax | taxes charged on the shipping cost (if set in settings) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| shipping_total | total shipping costs, including taxes on shipping costs (if set in settings) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| total | order total, including all taxes and shipping costs | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| payment_text | if you have added custom payment messages in your checkout settings page, we will load them up here, depending on the selected payment method your client has selected. If they have paid online and there is not custom payment text, we will leave this variable empty. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| pdf_invoice | the url of the pdf invoice document. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| coupon | object containing information about the used coupon
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| attributes |
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| items | a loopable collection of all items in the order
Each item contains the following attributes:
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| customer | object containing information about the customer that placed the order
|
Here's an example of how you can build up a custom confirmation email by using the available variables for an order that a customer places in your store.
You can get general information such as the current currency, the home url, ... from you shop. There is no object "shop" so the syntax is a bit different than what you are used to. The following variables are available:
| Attribute | Description |
|---|---|
| shop_name | the name of your shop |
| currency | the selected currency for your shop |
| currency_decimal | the decimal separator ( . or , ) |
| currency_thousand | the decimal separator ( . or , ) |
| currency_symbol | the symbol of the currency that is set in the backend |
| shop_url | the url of you store, http://yourdomain.solidshops.com or www.customdomain.com depending on your settings |
| assets_url | the url to your assets (images, files, ...). You can use this to build <img> tags, or in CSS to link to background images |
| products_count | the total number of active products in your store |
Example: create a home link
This will output:
Example: link to images and backgrounds in your assets folder
In HTML:
In CSS:
Just like you can loop over products, categories and pages, you can also render your shopping cart in any layout you want. Call the shopping cart data like this:
As you might have notice you can write anything you want instead of "cart". That's just a variable name. The cart will be filled with items, once somebody has added a product to the cart.
To loop over all items in your cart, you could do something like this:
| Attribute | Description | ||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| cart.items_quantity | the total number of items in your cart | ||||||||||||||||||||||||||||||||||||||||||||
| cart.items_subtotal | cost for all items in your cart, not including taxes | ||||||||||||||||||||||||||||||||||||||||||||
| cart.taxsetting | "incl" or "excl" depending on your shop settings | ||||||||||||||||||||||||||||||||||||||||||||
| cart.items_tax | total taxes for the items in your cart | ||||||||||||||||||||||||||||||||||||||||||||
| cart.items_total | total cost for all items in the cart, including taxes | ||||||||||||||||||||||||||||||||||||||||||||
| cart.shipping_cost | shipping cost for the items in your cart, not including taxes on shipping (if set) | ||||||||||||||||||||||||||||||||||||||||||||
| cart.shipping_tax | taxes charged on shipping costs (if set) | ||||||||||||||||||||||||||||||||||||||||||||
| cart.shipping_total | total shipping cost for the items in your cart, including taxes | ||||||||||||||||||||||||||||||||||||||||||||
| cart.total | grand total of your shopping cart, including taxes and total shipping cost | ||||||||||||||||||||||||||||||||||||||||||||
| cart.coupon_code | If you accept discount coupons, this is the code a user has entered | ||||||||||||||||||||||||||||||||||||||||||||
| cart.coupon_type | If a user has entered a coupon code, this contains the type of discount e.g. "cart_total" or "shipping" | ||||||||||||||||||||||||||||||||||||||||||||
| cart.coupon_discount | If a valid discount coupon has been entered, this contains the actual discount value. | ||||||||||||||||||||||||||||||||||||||||||||
| cart.attributes |
|
||||||||||||||||||||||||||||||||||||||||||||
| cart.items |
|
Here's a complete shopping cart example to get you started:
Please note the line where we have added a field with name="quantity_{{ item.id }}". When you name the field that way, SolidShops can automatically detect what product (and variant if you used one) you are changing the amount for.
If you want to give the user the opportunity to select his ship-to country, you can do this by calling the method solid.htmlShippingCountries(). This will roll out a list of available destinations to ship to, based on your shipping preferences.
Sometimes or even most of the times you may want to provide a "remove item" option in your shopping cart. We will need a form that posts the correct product ID that has to be removed, like so:
This link (or it can be an image, as long as it links to the correct url) needs to be available next to every item in your shopping basket, so you can e.g. put it in a table within your {% for item in cart.items %} loop.
You can add up to 5 attributes to each cart item and 5 to the cart itself. These attributes are used to add some extra customer fields to the cart. Some implementations are fields like "customer engraving","cartnote","deliverydate".
item attributes:
For each item in your shopping cart you can define up to 5 attributes.
product / add to cart:
cart template:
cart attributes:
For each item in your shopping cart you can define up to 5 attributes.
cart template:
The search template file can be used to display search results in your store. Building a basic search form for your online store can be done as follows:
You can place this form anywhere in your store. It's important to use the correct action "/search" as we will post your query to your search template through the URL. Also make sure that your search text field has the attribute name="query" in it. That way we know where to get your search term.
When somebody searches for e.g. "apples" by submitting the search form above, the user will be redirected to e.g. http://yourstore.solidshops.com/search/computers
Now we need to build up the search results page, in the same consistent way we build up the products, pages and categories pages. You can find the "search" template in your theme files.
To build up a list of products that match the search term, first we need to get the search term from the url by using url segments. Take a look at the following example:
The example above gets url segment number 2 from our url http://yourstore.solidshops.com/search/computers. Now we have a search parameter "computers" which we pass to the products options.
If you want you can pass along more parameters to build in pagination or order products in a certain way. See here for more product filter attributes.
Some stores require a custom contact form. You can build a contact form in any of your templates. Below is a fully working example of a contact form. Let's take a look at how it's been built and how it works.
You wil need the following to create a custom contact form:
If you want to make some fields required, you can do so by using javascript.
In the example above, you can see that we check url segment 3 against the word "false". When a users submits your form, we check whether or not the captcha was correct. When correct, we send and email to the contact email address you provided in your general store settings and we will create a URL like http://yourstore.solidshops.com/contact/status/true. This way you can detect if your form was sent and inform your user about this action. If the form submission fails (because of a bad captcha), we will return a URL http://yourstore.solidshops.com/contact/status/false
The Solid template language uses parts of the Twig library.
Parts of this documentation page are based on the original Twig documentation and are attributed to them.