# Templates

One of the most important aspects when creating the site is the base architecture and appearance of the site. In Template Builder, you'll be able to modify the base templates, along with the global JavaScript and CSS to use on your pages and change their structure as required.

Once you have selected a theme for a new site, you can access each template in the Template Builder and make any change you need.

Once inside the Template Builder, the main menu is hidden to optimize the workspace. In the top bar, on the left, you can find the section name and the current publication status.

Template Builder

  • Published: There is a published version of the templates and that the editable version you are working on now matches the state of the published version. This status changes whenever you save any changes to your templates.
  • Pending changes: When there is a previously published version, this status indicates that your editable version has "pending changes" that have not been published.
  • In review: This status appears when Team review is enabled and the editable version of your templates has changes that have been submitted for review.
  • Approved: When Team Review is enabled and if the item's review conditions were met. If you're in this state, your templates are ready to be published.

On the right side of the upper bar, you will find the latest publication date and the available actions:

Preview : Clicking this icon opens a new tab with the template preview mode, in which you will see how it looks as if they were published, with all the changes you have in your templates.


You can preview the changes as a user without a session, or with Modyo a session. For this, it's recommended to log in or log out of Modyo from your site before entering preview mode, because if you log out while in preview mode you might encounter security errors like x-frame-options or mixed-content, depending on your site's SSL and custom domain settings.

Differences : Clicking this icon will take you to the difference view, in which you can compare changes between multiple versions of your templates.

By default, you start by comparing the published version to the editable version. Using the version selectors, you can also compare with backup versions.


Every time you publish a new version, the version that gets replaced now becomes a backup version. By default, up to 20 backups are saved so that the most recent twenty backups can be compared, restored or used for a rollback. For more information on versioning, check out the versioning section .

Search in templates : Deploys a sidebar with a text finder that searches all editable templates.

Activity/Comments : Deploys a sidebar with the activity history and comments of the templates.

You can add new comments at the bottom of the sidebar. Next to each activity, you can also click on see detail to show the complete information of an activity log.

More actions :

  • Themes: This takes you to the Themes Gallery, where you can copy the current theme and use it in the other sites or channels in your account. To learn more, check Themes.
  • Restore All: You restore all templates to the original value of the theme.

Primary Actions

  • Save: Saves all changes to all templates.
  • Send for Review: Change the status of templates to “Waiting for Review”. In this state you can continue to make changes, but each change will be notified via email to the assigned reviewers.
  • Reject: Returns the status to "Pending changes" and notifies reviewers that the item was rejected.
  • Publish: Once the templates are approved, you can go to the co-publish view and publish your templates.

In the main work area, there are two sections:

  • The central work area.
  • The template selection area.

Each template you click on the right sidebar, opens a text editor in the middle area. If you open multiple templates, they are opened as tabs in the workspace.

The template bar on the right has two tabs: views and snippets.

# Custom Layouts

Modyo has three default layouts:

  • Home: Used exclusively on the home page of the site.
  • Base: All pages except the home page use this default layout.
  • Error: The error views use this clean layout (404, 401)

You can create new Layouts from the template builder, by clicking on "Add Layout" in the "Views" tab, which will allow you to define a new base structure to use on the pages.

You can use this code as a base, this contains everything you need to make your pages use all the necessary elements of the site, such as the head, header, footer, service worker, and Google Tag Manager settings, but keep in mind that you can modify it as much as you want:

{% html5 %}
  {% snippet 'shared/general/head' %}

{% body %}
{% snippet 'shared/general/body_tag_manager' %}
{% snippet 'shared/general/header' %}

{{ site.breadcrumb }}
<div id="main-layout">
{{ content_for_layout }}

<script>{% snippet "shared/serviceworker/register_js" %}</script>
{% snippet 'shared/general/footer' %}

{% endbody %}
{% endhtml5 %}

After you have created your new layout, you can start using it by going to the page editing view and changing it from the properties tab.

# Content views

In order to automatically display content on a site, you need to meet certain conditions:

  • Have a space with at least one language (the same language as the site) and at least one Type. Go to Spaces and Types to learn how.
  • Have entries published in the language of the site. Go to Entries and Location to learn more.
  • Create a custom view in the Template Builder.

To create a custom view in the Template Builder, go to the "Views" tab. At bottom of the list, there is a section called Custom and a button + Add a custom view. Click this to create a new custom view. You must type a name, select a space and choose a content type for this view to link to.

# Create a new Content View Template

To create a new Content View template with a custom dynamic page connected to Modyo Content, follow these steps:

  1. From the Modyo Platform main menu, expand Channels, and click your site.
  2. Click Templates.
  3. To create a new Content View, click the**+** button.
  4. Enter the path of the new template, select a Space, and select the type of entry that the template will belong to.
  5. Click Add.
  6. Customize the View by adding input attributes, custom fields, Snippets, HTML, CSS, JavaScript, or Liquid.
  7. Once finished, click on Publish.

::tip Tip To learn more about how to create a custom content view, see Creating a Content View. :::


The name of the view is the route (URL) relative to the site with the content you want to show. For this reason, you have to be careful when naming your views.


You can freely choose the name of each view, regardless of the space and content type you choose. You have to keep in mind that it is required to have an entry published in this site language in order to see content in these views.

By modifying this view, you can make use of Liquid and the entry object, for example: {{entry.published_at | format_date}}

A basic example of Liquid + HTML code that you can use to get started in these views is:

  <h1 class="title">{{ entry.name }}</h1>
  <time>{{ entry.published_at | format_date }}</time>
  <span class="url">
    <a href="{{request.url}}">{{request.url}}</a>

  <div class="description">
    {{ entry.description }}

This snippet takes entry.name, entry.published_at, request.url, and entry.description to generate a dynamic content view depending on the input you select.


To learn more about how to use Liquid, go to Liquid markup.

If you want to display the view with the values of the entry you're working on, the following requirements must be met:

  • The view must be created and published.
  • The URL being accessed is of type site_url/custom_view_name/entry_slug.
  • The custom_view_name is the name of the content view you created.
  • The URL matches the name of the view you just created.
  • An entry already exists in the language of the site.
  • The slug of the input is entry_slug.


If custom domain is enabled, to find the URL you must go to Site Settings > Domains.

In case it is not enabled, the URL will be in the form account_url/site_host.

# Errors in Views

In the views section, you will find 4 error types available for customization:

  • Disabled: You'll see this error if the site you're trying to access has been disabled.
  • 404: You will see this view if you enter a site URL that is not defined and if you decide to show 404 errors in the site restrictions instead of redirecting to the home page.
  • Privacy: You will see this error view if you don't have permission to access the site or one of its pages.
  • Template: You'll see this error when the page of the site you're loading has a liquid syntax error. It is unlikely that you will see this view, since from modyo 8.1 onwards we have a functionality that checks the syntax of liquid before you can save and publish changes to the template builder.

# CSS and JavaScript

You can create custom CSS and JavaScript templates by clicking the + buttons in the CSS and JavaScript sections respectively at the bottom of the Views tab.

To include any of these templates, different Liquid filters are available: asset_url to generate the template URL, and stylesheet_tag and script_tag to generate the corresponding tags, e.g.

  {{ 'my-css' | asset_url: 'css' }}
  {{ 'my-css' | asset_url: 'css' | stylesheet_tag }}
  {{ 'my-js' | asset_url: 'js' | script_tag }}

For more details and the parameters supported by these filters, see Liquid filters.

# Snippets

Snippets are pieces of code that can be created, modified, and reused. Next to each custom snippet, you'll find an icon () that you can use to copy the snippet's reference path. The copied code looks like this: {% snippet "snippet-name"%}.

You can add custom snippets to the bottom of the platform's snippet list by clicking on the + button.


In order for the system to recognize the programming language type of the snippet, place an underscore followed by the language type at the end of the snippet name (i.e. "front_css" or "library_js"). Without this naming syntax, the Template Builder assumes the snippet is HTML by default.


All elements of the Template Builder use Liquid as a templating engine.

For more information on what Liquid is and how to get the most out of it, check out the Liquid Markup page.

In the work area, under the tabs, you will find a bar with useful elements:

Asset manager: Opens a modal that lists all account files and provides filtering and search capabilities. Clicking on the image preview or file name opens an editor where you can resize/crop the image and change its attributes, such as the title or alternate text. Selecting the copy icon provides you with a URL you can paste and you can click on the "Upload files" tab to upload files.


For more information on the functionality of the Asset Manager, go to the Asset Manager.

Shortcuts helper: Opens a small pop-up that displays useful keyboard shortcuts for the Template Builder.

Snippets: Displays a list of custom snippets along with the option to copy the reference code of each snippet to insert them in a template.

Changes: A list of every "Saved" state of a template since it was last published. Click on any of these saved states to change the content of the template you are working on to that particular saved state. If you decide to do so, all your current changes will be lost.


If you publish a new version of your templates, this list of changes resets and erases all saved states. This is because the new editable version now matches the version you just published. Saving new changes adds new saved states until the next time you publish.


Sub-versions are for each template, so for some you may notice that there are changes and for others you won't see the change selector. Likewise, if you go back to a previous sub-version of a template, you won't affect the rest of the templates.


If an earlier version of your templates is restored, you can access the saved states of each template of that restored version. You can learn more about versioning here

You can reset all templates to their original version by clicking on the secondary action of the top bar " Reset All". If you want these reset changes to show up in the front end, you must publish them.

# Themes

In this view you can see what theme you have installed and a list of all the installed themes on the site.

By clicking on the Use button of an installed theme, you replace the content in all your editable themes with the content of the new theme you are using. You can preview these changes using the Template Builder preview mode and then publish them to use the new theme in the published site.

At the top of this view, you can find a few useful actions:

  • Theme Gallery: This opens a modal with all the themes available to install on the site. You can choose to install the default Modyo themes or the account themes (those you converted to themes from other sites). When you install a theme from the theme gallery, you will change the editable version of your templates to the templates of the theme you just installed.
  • Customize : Takes you to the Template Builder of the currently installed theme.
  • Convert to theme : Creates a copy of the currently installed theme as a global theme in your account. you can select a new name for this copy and use it for other sites in your account.
  • **Reset ** : Like the reset action of the template builder, this action restores all editable templates to their original versions.
  • Load templates : In some cases, after complex migrations, there may be some unmodified templates that could be lost and you may not see them in the template list of the Template Builder. This action retrieves those templates from the original theme and allows you to recover them.


The "Load templates" action does not modify the editable templates that are already in the Template Builder. It only restores those in the Themes Gallery.


When you create a theme from a site or channel, that theme becomes available to all other sites in your account. This means you can create a base theme and then use that theme to rapidly build new sites.


SEO (Search Engine Optimization) is one of the most important topics of your site and content.

In Modyo, we have a way to control the way search engines read your site and content, dynamically adding meta tags depending on the attributes you add to your pages and content.

You can add this code snippet to the Template Builder and then call this snippet from the head of your site:

<!-- Site SEO -->
<meta name="keywords" content="{{ site.keywords }}" />
<meta name="author" content="{{ site.name }}" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
{% if page %}
<!--Layouts SEO -->
{{ page.meta_tags }}
<meta name="description" content="{{ page.excerpt }}" />
<meta property="og:title" content="{{ page.title }}" />
<meta property="og:type" content="website" />
<meta property="og:url" content="{{ page.url }}" />
<meta property="og:image" content="{{ site.logo | asset_url : 'original' }}" />
<meta property="og:site_name" content="{{ site.name }}" />
<meta property="og:description" content="{{ page.excerpt }}" />
{% endif %} 
{% if entry %}
<!-- Content SEO -->
<meta name="description" content="{{ entry.excerpt }}" />
<meta property="og:title" content="{{ entry.title }}" />
<meta property="og:type" content="article" />
<meta property="og:url" content="{{site.url}}/{{entry.type_uid}}/{{entry.slug}}" />
<meta property="og:image" content="{{ entry.covers.first | asset_url : 'original' }} "/>
<meta property="og:site_name" content="{{ site.name }}" />
<meta property="og:description" content="{{ entry.excerpt }}" />
{% endif %} 
{% unless page or entry %}
<!-- Default SEO -->
<meta name="description" content="{{ site.description }}" />
<meta property="og:title" content="{{ site.name }}" />
<meta property="og:type" content="website" />
<meta property="og:url" content="{{ request.url }}" />
<meta property="og:image" content="{{ site.logo | asset_url : 'original' }}" />
<meta property="og:site_name" content="{{ site.name }}" />
<meta property="og:description" content="{{ site.description }}" />
{% endunless %}
<!-- END SEO <-->

This snippet is different when you're using a custom page, Modyo's default pages, or content views, so by using the attributes of each element, you can define a good SEO base for all your site's URLs.

If you require it, you can customize this snippet, defining what you want to appear for specific URLs or types.

For example, in the content section, you can use:

{% if entry %}
<!-- Content SEO -->
<meta name="description" content="{{ entry.meta.excerpt }}" />
<meta property="og:title" content="{{ entry.meta.title }}" />
<meta property="og:url" content="{{site.url}}/{{entry.meta.type_uid}}/{{entry.meta.slug}}" />
<meta property="og:image" content="{{ entry.fields.covers.first | asset_url : 'original' }}" />
<meta property="og:site_name" content="{{ site.name }}" />
<meta property="og:description" content="{{ entry.meta.excerpt }}" />
{% if entry.type_uid = 'posts'%}
<meta property="og:type" content="article" />
{% if entry.type_uid = 'place'%}
<meta property="og:type" content="place" />
<meta property="place:latitude" content="{{ entry.location.first.latitude }}" />
<meta property="place:longitude" content="{{ entry.location.first.longitude }}" />
{% endif %} 
{% endif %} 

In this example, the posts and place types share the title, excerpt and covers attributes, but the place types contain location attributes. In addition, we would need to define a different custom view in our site for each of these separate types.

# Integrations

# Private session management using OpenID Connect (OIDC)

The recommended method for interacting with a private API using the Modyo session with an OIDC integration consists of two steps: make the site private and enable account-level integration.

# Make the site private

  1. Log in to the account where you want to create a private site.
  2. Click on create a new site.
  3. Assign a name to the new site and select the base theme.
  4. In the Site > settings section, under the Restrictions tab, we select private under the Privacy level. This also activates Show home page to public visitors in order to redirect users without a session.

# Enable account-level integration (for all sites)

  1. In your account, go to Customers and from there to the Customer settings section and a the top of the view, click the drop down and select the Integration tab.
  2. Select the OpenID Connect integration and check the box for Enable OpenID Connect
  3. Fill in the data for Service Name, Client ID, Secret, and Issuer and click Launch Discovery Service
  4. Check the fields you need
    • Enable refresh token
    • Enable remote logoff
    • Enable token revocation
    • Enable claim synchronization
  5. Associate the provider fields with the custom fields you have in Modyo OpenID Connect 1.0 specification for Standard Claims (opens new window)

# Using Axios to do the integration

If you want to use a library such as axios to perform an integration from Modyo, a convenient pattern is to create 3 snippets that take care of the most basic aspects of an integration.

The tasks you must cover with these snippets are:

  1. A request interceptor to include a token.
  2. A session controller.
  3. A modal window that informs the user that their session will expire.

# Intercept requests to include a token

// global variable that represents an axios instance that will take care of the service's petitions
var axios_api = axios.create();
axios_api.defaults.baseURL = 'URL DE API';

// global variable that represents an axios instance that will take care of the petitions of Modyo's API
var axios_modyo=axios.create({
  baseURL: window.baseUrl + '/api/admin',
// global variable that represents an axios instance that will take care of the petitions of the site's content json
var axios_modyo_json=axios.create({
  baseURL: {{site.url}},
// global variable that represents an axios instance that will take care of the petitions regarding authentication
var axios_auth = axios.create();
axios_auth.defaults.baseURL = window.baseUrl + '/auth/openidc';
// function that generates activity in the site with each authentication petition
var resetIdleTime = function(request){
    return request;
// function that adds the token to each request
var appendTokenToRequest = function (request) {
    return axios_auth.get('/access_token').then(function(response){
        request.headers.authorization='Bearer '+ response.data.access_token;
        return request;
// function that manages the errors from each petition and calls a higher-level instance
var errorRequest=function(error){
  throw error;
axios_api.interceptors.request.use(appendTokenToRequest ,errorRequest);

# A session controller

//will be in charge of raising the warning modality that will warn the close of the session, this variable will return a promise that will be effective if you click on the Hold Session button and will issue a reject promise in the case of selecting the button with the refusal to continue
var modalConfirm=function () {
  return new Promise (function (resolve, reject) {
    $ ("# session-modal"). modal ({
      backdrop: "static",
      keyboard: false,
      show: true
    $ ("# session-modal-yes"). on ("click", function () {
      resolve ("keep session");
      $ ("# session-modal"). modal ("hide");
    $ ("# session-modal-no"). on ("click", function () {
      reject ("destroy session");
      $ ("# session-modal"). modal ("hide");
//it will be the one that will be in charge of starting the time tracking to lift this modal and handle the Front side of the session, then we will explain each of the properties and methods of this object that handles the session
var sessionManager={
  //property that defines the time from the last activity until the end of the session in seconds (note not the refresh time of the token but the end of the session, it is recommended that this be one minute shorter than the one declared by the provider of the Open ID Connect to have a little slack with the session and closing it is 100% valid)
  timeToEndSessionInSeconds: 900,
  //property where the lifting time of the inactivity modal is defined since the last action or request on the page
  timeToRaiseWarningModalInSeconds: 720,
  //property that saves the timestamp of the last moment of activity of the sessionManager
  lastActionTimeInThisWindow: new Date (). getTime (),
  //function that converts seconds to milliseconds
  secondsToMilisecs: function (minutes) {
    return minutes * 1000;
  //property to store the session id interval of session review
  intevalId: null,
  //function that determines if the application is being accessed from the modyoShell or not
  isModyoAppShell: function () {
    return/; Modyo_App_Shell/.test (navigator.userAgent);
  //method that must be executed on each page load to begin the process of session events to follow up recommended do this invocation sessionManager.init () in the head of the layout to begin tracking the session (in some cases it will be defined that developers do not launch this invocation in that case the test api to connect us must also have this if and so we will achieve that axios_api serves for the develop and development environment one with session and the other without session manager)
  init: function () {
    this.resetIdleTime ();
    this.intevalId=this.interval ();
  //restart the timeout or create a new activity on the site
  resetIdleTime: function () {
    this.lastActionTimeInThisWindow=new Date (). getTime ();
    var sessionEndTime =
      this.lastActionTimeInThisWindow +
      this.secondsToMilisecs (this.timeToEndSessionInSeconds);
    localStorage.setItem ("timeToEndSession", sessionEndTime);
    var raiseWarningModalTime =
      this.lastActionTimeInThisWindow +
      this.secondsToMilisecs (this.timeToRaiseWarningModalInSeconds);
    localStorage.setItem ("timeToRaiseWarningModal", raiseWarningModalTime);
  //method that initiates the activity every second js that will handle the session events
  interval: function () {
    var self=this;
    return setInterval (this.checkSessionEvents, 1000, self);
  //method that raises the warning time modal
  raiseModal: function () {
    return modalConfirm ();
  //logout method and clean storage
  logout: function () {
    localStorage.clear ();
    sessionStorage.clear ();
    clearInterval (this.intevalId);
    var withRedirect =
      arguments.length> 0 && arguments [0]! == undefined? arguments [0]: false;
    if (withRedirect) {
      window.location.href =
    } else {
      window.location.href="{{site.account_url}}/logout? site={{site.uuid}}";
  //method that reviews session events to determine if it is time to close it or keep it after showing the modal
  checkSessionEvents: function (self) {
    var sessionEndTime=localStorage.getItem ("timeToEndSession");
    var raiseWarningModalTime=localStorage.getItem ("timeToRaiseWarningModal");
    var diffInSecsToShow =
      Math.round ((sessionEndTime - new Date (). GetTime ())/1000)> 0
        ? Math.round ((sessionEndTime - new Date (). GetTime ())/1000)
        : 0;
    var expirationTimeHtml=document.querySelector ("# expiration-time");
    var timeNow=new Date (). getTime ();
    if (sessionEndTime - timeNow <0) {
      self.logout ();
    } else if (raiseWarningModalTime - timeNow <0) {
        .raiseModal ()
        .then (function (response) {
          axios_auth.get ("/access_token");
        .catch (function (err) {
          self.logout ();
    } else {
      if (($ ("# session-modal"). data ("bs.modal") || {}) ._ isShown) {
        $ ("# session-modal"). modal ("hide");

# A modal window that informs the user that their session will expire

This should be the modal to activate in the previous step with bootstrap for handling the warning modal.

  class="modal fade"
  tabindex="- 1"
  <div class="modal-dialog" role="document">
    <div class="modal-content">
      <div class="modal-header">
        <h5 class="modal-title" id="session-modal-label">
          Your session will expire
      <div class="modal-body text-center">
          Your session will expire in <span id="expiration-time"> </span> seconds.
        <p> Do you want to keep your session? </p>
      <div class="modal-footer">
        <button id="session-modal-yes" type="button" class="btn btn-primary">
          class="btn btn-secondary"