Liquid Tutorial 8 - Joining Liquid files together with include/render

With the powerful include and render tag, you can use Liquid to pull in other Liquid files into the file you're working in. This allows you to access oven-ready Siteglide functionality and efficiently re-use your own content across your site.

Written By Matt Jones

Last updated About 1 month ago

Liquid Partials

One of the benefits of Liquid over plain HTML is that we can join files together instead of writing all our Liquid in one page.

Liquid files which join together are called partials; literally, they are a part ial of a page.

Using partials is beneficial because:

  • It avoids repetition

  • It makes code more maintainable by abstracting - allowing files to carry out specific roles and making it easier to read and test each file separately and understand its function.

You can learn more about partials here: Tags for Includes

Special kinds of includes can be created via Siteglide Admin e.g. Content Sections Content Sections

A Studio Section is another special kind of partial, which can be created using Studio and there is a special UI for including these in a Studio page: Theme Sections

To get complete freedom over creating Liquid Partials, you need to use the Siteglide CLI: Includes with Siteglide CLI & Introduction

Creating a Partial in CLI

When you have pulled a Site with Siteglide CLI, there are two different places in the file structure where a partial can be created- either is fine, but each folder is designed for a slightly different purpose:

Filepath

Purpose

marketplace_builder/views/partials

Intended for Liquid partials which create HTML to be displayed visually on a webpage.

marketplace_builder/lib

Intended for Liquid partials which carry out calculations or business logic. Normally these will be functions, a special kind of partial we will cover in future.

If you are not sure which to use, views/partials is normally easiest.

In reality, all partials end up in the same bucket, whichever folder they were added to. The folder bucket is only there to help the developer organise their files and understand their purpose.

To create a partial, create a file in either of these folders, or in a sub-folder of your choice, with a .liquid extension.

Adding a partial to the page- the render tag

Let’s say we created a partial at the filepath: marketplace_builder/views/partials/marketing/call_to_action.liquid

This is the physical_file_path of the file, which determines where it shows in the file structure and includes its extension.

Actually when working with in GraphQL, the physical_file_path does not include marketplace_builder.

In order to add the partial to our current file, we need the relative path of the partial file:

marketing/call_to_action

Note, the path is only the unique section of the physical file path which refers to the file. You don’t need to include views/partials since all partials have it. For the same reason, you don’t need lib or .liquid

Then you can add the file, using the render tag and its path as the 1st parameter:

Example
{% render "marketing/call_to_action" %} {% render "marketing/call_to_action" %}

In the example’s tabs you can see two Liquid files. The first is the page, the second is the partial.

By including the partial twice, we include the code twice, without repeating ourselves. If we need to modify the code in the include, we can do it in one place, reducing human error; without this, often inconsistencies will develop over time between code which is intended to be the same but is updated haphazardly.

Render tag parameters, passing in data

This is all very well when the code needs to be exactly the same, but commonly we will need code which does a particular job, but which needs to do the job slightly differently depending on context.

We covered variables at the beginning of these tutorials: Liquid Tutorial 2 - Liquid variables and types

E.g. In Studio a Section may have the same Liquid code, but will show different content depending on the fields, lists and settings the user enters in that specific page.

To pass data from a Liquid file into the nested Liquid file, we can add parameters to the render tag. We can name the parameters almost anything we like, creating our own settings:

Example
{% render "marketing/call_to_action", color: "blue" %} {% assign color = green %} {% render "marketing/call_to_action", color: color %}

Note the second render tag works the same way, but instead of directly passing a String into the parameter’s value, we pass a reference to a variable containing a String instead. Note that we don’t need quotes and we don’t need to output the variable here.

The following is incorrect as it confuses the syntax for tags and outputs explained in Liquid Tutorial 1 - Recognising the syntax of tags, outputs and filters :

Example
{% render "marketing/call_to_action", color: "blue" %} {% assign color = green %} {% render "marketing/call_to_action", color: {{color}} %}

Inheritance

Just as in HTML elements, we use an analogy of a family when talking about including Liquid partials. The partial can be described as a “child” of the “page” which includes it.

Variables defined using the assign, capture (or other assign-like tags) inside the partial do not automatically have scope back in the parent Liquid file.

Example
{% render "fetch/info", gift: "I am a gift" %}

Note that the HTML result is able to output the gift variable which was passed from parent to child explicitly in a parameter, but the info variable was not able to be output by the page. The page has no knowledge of the info variable.

The difference between Include and Render

The difference between include and render is subtle, but understanding it can help you to avoid and fix bugs.

Consider the following example and the HTML result:

Example
{% assign info = "Ooops - I was not supposed to be used." %} {% render "display/info", index: 1 %} {% include "display/info", index: 2 %}

The include tag allows not only explictly passed parameters, like index, to be passed through to the variable, but it also inherits all previously assigned variables in the parent file.

Note that even though include allows all variables to inherit from parent to child, it still does not automatically allow variables to pass back up from child to parent.

include’s behaviour seems useful and often it can be; but often it can lead to bugs and unexpected behaviour, especially where multiple partials share commonly named parameters and are nested on multiple levels. For example, many Siteglide partials use the parameters “type” and “layout”. Sometimes someone may expect type and layout to have default values of “list” and “default”, but because of Liquid inheritance, they actually get their parents’ values. This is why we’re starting to replace include tags with render tags in this documentation; render makes variable inheritance more deliberate and controlled.

Passing variables up

Exports

Sometimes you do want to deliberately pass data up from a partial to its parent Liquid file. One way to do this is to modify the context object using exports.

You can re-cap the context object here: Liquid Tutorial 5 - Accessing data from the page and URL

  1. First create a variable in the child Liquid file

  2. Use the export tag in the child Liquid file, optionally setting a namespace parameter which can organise properties into nested objects. (This is usually a good idea, to separate your variables from Siteglide variables)

  3. Access the property in context.exports in the parent file, after the render tag which included the child file.

Example
{% render "child" %} {{context.exports.a}} {{context.exports.info.b}}

Functions

Functions are a special kind of include. They can also be used to conveniently pass data from child to parent, however, they are very specialised to that role, and cannot themselves output data to the page.

To test and debug functions, you need to use platformOS logs to see which lines are behaving unexpectedly, because you can’t output anything.

https://documentation.platformos.com/api-reference/liquid/platformos-tags#log

You can access logs using Siteglide CLI

https://feedback.siteglide.com/en/help/articles/5476054-referencemd#

Functions are a good candidate to be placed in the lib folder. Instead of include or render, you use the function tag- and it must also create a new variable (similar to assign):

Example
{% function result_1 = "divide", number_1: 54, number_2: 9 %} 54 / 9 = {{result_1}} {% function result_2 = "divide", number_1: 0, number_2: 9 %} 0 / 9 = {{result_2}}

Every function must have a return tag which runs, whatever the outcome of the logic. This value is passed to the new variable created by the function tag e.g. in the example result_1.

To re-cap logic, and our initial introduction of the return tag, see: Liquid Tutorial 6 - Logic

When a return tag is used in a function, or in an ordinary render include, it always ends execution of that function/render, but does not end the execution of the parent page, which can continue.

Functions are a fantastic way to improve the readability of your code. By abstracting specific calculations or logic or other Liquid code with a specific job, you can keep your main file easier to follow; there will be less distractions from the most important code.

Using render to include Siteglide functionality in your Liquid file

As well as creating your own Liquid partials and including them with render, there are a huge number of ready-built Siteglide includes. For example:

WebApps and Modules

Often Siteglide will have created partials in private files which you’re not able to directly read, but you can read in the docs which parameters are available to pass through.

The following code outputs a WebApp layout:

Example
{% render "webapp", id: "1", layout: "custom", type: "list" %}

You may have copied and pasted code like this before, but what is the Liquid actually doing?

  1. Firstly the code finds and renders a partial from views/partials/webapp.

  2. This is actually a shortcut which in turn includes a private partial file from the siteglide_system module with the same name.

  3. This file in turn carries out several functions behind the scenes, including importantly carrying out a GraphQL query to get the WebApp data. It assigns the data to a new variable called this.

  4. It then itself includes the layout file based on the path you specified originally in the layout parameter. It passes the this variable through to the layout as a parameter.