SiteBuilder is now designed to be extendable. Developers can add new Themes and modules. They can also extend our core libraries (and their own) with new layouts.
Developers will need to have a good understanding of:
Building a custom module on Siteglide
The syntax of writing JSON objects. We use this for configuration.
There are two main pathways to extending SiteBuilder with content and a good starting point is to work out which one matches your needs best. The two approaches are aimed at different use-cases.
Create a Theme Developers - Creating SiteBuilder Themes
Create a Module Developers - Support for Marketplace Modules
If you wish to add a new library to SiteBuilder which contains code published by a 3rd party, please check that you are allowed to do so under the terms of your license, for example, if the license is "open-source". If you have a license which covers your own agency's use, but does not allow you to redistribute the code as your own product, it's advisable to either:
ask the copyright holder for permission to resell their content as a SiteBuilder-compatible module
build the module for your agency's personal use, but keep it "private" on the Siteglide marketplace.
This route is for those who are creating a Siteglide module which adds database functionality to Siteglide. It shows how SiteBuilder compatible layouts can be included within the module itself.
Through this route, you can create layouts for your module for any existing themes which allow extension. For example, you may add either Flowbite or Bootstrap layouts for your module to cater for both sets of users.
If a theme-creator does not generally allow extension, please contact them to see if they would consent to allow you to extend their theme.
We'll add both a commented example you can look at on Github and an explanation here.
The first step is to register your module in the Siteglide marketplace in order to receive your module's Siteglide marketplace ID (if you haven't already). You'll need to reference this ID in several places, so make a note of it.
To start with, you just need to fill out the required fields. Add a name and set the type to "module", write a short description and initial version e.g. 0.1.0.
The "Vanity ID" will then appear. This is the unique ID that can be used across the marketplace to refer to your module.
Most of the files in your module will be in the private folder so SiteBuilder won't know they're there unless it knows where to look. You'll next need to create the following file at the public path: modules/module_<module_vanity_id>/public/views/partials/sitebuilder/module_registry.liquid
to make your module available to SiteBuilder.
The placeholder <module_vanity_id> should be replaced by the vanity ID that Siteglide gave you earlier.
While most of your module files will sit in the private folder, Liquid allows developers to access private files if they know their filepaths.
To give an optional extra level of protection to your intellectual property, you can register your module with Sitegurus in return for a secret key. We'll give you this secret key and associate it with your module vanity ID so that SiteBuilder can find your files, but your users can't. When you're given your secret key, the /sitebuilder/ folder will be replaced in your file structure with /sitebuilder_<secret_key>/
Do bear in mind that this system isn't perfect and we cannot guarantee that Liquid errors will not expose this key. We recommend careful testing to avoid errors with each new version.
If your module is open-source or you want to keep things simple, feel free to skip this section.
To configure the module and help SiteBuilder understand at a high level what content it contains, you need to create a file at the following path:
modules\module_<module_vanity_id>/private/views/partials/sitebuilder<secret_key_preceded_by_underscore>/module_config.liquid
. If you skipped the last section, you would keep the "/sitebuilder/" folder without an underscore or secret key.
Note that this file is a liquid file and allows Liquid syntax, but at runtime will compile to a JSON file. This means you must write the syntax so that the end result validates as JSON or risk introducing Liquid errors into the module as a whole. Comments can be added as Liquid comments (as we have used), as these will be removed at runtime.
Modules without sub-modules example
Here is an example of the Blog module's configuration which does not have sub-modules. You should always provide a "default" sub-module instead of the list in the example above.
Modules with non-standard parameters in their Liquid Tags
The following example shows the configuration for the "Headers" sub_module within the built-in Menu Module. Since the Siteglide Liquid tag offers slightly different parameters from a normal module tag, the settings must be configured to reflect this.
We will only comment on the parts of this example which are different from the previous example. Return to the previous example for an explanation of the other keys.
While layout code is stored in files in your main file structure, the layout_config liquid file is needed to give SiteBuilder the metadata it needs to display these layouts in the UI, find the files it needs and install them to the correct folders.
These instructions are mostly the same whether you are a module or a theme creator, so from here we'll link you to the joint documentation on configuring layouts. Just note that for module creators, you would normally only link layouts back to your module vanity ID and submodule ID.
If you wanted to add for example a front-end eCommerce layout for users to buy the content in a courses module, you could harness sub-modules to achieve this.
These instructions are very similar whether you are following the theme or module creator pathway, so both tutorials converge here.
Each Layout gets its own folder in the file structure. It's position in the file structure is affected by its theme and its module.
Most Siteglide layouts actually consist of more than one layout, so Within that folder, you need to create the same number of source files inside your module folder.
How you organise your files into folders within your layout folder is optional, however, you will need to reference these source files' exact paths in the "src" property of the "files" array in the layout config later.
Module creators will normally have multiple theme folders with a single module folder and single layout_config file in each. For example:
Theme creators will normally have only a single theme folder containing multiple module folders to organise layouts accordingly. For Example:
Layouts in the same module but different sub-modules will still share the same module folder. The sorting of sub_modules is done instead based on the layout_config file, see the next section.
If you want to see the format for adding layout source code to the files in this structure, look at step 4. Otherwise, move on to step 2.
While the actual code for each layout goes in its own file, SiteBuilder also needs Layout Config Files to give it the metadata needed to display and install layouts correctly.
A layout_config file is needed for each theme you want to add layouts for.
Theme creators need only create a single layout_config file for their module. For example, if you're creating a theme, your layout_config file should be at the following path:
modules/module_<module_vanity_id>/private/views/partials/sitebuilder<secret_key_preceded_by_underscore>/theme_<module_vanity_id>/layout_config.liquid
Module creators will need a layout_config file per theme they wish to add their module layouts to. For example if a module creator wants to offer their users both Bootstrap and Flowbite layouts (they would have also set the "extends_themes" key in their module_config to include the same IDs "theme_01" and "theme_02"), they'll need to add files at the following paths:
modules\module_<module_vanity_id>\private\views\partials\sitebuilder<secret_key_preceded_by_underscore>\theme_01\layout_config.liquid
modules\module_<module_vanity_id>\private\views\partials\sitebuilder<secret_key_preceded_by_underscore>\theme_02\layout_config.liquid
You'll see the main difference is that the folder named after the theme will either point at a theme you created or a theme created by someone else, depending if you are a theme or a module creator. The theme folder will also contain folders for layout code files as well as the config file.
Step 3 - Configuring the Layout Config Files
The following example is from a module creator's layout_config file.
Perhaps the most complex and important part of the configuration to pay attention to is the files array. When SiteBuilder installs a layout, it takes a copy of the layout source code you've stored in the private folder and adds those copied files to the marketplace_builder folder where they can be freely read and edited by the module user. It is therefore important to note the difference between the src property which points at the files you add and the dest property that points to where you wish the files to be installed.
Adding Liquid to Layouts using the Raw Tag
In step 1, you created the folder structure for the layouts, but this section shows how you can format the layout code within each file.
It's up to you what kind of Liquid code to add to layouts, but there is one important rule:
Where your layout contains any Liquid code which you wish to render at runtime, you need to wrap it in the `` liquid tags, see https://documentation.platformos.com/api-reference/liquid/introduction#raw. In almost all cases, you can just wrap this tag around your entire layout. Without this tag, Liquid will run at build-time while SiteBuilder is creating your layout, which would most likely mean the Liquid would be rendered to nothing, or to something unexpected.
Important! Once you put raw tags into a layout, the Siteglide-CLI will ignore any errors in your code. So if you have an unexplained file in your layout that is not installing properly, try taking out the raw tags, syncing, then putting them back in. You may discover the error in the CLI.
If you're using VSCode, you can use find & replace to add raw tags to all files in a folder.
![VSCode regex find and replace ((.|\n)*) with $1.]https://res.cloudinary.com/sitegurus/image/upload/v1667563298/modules/module_86/documentation/adding_raw_tags.png
Pagination
Layouts should aim to be self-contained. This often means that Siteglide's default pagination position is too low and it's better to move the pagination higher up in the DOM (so that it has the correct padding after it.)
The recommendation is that you use the following code to position custom pagination:
To use it, the module_user must both set show_pagination: 'false'
on the include tag to remove the default pagination and then set a custom pagination_layout
.
Built-in module module_s2
can be used to add new pagination layouts to a theme.
Adding Settings (Optional)
As well as this rule, there are also some helpful conventions which you can follow when writing layouts. One of these is Layout settings.
The main purpose of Layout settings is to gather together at the top of the file, variables which cannot be handled completely dynamically and require the module user to enter some input to make the layout work as expected. For example, if you've got a link from the layout to another page, there's no way of a layout knowing the context of the site and which URL to link to.
This adds convenience to the user; instead of searching through the layout to find the variables they'll almost certainly want to change, they can look at the top of the layout first.
Here is an example of settings being implemented in a SiteBuilder Layout:
Notes:
Where a layout contains multiple files, the settings block should be placed at the top (under the tag) of the first file that will be outputted, which would normally be called the wrapper
.
The entire settings block should be wrapped between two Liquid comments `
` and ``. 3. Each setting should be preceded by another comment with the name of the setting (6 dashes before and after), then a comment to explain the purpose of the setting. 4. Finally, each setting should contain a Liquid tag to set the variable. This variable's value should be read where needed within the rest of the file and within any other files in the layout which may need to use it. Due to Liquid inheritance, the variable will be available for any files included by the file that contains the setting block.
These conventions help to keep the settings consistent and readable for the module user (and the developer). Following them now will also allow your layouts to take advantage of future improvements when settings are further integrated into the SiteBuilder UI. Watch this space!
Sitebuilder Component IDs (optional)
Another convention we use when building layouts with JavaScript interactivity is the Sitebuilder component ID.
Where JavaScript needs to be given an element query selector in order to make that element interactive, you can normally pass it an element ID. However, you need to think about what would happen if the user added more than one similar (or the same) layout to the page.
Using the following code, we dynamically generate a unique ID for each layout that needs one. Since this is generated by Liquid at runtime, it doesn't matter if the same layout is used twice- the ID will still be unique. This is by convention generated straight after the settings.
Instead of including JS within the layout to capture these variables, it is possible to store the ID in data-attributes and target all the elements at once. This allows your JS to run asynchronously for better performance.
Liquid
JS
Using these conventions from the beginning should help you avoid bugs arising from conflicting IDs.
Nesting or embedding layouts (optional)
In the previous sections, the documentation alluded to nested or embedded layouts. This is an advanced feature of SiteBuilder which allows layouts from one module to embed within them modules from another.
Look back at the example for step 1 to see the file-structure for embedding a testimonials layout within a module layout (the layout folder is "2").
Look back at step 2 to see how the embedded layout is configured.
You also need finally in your Layout code to add the Liquid tag which will include the embedded layout itself.
The main limitation of embedded layouts, is that it's not always possible to know all of the information you'd need to embed a layout successfully. This will depend on context on a case-by-case basis.
One piece of information which you will have which might surprise you however, is the name of the layout. Due to the way we set up the layout config, the embedded layout will have the same layout name as the parent layout (they are installed at the same time!). This means whatever the module-user chooses to name the layout, you will be able to access it! Use the example below:
In this example, the layout_config files array contains a file with the dest: testimonials/list/wrapper
. Since list and wrapper are handled by Siteglide ( you need to add the type: "list"
parameter though), only the "testimonials" part of the path is needed. Any other optional additional folders should also be added to the capture tag. We also prepend the name of the current parent layout. The embedded layout will have been created at the same time, with the same name, so we can reference it using the inherited {{layout}}
variable.
Resetting _top_model
for consistent layout paths
The unusual looking _top_model: nil
parameter is useful for making sure the nested Siteglide tag looks in a consistent location for layouts. Due to legacy reasons, where an `
` tag is nested inside another, Siteglide will look inside the parent module folder for all child module layouts. This is inconsistent with other tags, for example secure zones where Siteglide will look in the child module's folder, so it's easier to use this parameter to tell Siteglide to ignore the parent layout and look in the module folder for the current module. That way you can always store layouts safely accordingly to their own functionality rather than the functionality of the layout they're nested inside.
Preserving the Layout Variable across multiple layers of Liquid
If you're nesting layouts in more than two layers, you may experience a difficulty where the first layer redefines the layout
variable and it's not accessible in layers below. In this case, at the top layer, you should assign a new variable on the very top layer which will reliably not be overwritten:
Datasources
If you wish, you can also make this embedded layout into a datasource! Here we use one of the datasource fields in the parent layout to store Testimonial IDs we can use to filter by.
Troubleshooting Layouts
Check the JSON for each config file validates to correct JSON when you "include" and "output" the file on a test page with Liquid. A comma in the wrong place can invalidate your JSON and cause errors.
If there are missing files in your layout, try temporarily removing the raw tags from that file and syncing with Siteglide-CLI. The raw tags may be causing a syntax erro to go undiscovered.
Check that the raw tags are present in each file.
Check that the number of files listed in the layout_config file matches, or is less than, the number of files in your layout's file structure.
When your layout is working, but you're working on improving the layout's functionality and styling, try using PageBuilder to quickly generate multiple test layouts, and use the view page feature to view. When done, close the modal with the top-righthand corner close button and run the test again when you're readyby giving the page a new name.
This documentation is aimed at those following the theme-creator route. It's not currently supported to include static layouts within the module-creator route.
Static layouts are HTML layouts which can be included in a theme. They won't directly interface with the database in the same way as a dynamic layout and are likely to have their content edited by the module-user, either in the code, or in the Siteglide Admin's Studio tab.
The Studio tab in Siteglide is one place that SiteBuilder static layouts will appear. They can be dragged and dropped into the page and edited there.
SiteBuilder static layouts will only appear in the Studio tab if the theme to which they belong is attached to any installed Page Template on the site. It's not yet possible to only show static layouts which are an exact match to the current page's template, but we will implement this when we can.
PageBuilder will show static layouts as section blocks which can be added to the page within the SiteBuilder UI. These will only show for the currently selected theme.
Siteglide will be publishing a webhook allowing any module to add static layouts to the Studio tab without going through SiteBuilder. SiteBuilder builds upon that API with behind-the-scenes code which merges all static layouts in the file structure and automatically builds their categories.
Under your theme folder, you'll need to create folders for each category of Static Layouts. The folder name will be capitalised and its underscores will be replaced by spaces within the UI e.g. "call_to_action" becomes "Call To Action".
Within each folder, each static layout gets its own file. The name of this file should be a number, which relates to the layout's ID in the static_config
file, see next step.
At the present time, static content should be added inside each file as HTML only (including <style>
or <script>
tags if you like). It may be possible in future to include Liquid wrapped in raw tags, but it is not currently.
The static_config.liquid
file should be added inside the theme folder in order to give SiteBuilder the metadata it needs to find your layouts and display them in either the Studio tab UI or the PageBuilder UI.
A theme module in Siteglide is generally a module which does not add database functionality to the Siteglide Admin or the front-end, but does add files which are helpful for styling the front-end of a website. With the help of this documentation, you can go a step further by hooking into SiteBuilder functionality:
Page Templates
You'll be able to configure SiteBuilder to create a Siteglide Page Template, containing all the global CSS and JS your theme needs for its HTML to look and interact as expected.
Layouts
Any static or dynamic HTML or Liquid (respectively) layouts will not be installed straight away on a user's site, but will be available in the module UI. There are two main advantages of this: firstly, it avoids clutter; secondly, it allows you to make improvements to layouts without breaking any of the module-user's own changes- instead your improvements will be fetched next time the layout is installed.
Compatibility with Other Themes
Building a theme module lets you create a single theme per module. However, by configuring the settings, you can mark your theme as compatible with other themes which use a similar CSS framework. This allows module-users to use layouts from several simialr thems on the same site.
In this documentation, for an example, we'll be creating a theme for the Siteglide Studio Design System. As this theme is moving to being deprecated on Siteglide, it's an excellent opportunity to turn it into an open-source theme module to show you what is involved.
You'll need to register the new module with Siteglide to receive the "vanity_id". We'll use this as a unique ID to identify your theme and module within SiteBuilder.
First in the Siteglide Portal, go to the marketplace tab and select "add new".
Secondly, fill out the name, type and description. For type, select "theme".
Thirdly, make a note of your "vanity ID". We'll refer to this as <module_vanity_id> where it needs to be substituted in the examples.
Most of the files in your module will be in the private folder so SiteBuilder won't know they're there unless it knows where to look. You'll next need to create the following file at the public path: modules/module_<module_vanity_id>/public/views/partials/sitebuilder/module_registry.liquid
to make your module available to SiteBuilder.
The placeholder <module_vanity_id> should be replaced by the vanity ID that Siteglide gave you earlier.
While most of your module files will sit in the private folder, Liquid allows developers to access private files if they know their filepaths.
To give an optional extra level of protection to your intellectual property, you can register your module with Sitegurus in return for a secret key. We'll give you this secret key and associate it with your module vanity ID so that SiteBuilder can find your files, but your users can't. When you're given your secret key, the /sitebuilder/ folder will be replaced in your file structure with /sitebuilder_<secret_key>/
Do bear in mind that this system isn't perfect and we cannot guarantee that Liquid errors will not expose this key. We recommend careful testing to avoid errors with each new version.
If your module is open-source or you want to keep things simple, feel free to skip this section.
You'll need to add a theme_config file at the following path: modules/module_<module_vanity_id>/private/views/partials/sitebuilder<secret_key_preceded_by_underscore>/theme_config.liquid
. This adds the metadata SiteBuilder needs to understand your theme.
For the content, add the following, adapting it to your module where suitable:
In the previous step, when editing the theme_config file, there was a CSS preferences object. Here we will look at this, and the alternative and add the files that are referenced in the config.
CSS File Structure
This is an example CSS file structure for the same theme.
Firstly, ../css/default/css.liquid
contains a Liquid snippet which will be added to all templates created using your theme. This happens regardless of whether or not a CSS preference is chosen (see next sub-section).
This file will contain Liquid/HTML. For example, it can be useful to include tags to files which are hosted on an external CDN and don't need to be hosted on Siteglide or edited. It can also contain inline style tags, should you so wish.
It is okay to include a small amount of JS here, for example, Flowbite includes a few lines of render-blocking JS so that dark mode is supported immediately on page load. As in this example, it's recommended that JS is only included here where it relates to styling. Another file exists for the main JS includes.
If you don't need to use this, you must include the file, but please leave the contents completely blank.
As well as default CSS, you can choose to have some CSS files which are copied onto the module user's site and hosted there. The benefit of this is that it allows the module-user to edit that CSS.
This feature is very flexible. For example, you can cater to both module-users who prefer writing native CSS or users who use SCSS; you configure the options and then let the user decide which to install when they create a template.
We hope the flexibility is enough to enable a wide range of CSS frameworks.
Create a folder for each option you'd like to give the user. In the example file structure above, there is min_css
and css
. These folder names must match the keys in the theme_config's css_preference_options
object.
Within each folder, create a liquid file for each file you'd like to install. The file should be named the same as the destination file, but you must replace any special characters with their URL encoded equivalents. For example, an underscore should be replaced with %5F
- see the example.
In each file, add YAML at the top of the Liquid file to add the following metadata- the role of this is to set what the extension of the final destination file will be.
Below this add the body of the file. e.g. the actual CSS/SCSS code.
When a user selects this option while building a template, all the files will be created on their site- but not all will have HTML <link>
tags added to the template. - Remember to add the link_in_template: true
property in the theme_config for each option where this is needed- e.g. for .min.css
files but not for .scss
files.
If you don't need the CSS preferences feature, leave the "css_preference_options" property as an empty object {}
in the theme_config.\
To add JavaScript (which you don't expect to be edited by the ordinary module-user) to any templates which need to be installed, you can add any script tags to the path modules/module_<module_vanity_id>/private/views/partials/sitebuilder/theme_<module_vanity_id>/js.liquid
. These will be added to the template, as is, when the template is created.
The JavaScript itself, where necessary, should be added to .js
files in your module's private folder, or you may choose to link to scripts in a CDN.
Editable JavaScript
If there is some JavaScript you expect to be edited by the user, it's often best to add this as an inline <script></script>
tag, either in the main js.liquid file, or in an individual layout.
Inline JS for capturing Liquid variables
Another situation where it might be useful to write inline JS is if you need to capture a variable from the Liquid. In this case, it's useful to write a short inline script to assign the variables to the global scope and then use a longer external script to use those variables. You can also write an API request to a Liquid page to fetch Liquid variables into your JS.
Performance
All JavaScript will be added to the head of the page, for simplicity.
To improve performance, it is recommended therefore that you write as much JavaScript as possible so that it can be deferred or loaded asynchronously.
Tips:
Write event listeners instead of using events which are stored in HTML attributes like onclick=""
. This means that if a button is clicked before the JS is loaded, no "function is not defined" error will occur. The button only becomes interactive once the JS has loaded.
If using defer, your JS can normally use the DOMContentLoaded event to run your main JavaScript.
HTML
JS
For async code, you won't be able to control the order in which scripts load. To handle any dependencies, you can either use a bundler like Webpack to load JavaScript modules from a registry like npm or use the following pattern to load dependencies efficiently from a CDN:
HTML
JS
This page is intended to document the themes and modules that are built into SiteBuilder, to help you reference those IDs in your own modules and build onto that content.
If you want the community to collaborate with you on what you build, we suggest you make similar documentation of your own!
Theme | ID |
---|
Module | ID | Submodules | Submodule IDs |
---|
If a module that has no sub-modules is given a sub-module in an update, the sub_module 0 which was previously default will be renamed to miscellaneous. Layouts referencing that sub_module will be displayed in the miscellaneous group until they are updated to reference one of the new sub_modules.
Flowbite | theme_01 |
Flowbite Pro | theme_111 |
Bootstrap 5 Design System | theme_113 |
Menu | module_2 | Headers, Footers, Sidebars | 1, 2, 3 |
Blog | module_3 | Default | 0 |
Events | module_12 | Default | 0 |
Slider | module_4 | Default | 0 |
FAQ | module_10 | Default | 0 |
Testimonials | module_8 | Default | 0 |
eCommerce | module_14 | Product List, Product Detail, Cart, Order Detail, Currency Changer, Tax Code Changer | 1, 2, 3, 4, 5, 6 |
Forms | module_s1 | Default | 0 |
Secure Zones | module_5 | Login Forms, Logout Buttons, User Form Submissions | 1, 2, 3 |
Pagination | module_s2 | Default | 0 |
Form Confirmation | module_s3 | Default | 0 |