LogoLogo
Siteglide.comAdminRoadmap
  • πŸ‘‹Welcome
  • Get Started
    • πŸš€Quickstart Guides
    • ❔Support & FAQs
      • ℹ️Siteglide Support Policy
      • ℹ️Siteglide Technology Stack
      • ℹ️External Resources
      • ℹ️Front-end Browser Support
  • Portal
    • Account
    • Sites
      • πŸš€Quickstart: Create a Site
      • ℹ️Site Details
      • ℹ️Site Users
      • πŸ“‹Install & Manage Modules
      • πŸ’³Go Live
      • πŸ’³Subscription
      • 🌍Domains
        • πŸ“‹Add a Fully Delegated Domain
        • πŸ“‹Add an External Domain
        • πŸ’»Subdomain on a separate instance
        • πŸ“‹How to setup a multi domain start page
      • ☁️Site Backups and Disaster Recovery
    • Users
      • πŸ“‹User Roles
      • πŸ“‹Invite & Manage Users
    • Billing
      • πŸ’³Billing Setup
      • πŸ’³Subscriptions and Changes
      • πŸ’³Automatic Site Upgrades
      • πŸ’³Invoices
    • Tickets
    • Marketplace
    • Agencies
      • πŸ‘©β€πŸ’»Agency Account
      • πŸ‘©β€πŸ’»Clients
      • πŸ‘©β€πŸ’»Site Copies
      • πŸ‘©β€πŸ’»Agency Whitelabelling
  • Developer Tools
    • CLI
      • πŸš€Quickstart: CLI
      • ℹ️About
      • πŸ“‹Site Setup
      • ❔Troubleshooting
      • πŸ’»Reference
      • πŸ›³οΈCLI Changelog
      • πŸ§™β€β™‚οΈGo Further: CLI
        • Creating WebApps via CLI
    • Liquid
      • ℹ️About
      • πŸ’»Reference
      • Accessing Data in Liquid Variables - Tutorial 1 - Using Dot Notation
      • Accessing Data in Liquid Variables - Tutorial 2 - Iterating over Arrays and Objects
      • Using Collections with WebApps and Modules
      • Accessing Data from the Global Context Variable
      • Truthiness - Using Liquid to determine if a field is empty or blank
      • πŸ“‹Alternatives to Storing and Executing Liquid from Database Items
    • GraphQL
      • ℹ️About GraphQL
      • πŸ“‹Tutorials
        • Tutorial 1 - Your First Query
        • Tutorial 2 - Pagination
        • Tutorial 3 - Filtering the Results
        • Tutorial 3 - (Answers)
        • Tutorial 4 - Advanced Filtering
        • Tutorial 4 - (Answers)
        • Tutorial 5 - Using Liquid to run GraphQL queries on your Site
        • Tutorial 6 - Variables
        • Tutorial 6 - (Answers)
        • Tutorial 7 - Sorting
        • Tutorial 8 - Building a Liquid API GET Endpoint Page powered by GraphQL queries
        • Tutorial 9 - Using Mutations to Create New Records
        • Tutorial 10 - Using Mutations to Edit a Record
        • Tutorial 11 - Using Mutations to Delete an Item
        • Tutorial 12 - Related Records and Datasources
    • Configuration
      • ℹ️Field Types
      • ℹ️Custom Field IDs
    • Zapier Integration
      • ℹ️Formatting arrays correctly
    • Developer Marketplace
      • ℹ️About Building Modules
      • ℹ️Module Setup
      • ℹ️Site Template Modules - and How to Make Your Own
      • ℹ️Create Folder Structure
      • ℹ️Updating Modules
      • ℹ️Submit Module for Approval
      • ℹ️Adding Payment to a Module
      • ℹ️Theme Module Example
      • ℹ️Data & UI Module Example
      • πŸ’»Reference
      • 🌳File Structure
    • Release Notes
      • πŸ›³οΈSiteglide Admin/API - Changelog
      • πŸ›³οΈModule - System Files - Changelog
      • πŸ›³οΈModule - eCommerce - Changelog
      • πŸ›³οΈModule - Menu - Changelog
      • πŸ›³οΈModule - Slider - Changelog
      • πŸ›³οΈModule - Secure Zones - Changelog
      • πŸ›³οΈModule - FAQ - Changelog
      • πŸ›³οΈModule - Events - Changelog
      • πŸ›³οΈModule - Blog - Changelog
  • SiteBuilder
    • Build Sites Faster
      • πŸš€Quickstart: SiteBuilder
      • About
      • Site Setup
        • πŸ—οΈMarketplace Themes & Templates
        • πŸ—οΈCreate Site From Template
        • πŸ—οΈInstall SiteBuilder Module
        • πŸ—οΈCreate a Page Template
        • πŸ—οΈSet Up Tailwind CSS with the recommended CLI method
      • Styling
        • πŸ—οΈEditing Tailwind CSS using the recommended CLI method
        • πŸ—οΈTailwind CSS Themes - Choosing a Build Method
        • πŸ—οΈTailwind CSS - Preview Mode
        • πŸ—οΈTailwind's JIT Compiler Via CDN (deprecated)
        • πŸ—οΈTheme Presets
        • πŸ—οΈExample Tailwind Project Setup
      • Layouts
        • πŸ—οΈInsert Static Layouts
        • πŸ—οΈInstalling Dynamic Layouts
        • πŸ—οΈEditing Dynamic Layouts
        • About Layouts
          • πŸ—οΈDynamic Layouts
          • πŸ—οΈStatic and Dynamic Form Layouts
          • πŸ—οΈSliders
      • πŸ’»Reference
    • Advanced Features
      • 🧞SiteBuilder Live Updates API
        • πŸ‘€Live Updates Reference
        • πŸ”ΉLive Updates Markup Example
        • πŸ“‹Steps to Setting Up Live Updates API in a Module/WebApp Layout
        • πŸ”ΉLive Updates Example - Enforcing Filters
        • πŸ“‹Steps to Use Live Updates Methods
        • πŸ“‹Steps to Initialise Live Updates with JS
        • πŸ—“οΈLive Updates Changelog
      • ℹ️SiteBuilder JavaScript
        • ℹ️Forms JS
        • ℹ️Social Sharing JS
        • ℹ️Sliders JS
        • ℹ️Dark Mode JS
        • ℹ️Cookie Settings JS
      • ℹ️SiteBuilder Liquid Includes
        • ℹ️Pagination
      • ℹ️SiteBuilder Liquid Functions
        • ℹ️Detail Page Valid
        • ℹ️Field Mapping
        • ℹ️Get Table Config
        • ℹ️Case From Order ID
      • πŸ—“οΈSiteBuilder Changelog
    • Extend SiteBuilder
      • ℹ️Create SiteBuilder Themes
      • ℹ️Create Marketplace Modules
      • ℹ️Adding Dynamic Layouts to Themes & Modules
      • ℹ️Adding Static Layouts to your Theme
      • πŸ’»Reference
  • CMS
    • Dashboard
    • Pages
      • πŸš€Quickstart: Pages
      • 🎨Studio Alpha Release
      • ℹ️Studio
      • ℹ️Code View & Toolbox
      • ℹ️About Pages
        • ℹ️Page Settings
        • ℹ️Custom Fields in Pages
        • ℹ️Pages with Siteglide CLI
      • ℹ️About Page Templates
        • ℹ️Page Templates with Siteglide CLI
        • Preventing Duplicate Content
      • ℹ️System Pages
      • πŸ’»Reference
      • 🌳File Structure
    • Content Sections
    • File Manager
      • πŸ”ΉAbout Assets
      • πŸ”ΉLinking to Assets Explained
      • πŸ”§Assets Troubleshooting
      • πŸ”ΉSiteglide Scripts Explained
      • πŸ’»Assets with CLI
      • πŸ”ΌMigrating Assets
      • πŸ“‹Steps to Optimise Images on the Fly with Cloudinary
      • πŸ”Ήsiteglide_head_scripts and siteglide_footer_scripts Explained
      • 🌳Assets File Structure
      • πŸ‘€Tags for Assets
    • Forms
      • Quickstart: Forms
      • ℹ️About Forms
      • πŸ“‹Guides: Forms
        • πŸ“‹Steps to Using Separate Fields for First Name and Surname in a Form
        • πŸ“‹Steps to Programmatically Redirecting after a Form Submission
        • πŸ“‹Steps to Adding Form Confirmation Pages
        • πŸ“‹Steps to Adding a Progress Bar
        • πŸ“‹Steps to Changing Form Styling on Submission Using CSS
        • πŸ“‹Steps to Using Custom Field Set fields in a Form's Custom Layout
      • πŸ§™β€β™‚οΈGo Further: Forms
        • ℹ️Migrating Forms
        • ℹ️Explained - Preventing Spam Form Submissions and Captchas
        • ℹ️Explained - Show Clearly When a User is Already Logged in When Submitting a Form
        • ℹ️Forms Error Callback and Validation
        • ℹ️Forms Success Callback
        • ℹ️File Upload Previews
      • 🌳Forms File Structure
      • πŸ’»Reference
      • ❔Troubleshooting
    • Automations
      • πŸš€Quickstart: Automations
      • ℹ️About
        • ℹ️Email Templates
        • ℹ️Email Automations and Email Templates with Siteglide CLI
      • πŸ“‹Guides
        • ℹ️Integration Automations
        • ℹ️A Transactional Email Example
        • ℹ️An API Call Action Example
        • ℹ️A Custom Liquid Action Example
        • πŸ“‹Steps to Testing Emails on a Staging Site
        • πŸ“‹Steps to Authenticating Sendgrid Emails on Live Sites
      • πŸ§™β€β™‚οΈGo Further
      • πŸ’»Reference
      • 🌳File Structure
    • Categories
      • πŸš€Quickstart: Categories
      • ℹ️About
        • ℹ️Outputting Categories on WebApp / Module / eCommerce Layouts
        • ℹ️Filtering WebApps and Modules by Categories Using Liquid Parameters
      • 🌳File Structure
      • πŸ’»Reference
    • Company Information
      • ℹ️About
      • πŸ’»Reference
      • ❔Troubleshooting
    • URL Redirects
  • Modules
    • Core Modules
      • MenuBuilder
        • πŸš€Quickstart: Menu Builder
        • ℹ️About
      • Secure Zones
        • πŸš€Quickstart: Secure Zones
        • ℹ️About
          • πŸ“‹Dynamically Assign a Secure Zone during Form Submission
        • πŸ§™β€β™‚οΈGo Further
          • ℹ️Secure Zones with Siteglide CLI
          • ℹ️Using the context.current_user object
      • Media Downloads
        • πŸš€Quickstart: Media Downloads
        • ℹ️Layouts
        • πŸ’»Reference
      • Blog & Authors
        • πŸš€Quickstart: Blog & Authors
        • πŸ”ΉBlog Archive & Date Filtering
        • πŸ”ΉBlog Search
        • πŸ”ΉBlog Filter by Category
        • πŸ”ΉBlog Filter by Author
        • 🌳File Structure
        • πŸ’»Reference
      • Events
        • πŸš€Quickstart: Events
        • ℹ️Standard List View
        • ℹ️Getting Started with Event Filtering & Searching
        • ℹ️Filter by Category
        • ℹ️Filter By Host (Author)
        • ℹ️Filter by Event Dates
        • ℹ️Datasourcing the Event Host
        • ℹ️Search
        • ℹ️Map List View
        • ℹ️Calendar List View
      • FAQ
        • πŸš€Quickstart: FAQ
        • πŸ’»Reference
      • Testimonials
        • πŸš€Quickstart: Testimonials
        • πŸ’»Reference
      • Slider
        • πŸš€Quickstart: Slider
        • πŸ’»Reference: Slider
    • Community Modules
      • πŸ—οΈSiteBuilder
      • πŸš€CRM Sync
        • ℹ️About CRM Sync Module
        • πŸ“‹Steps to Set Up CRM Sync on an Automation
        • πŸ—“οΈCRM Sync Changelog
    • Go Further: Modules
      • ℹ️Front-end Submit Modules
  • WebApps
    • πŸš€Quickstart: WebApps
    • WebApp Items
      • πŸ“‹Create WebApp Items
      • πŸ“‹Importing and Exporting
    • Layouts
      • ℹ️WebApp List Layout
      • ℹ️WebApp Detail Layouts
    • Go Further: WebApps
      • πŸ“‹Searching by Location
      • πŸ“‹Searching - Advanced Filtering
      • πŸ“‹Searching - By Keyword
      • πŸ“‹Front End Create Forms
      • πŸ“‹Front End Update Forms
      • πŸ“‹Front End Delete
  • WebApp Troubleshooting
  • eCommerce
    • πŸš€Quickstart: eCommerce
    • Get Started
      • πŸ’‘About the eCommerce Module
      • Settings
      • πŸ“‚Cart, Checkout and Quotes
        • πŸ’‘About Cart, Checkout and Quotes
        • πŸ“‹Steps to Implement a Guest Checkout Flow
        • πŸ“‚Product Views
          • πŸ”ΉProduct Layouts
          • πŸ”ΉProduct List Layout
          • πŸ”ΉProduct Detail Layout
          • πŸ”ΉAdd to Cart Button
          • πŸ“‹Steps to Datasource and Display Related Products
          • πŸ”ΉDynamic Product Layouts based on Categories
          • πŸ“‚Attribute Selection
            • πŸ”ΉAttribute Layout - Presenting the Choice to the Customer
            • πŸ”ΉAttributes - Changing Product Price after Change
          • πŸ“‚Discount Selection
            • Discount Codes Layout
            • Minimum Payments
          • πŸ“‚Shipping Selection
            • Shipping Options Layout
        • Managing Products
          • Creating and Editing
          • Securing Products
          • Location
          • Custom Fields
          • Edit Module Structure
          • Product Custom Field Sets
          • Inventory
          • Managing Attributes
          • Pricing
          • Product Categories
          • Open Graph Fields
          • SEO Fields
          • Standard Fields
          • Product Import and Export
          • Discounts
        • πŸ“‚Cart
          • πŸ”ΉCart Layouts
          • Checking Inventory in Cart
          • Updating Quantity in Cart
          • Updating Displayed Cart Quantity
        • πŸ“‹How to Set Up a Shopping Cart and Guest Checkout - Tutorial
        • πŸ“‚Checkout Forms
          • πŸ”ΉCheckout Form Layouts
          • πŸ”ΉCheckout Forms with PayPal
        • πŸ“‚Orders
          • Order Confirmation
          • Re-Ordering
          • πŸ”ΉOrders Layouts
        • πŸ“‹Steps to Add Secure Zones and User Orders View to your Checkout Flow
        • Quotes
        • Selling Digital Products
        • πŸ”ΉVolume Pricing
        • πŸ“‹Steps - Alternatives to Product Grouping
      • πŸ“‚Basic Payment Forms
        • πŸ’‘About Basic Payment Forms
        • πŸ“‹Steps to Set up a Basic Payment Form (with a Fixed Payment Amount)
        • πŸ“‹Authorize.net Basic Payment Forms
        • πŸ“‹PayPal Basic Payment Forms
        • πŸ“‹Steps to Allow User to Decide Amount they Will Pay
        • πŸ“‹Step-by-step Basic Payment Confirmations
        • πŸ‘€Basic Payment Forms Reference
        • ℹ️ecommerce/basic_payment
      • πŸ“‚Payment Gateways
        • πŸ’»Building a Custom Payment Gateway
          • πŸ“‹Steps to Support Basic Payment Forms with your Custom Payment Gateway
          • πŸ“‹Steps to Support Checkout with your Custom Payment Gateway
        • πŸ”ΉPaypal Custom Parameters
        • πŸ”ΉStyling Stripe Card Elements
        • πŸ’‘About Payment Gateways
        • πŸ“‹Steps to Switching Payment Gateway
        • πŸ”ΉTest Cards
      • πŸ“‚Currency and Tax
        • πŸ’‘About Tax Codes
        • Currency Changer
        • Tax Code Changer
        • Formatting Currency
      • πŸ“‚Subscriptions
        • πŸ’‘About Subscriptions
        • Managing Subscriptions
          • Creating Subscription Products
          • Changing Price and Billing Interval
          • Creating a Form for Signing Up and Changing Payment Details
          • Subscription Order Status Explained
          • Terms and Conditions (Good Practice)
        • πŸ“‹Subscriptions Payment Gateway Setup
        • Subscriptions List Layout
        • Subscriptions Detail Layout
        • User's Active Subscriptions
        • Subscription Action Required
        • Cancelling Subscriptions
      • 🌳Basic Payment Forms Folder Structure
      • 🌳Cart and Checkout Folder Structure
  • CRM
    • πŸš€Quickstart: CRM
    • Users
      • User Details
      • User Secure Zones
      • How Users Edit their Email and Password Front End
      • Custom Field Sets & CRM Custom Fields
      • Storing User's Favourite WebApp / Module Items
    • Companies
    • Cases
      • User's Form Submissions (Cases)
  • Site Manager
    • Code Editor
    • Templates (Pages & Email)
    • Headers & Footers
    • Code Snippets (Includes)
      • πŸ”§Includes Troubleshooting
      • πŸ‘€constants_json
      • πŸ‘€constants
      • 🌳Includes File Structure
      • πŸ’»Includes with Siteglide CLI
      • πŸ”§Tags for Includes
    • System Pages
      • Automatic Site Maps
    • System Emails
    • Data Management
    • Admin Menu Editor
    • Integrations
  • Reporting
    • πŸš€Quickstart: Reports
  • Miscellaneous
    • System Features
      • Pagination on Liquid Tags
      • Custom Pagination Layouts
      • Timezones in the Siteglide Admin and on the front-end of your Site
      • Module/WebApp Caching
      • Getting Started with Liquid Caching - to Reduce Server Response time and Improve Performance
      • Translating Dates
      • Site Search
      • About Site Search
      • AI Tools for the Rich Text Editor
      • Cookies on Siteglide Sites
    • Front-End Performance
      • Video Embeds
      • Forms Above the Fold
Powered by GitBook
On this page

Was this helpful?

Export as PDF
  1. SiteBuilder
  2. Extend SiteBuilder

Adding Dynamic Layouts to Themes & Modules

Configuring Dynamic Layouts

These instructions are very similar whether you are following the theme or module creator pathway, so both tutorials converge here.

Step 1 - Create the File Structure for Dynamic Layouts

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:

└───modules
    └───module_<module_vanity_id>
        β”œβ”€β”€β”€private
        β”‚   └───views
        β”‚       └───partials
        β”‚           └───sitebuilder<secret_key_preceded_by_underscore>
        β”‚               β”‚   module_config.liquid
        β”‚               β”‚
        β”‚               └───theme_01
        β”‚               |   β”‚   layout_config.liquid
        β”‚               |   β”‚
        β”‚               |   └───module_<module_vanity_id>
        β”‚               |       β”œβ”€β”€β”€1
        β”‚               |       β”‚   └───list
        β”‚               |       β”‚           item.liquid
        β”‚               |       β”‚           wrapper.liquid
        β”‚               |       β”‚
        β”‚               |       └───2
        β”‚               |           β”œβ”€β”€β”€detail
        β”‚               |           β”‚       item.liquid
        β”‚               |           β”‚       wrapper.liquid
        β”‚               |           β”‚
        β”‚               |           └───testimonials
        |               |               └───list
        |               |                       item.liquid
        β”‚               |                       wrapper.liquid
        β”‚               └───theme_02
        β”‚                   β”‚   layout_config.liquid
        β”‚                   β”‚
        β”‚                   └───module_<module_vanity_id>
        β”‚                       β”œβ”€β”€β”€1
        β”‚                       β”‚   └───list
        β”‚                       β”‚           item.liquid
        β”‚                       β”‚           wrapper.liquid
        β”‚                       β”‚
        β”‚                       └───2
        β”‚                           β”œβ”€β”€β”€detail
        β”‚                           β”‚       item.liquid
        β”‚                           β”‚       wrapper.liquid
        β”‚                           β”‚
        β”‚                           └───testimonials
        |                               └───list
        |                                       item.liquid
        β”‚                                       wrapper.liquid

Theme creators will normally have only a single theme folder containing multiple module folders to organise layouts accordingly. For Example:

└───modules
    └───module_<module_vanity_id>
        β”œβ”€β”€β”€private
        β”‚   └───views
        β”‚       └───partials
        β”‚           └───sitebuilder<secret_key_preceded_by_underscore>
        β”‚               β”‚   theme_config.liquid
        β”‚               β”‚
        β”‚               └───theme_<module_vanity_id>
        β”‚                   β”‚   css.liquid
        β”‚                   β”‚   js.liquid
        β”‚                   β”‚   layout_config.liquid
        β”‚                   β”‚   static_layouts.liquid
        β”‚                   β”‚
        β”‚                   β”œβ”€β”€β”€module_2
        β”‚                   β”‚   └───5
        β”‚                   β”‚           item.liquid
        β”‚                   β”‚           login.liquid
        β”‚                   β”‚           logout.liquid
        β”‚                   β”‚           wrapper.liquid
        β”‚                   β”‚
        β”‚                   β”œβ”€β”€β”€module_3
        β”‚                   β”‚   β”œβ”€β”€β”€3
        β”‚                   β”‚   β”‚   β”‚   archive.liquid
        β”‚                   β”‚   β”‚   β”‚   search.liquid
        β”‚                   β”‚   β”‚   β”‚   sidebar.liquid
        β”‚                   β”‚   β”‚   β”‚
        β”‚                   β”‚   β”‚   └───list
        β”‚                   β”‚   β”‚           item.liquid
        β”‚                   β”‚   β”‚           wrapper.liquid
        β”‚                   β”‚   β”‚
        β”‚                   β”‚   └───4
        β”‚                   β”‚       β”‚   archive.liquid
        β”‚                   β”‚       β”‚   search.liquid
        β”‚                   β”‚       β”‚   sidebar.liquid
        β”‚                   β”‚       β”‚
        β”‚                   β”‚       └───detail
        β”‚                   β”‚               item.liquid
        β”‚                   β”‚               wrapper.liquid
        β”‚                   β”‚
        β”‚                   β”‚
        β”‚                   β”œβ”€β”€β”€module_s1
        β”‚                   β”‚   └───2
        β”‚                   β”‚       β”‚   dynamic_wrapper.liquid
        β”‚                   β”‚       β”‚   static_wrapper.liquid
        β”‚                   β”‚       β”‚
        β”‚                   β”‚       └───components
        β”‚                   β”‚               array_custom.liquid
        β”‚                   β”‚               basic_payment.liquid
        β”‚                   β”‚               boolean.liquid
        β”‚                   β”‚               checkout_standard.liquid
        β”‚                   β”‚               datasource.liquid
        β”‚                   β”‚               datasource_multi.liquid
        β”‚                   β”‚               date.liquid
        β”‚                   β”‚               email.liquid
        β”‚                   β”‚               email_edit.liquid
        β”‚                   β”‚               file.liquid
        β”‚                   β”‚               folder.liquid
        β”‚                   β”‚               heading.liquid
        β”‚                   β”‚               hidden_fields.liquid
        β”‚                   β”‚               image.liquid
        β”‚                   β”‚               image_array.liquid
        β”‚                   β”‚               input_checkbox.liquid
        β”‚                   β”‚               input_radio.liquid
        β”‚                   β”‚               name_field.liquid
        β”‚                   β”‚               number_float.liquid
        β”‚                   β”‚               number_integer.liquid
        β”‚                   β”‚               password.liquid
        β”‚                   β”‚               password_edit.liquid
        β”‚                   β”‚               quote_only.liquid
        β”‚                   β”‚               recaptcha.liquid
        β”‚                   β”‚               select.liquid
        β”‚                   β”‚               select_multi.liquid
        β”‚                   β”‚               string.liquid
        β”‚                   β”‚               subheading.liquid
        β”‚                   β”‚               subscription_detail.liquid
        β”‚                   β”‚               textarea.liquid
        β”‚                   β”‚
        β”‚                   β”‚
        β”‚                   └───static
        β”‚                       β”œβ”€β”€β”€hero
        β”‚                       β”‚       3.liquid
        β”‚                       β”‚
        β”‚                       └───new_static_category
        β”‚                               3.liquid

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.

Step 2 - Create the Layout Config File

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.


{ 
{% comment %}Object. Required.{% endcomment %}
  "module_<module_vanity_id>": { {% comment %}Object. Required.{% endcomment %}
    "1": { {% comment %}Object (key matches the numbered folder containing the layout files). Required.{% endcomment %}
      "name": "Custom gallery image list", {% comment %}String. Optional (recommended, otherwise SiteBuilder will name the Layout by its module and a number).{% endcomment %}
      "type": "list", {% comment %}String ("default", "list" or "detail"- recommended most situations to choose list or detail. Default is used for modules which have no concept of list or detail, for example forms or some Secure Zones Layouts). Required.{% endcomment %}
      "image": "", {% comment %}String (image absolute URL). Required. A screenshot of the layout on a website. It can be tricky to get this right, but it's worth getting the best quality image possible to make your layout look attractive to users.{% endcomment %}
      "enabled": true, {% comment %}Boolean. Required. Set to false to hide the layout if it is not ready to be shown.{% endcomment %}
      "dest": "layouts/modules/module_<module_vanity_id>", {% comment %}String. Required. This is the main folder where the layouts will be installed. Currently it is not used, but exists for legacy reasons. Instead we use the similar fields inside the files array.{% endcomment %}
      "files": [ {% comment %}Array (array of objects). Required{% endcomment %}
        { {% comment %}Object. Required.{% endcomment %}
          "src": "list/item", {% comment %}String. Required. This should be a filepath relative to the folder with the same ID as this layout's source code. For example, the full filepath referred to here is "modules/module_<module_vanity_id>/private/views/partials/sitebuilder<secret_key_preceded_by_underscore>/theme_01/module_<module_vanity_id>/1/list/item.liquid" but only the path after the "1" folder and without the file extension is needed. {% endcomment %}
          "dest": "layouts/modules/module_<module_vanity_id>", {% comment %}String. Required. This should be a filepath relative to the marketplace_builder/views/partials folder where the module user's "installed" copy of the layout will be placed. Nested layouts, which we'll look at later, for example, embedding an author layout inside a Blog layout, use this to install layouts in any number of required locations.{% endcomment %}
          "install_type": "default" {% comment %}String (default,layout_is_liquid_file). Optional (default is default). Normally leave this property out. The default install process will look for a list/detail folder with the wrapper and item file inside and copy that structure in the destination folder. However, some layouts, like say, an Add to Cart button have a simpler structure with a single file which takes the name of the layout instead of a layout folder. In this case, set the install type to "layout_is_liquid_file"- which will take the file and rename it to have the name of the layout and put it directly inside the dest folder without a list/detail folder.{% endcomment %}
        },
        {
          "src": "list/wrapper", {% comment %}{% endcomment %}
          "dest": "layouts/modules/module_<module_vanity_id>"
        }
      ],
      "sub_module": 1 {% comment %}Integer. Required. Where a module might contain more than one kind of layout, each using a different Liquid syntax to output them, e.g. Secure Zones Login Forms and Logout Buttons, sub_modules are used to distinguish between them. If there is more than one sub_module defined in the module_config file, select the ID of the sub_module which best categorizes this layout. Only if no sub_modules are defined, can you add 0 to select no sub_modules. If you're not sure which sub_modules are available for a module, check the documentation for that module or contact the module creators.{% endcomment %}
    },
    "2": {
      "name": "Custom gallery video detail with embedded testimonials",
      "type": "detail",
      "image": "",
      "enabled": true,
      "coming_soon": false,
      "dest": "layouts/modules/module_<module_vanity_id>",
      "files": [
        {
          "src": "detail/item",
          "dest": "layouts/modules/module_<module_vanity_id>"
        },
        {
          "src": "detail/wrapper",
          "dest": "layouts/modules/module_<module_vanity_id>"
        },
        {
          "src": "testimonials/list/wrapper", {% comment %}Note this is an example of an embedded layout. We're still inside the same layout folder as the other files, but add another folder to keep the embedded layout files distinct and organised.{% endcomment %}
          "dest": "layouts/modules/module_8" {% comment %}Note this is an example of an embedded layout. The destination folder is actually in a completely different module folder. However, the name of the layout will remain the same. E.g. If the module user installs a layout and calls it "Gallery 2", both the Gallery Layout and the embedded Testimonials layout will have the folder names "module_<module_vanity_id>/gallery-2" and "module_8/gallery-2" respectively. See the embedded layouts section for more tips.{% endcomment %}

        },
        {
          "src": "testimonials/list/item",
          "dest": "layouts/modules/module_8"
        }
      ],
      "sub_module": 2
    }
  }
}

Step 4 - Adding the Content to Layout Source Files

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:

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.

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:

{%- if _show_pagination == 'false' and pagination_layout != blank and pagination_layout != "default" -%}
  {%- include 'modules/siteglide_system/get/get_pagination', pagination_layout: _pagination_layout -%}
{%- endif -%}

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:

{% comment %} ---Settings--- {% endcomment %}
{% comment %}------ Login URL ------- String for the URL of your login page. {% endcomment %}
{% assign login_url = "/login" %}
{% comment %} ---End Settings--- {% endcomment %}

Notes:

  1. 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.

  2. 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.

{% comment %}---Settings---{% endcomment %}
{% comment %}---End Settings---{% endcomment %}
{% capture sitebuilder_uniq_component_id %}sitegurus_component_{% increment sitegurus_gen_uniq_component_id %}{% endcapture %}

<div id="slider_{{sitebuilder_uniq_component_id}}" class="js-slider"></div>
<div id="toggle_{{sitebuilder_uniq_component_id}}" class="js-toggle-button"></div>
<script>
  (function () {
    var a = document.querySelector('#slider_{{sitebuilder_uniq_component_id}}')
    var b = document.querySelector('#toggle_{{sitebuilder_uniq_component_id}}')
    // Run JS for initialising your components here.
  })();
</script>

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

{% comment %}---Settings---{% endcomment %}
{% comment %}---End Settings---{% endcomment %}
{% capture sitebuilder_uniq_component_id %}sitegurus_component_{% increment sitegurus_gen_uniq_component_id %}{% endcapture %}

<div data-slider="{{sitebuilder_uniq_component_id}}" class="js-slider"></div>

JS

var sliders = document.querySelectorAll('[data-slider]');
sliders.forEach(
  function(slider) {
    var id = slider.dataset.slider;
    //Run JS to intialise the slider here.
  }
)

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").

|               |        └───testimonials
|               |               └───list
|               |                       item.liquid
β”‚               |                       wrapper.liquid

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.

{% capture testimonials_layout -%}{{layout}}/testimonials{%- endcapture %}
{% include 'module', id: '8', layout: testimonials_layout, type: 'list', item_ids: item_ids, _top_model: nil %}

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:

{% assign original_layout = _layout %}

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.

{% if this.properties['module_field_109_8'] != blank %}
  {% capture testimonials_layout -%}{{layout}}/testimonials{%- endcapture %}
  {% assign item_ids = this.properties['module_field_109_8'] | join: "," %}
  {% include 'module', id: '8', layout: testimonials_layout, type: 'list', item_ids: item_ids, datasource: 'true' %}
{% endif %}

Code Snippets

If your layout uses a significant amount of Liquid so it's not realy a static layout, but it doesn't rely on any specific Siteglide Module or WebApp database table, you may wish to install it as a code_snippet.

To make a layout install as a code snippet, set the "install_type": "code_snippet" in the layout_config file. It's only possible for these layouts to have a single file. It doesn't matter what you name the file, but the src setting in layout_config must match that name.

WebApp Layouts

WebApp Layouts work exaclty the same way as Module Layouts, but with some key differences.

WebApp Layouts can output standard fields like categories as normal, however, most of the fields you'll want to output will be custom fields.

To make field mapping possible, you need to first figure out the field slots you want in the item.liquid layout file, by adding Liquid code like so:

{{field_map['Example Field Slot']}}

This field slot can represent any potential webapp custom field. The module user will select which webapp custom field they think will best fit, based on the name and recommended type, so choose names carefully.

Then, you need to add an object to the layout_config.liquid JSON, to define these field slots (note instead of module_3 etc, the folder should be webapp, but it sits alongside the other module folders):

{
  "webapp": {
    "5": {
      "name": "Card with link",
      "image": "https://res.cloudinary.com/sitegurus/image/upload/f_auto/v1678980100/modules/module_86/admin/libraries/5/WebApps/webapp-card-1.png",
      "dest": "layouts/webapps",
      "files": [
        {
          "src": "list/wrapper",
          "dest": "layouts/webapps"
        },
        {
          "src": "list/item",
          "dest": "layouts/webapps"
        }
      ],
      "type": "list",
      "tags": [
        "card"
      ],
      "field_mapping": { {% comment %}{Object. Required (for WebApps). Defines field slots for mapping.{% endcomment %}
        "Title": { {% comment %}Object. Required. Human-readable name of the field slot. This must match the reference in the Liquid file itself.{% endcomment %}
          "required": true, {% comment %}Boolean. For very important fields which the Layout would not work without, set this to true. Otherwise, set to false and add logic within the layout to hide an element if the field is null. The user should expect the layout to work out of the box, so long as they mapped all required fields.{% endcomment %}
          "recommended_types": [ "input_text","input_radio","select" ] {% comment %}Array of Strings. Required. To help the user find a suitable field for this slot quickly, you must add an array of field types as defined by Siteglide. The UI will move fields of this type to the top of the options during field mapping. {% endcomment %}
        },
        "Card Icon": {
          "recommended_types": ["image", "file"]
        },
        "Description Short": {
          "recommended_types": ["textarea", "input_text"]
        },
        "Button Icon": {
          "recommended_types": ["image", "file"]
        }
      },
      "sub_module": 1
    }
  }
}

The installation process will automatically add Liquid code to the top of your layouts. One snippet of code defines the user's chosen field mapping as JSON, where the keys are the slot names and the values are the Siteglide WebApp field IDs. The second snippet of code takes values from this and assigns them to the headings in the field_map object.

WebApp Layout File Structure

WebApp List Layouts must have a wrapper and an item file.

"files": [
  {
    "src": "list/wrapper",
    "dest": "layouts/webapps"
  },
  {
    "src": "list/item",
    "dest": "layouts/webapps"
  }
],

WebApp Detail Layouts must have an item file. Since WebApp Detail views don't allow you to set the use_wrapper parameter, you need to write the layout without a wrapper. You also must set the install_type to webapp_detail which makes sure the file is renamed as the layout name given by the user.

"files": [
  {
    "src": "list/item",
    "dest": "layouts/webapps",
    "install_type": "webapp_detail"
  }
],

Front-End Access to Module / WebApp Config Data

You can use the table_config function to fetch additional information about the layout which you may wish to output, e.g. the name of the WebApp and the names of the fields.

Troubleshooting Layouts

  1. 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.

  2. 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.

  3. Check that the raw tags are present in each file.

  4. 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.

  5. 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.

PreviousCreate Marketplace ModulesNextAdding Static Layouts to your Theme

Last updated 2 months ago

Was this helpful?

Where your layout contains any Liquid code which you wish to render at runtime, you need to wrap it in the raw liquid tags, see . 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.

ℹ️
https://documentation.platformos.com/api-reference/liquid/introduction#raw
VSCode regex find and replace ((.|\n)\*) with $1.