# Templates

The base architecture and appearance are essential aspects of a site. In the Templates section, you can adjust the base templates as well as the global JavaScript and CSS and modify the structure as needed.

When you create a site, it comes complete with different templates to generate the Minimal theme, and you can start creating your digital channel on it. You can also create HTML, JS, and CSS code snippets to extend the functionality of your site.

In the templates section, the main menu is hidden to optimize the work area. At the top left, you'll find the name of the section and the current status of the post:

  • Published: There is a published version and the editable version is identical.
  • Pending changes: There is a published version, but there are changes pending publication in your editable version.
  • Under review: Team review is active, and the editable version has been submitted for review.
  • Approved: Team review is active and the item's review conditions have been met. In this state, the template is ready to be published.

At the top right, you can see the last date of publication and icons with the available actions:

Preview: Click on this icon to open a new tab with a preview of the templates. Here you can view all the changes to your templates, as if they were published.

Attention

You can preview the changes as a non-session user or a user with an active Modyo session. For this reason, we recommend starting or closing the Modyo session on the site before entering preview mode, given that if you start or close the session in preview mode. This is because logging in or logging out in preview mode can generate security errors such as x-frame-options or mixed-content, depending on the site's custom domain and SSL configuration.

Differences: Compare changes between multiple versions of your templates. By default, Modyo compares the published version with the editable version. Use the version selectors to compare with backup versions.

Tip

Every time you publish a version, the version that was published becomes a backup version. By default, up to 20 backups are saved, allowing you to compare, restore, and roll back to the last 20 versions

For more information on versioning, see the section on versioning.

Search in templates: Displays a sidebar with a text search engine that explores all editable templates.

View activity: Displays a sidebar that shows the activity history and where you can read and write comments. Click on view detail to show the full information of any activity log.

More actions: This icon allows you to Archive or Delete the open template. These actions are only available on templates that can be deleted, such as the ones you create or the Home layout. The other templates the site comes with, such as the Base and Error layouts, cannot be archived, unpublished, or deleted.

  • Archive: Available when the template has no published version; if it has one, unpublish it first. An archived template cannot be edited and disappears from the list. To see it, turn on Show archived at the bottom of the side panel and, if you want to use it again, click Restore.
  • Delete: Available when the template is archived and has no published or scheduled version. This action is irreversible.

The last option in the top bar shows the main actions you can perform:

  • Save: Saves all changes to all templates.
  • Submit for review: Changes the status of the templates to "Awaiting Review". In this state, you can continue to make changes, but each change will be notified by email to the assigned reviewers.
  • Force publication: Only available to site administrators, allows you to immediately publish a template, even if it is awaiting review.
  • Reject: Returns to "In Edit" status and notifies reviewers that the item was rejected.
  • Publish: Once the template has been approved, you can send it to publish.
  • Unpublish: Available on published templates that can be deleted. Choose Unpublish now, or Unpublish on to schedule it for a date. Published templates that reference the unpublished template can no longer render it.

In the main work area, there are two sections:

  • The editing area: Clicking on a template from the list in the selection area on the right side will open the template in the central area with a text editor. If you open multiple templates, they will open as tabs in the workspace.
  • The template selection area: Select the views or snippets tab, as required.

# Layouts

Modyo offers three predefined layouts:

  • Home: Exclusively for the main page of the site.
  • Base: All pages, except the home page, use this layout.
  • Error: Used in the site's three error views (404, disabled, and template), showcasing a clean design.

To create a new layout:

  1. In the Templates section, click on the Views tab
  2. Click the + button next to Layouts.
  3. Add the Route and click Add.

This allows you to define a new base structure for use on pages.

When you create a layout, Modyo initializes it with a minimal structure. If you want your pages to use every element of the site, such as the header, the footer, the service worker, and the Google Tag Manager configuration, replace that content with the same code that ships in the Base layout and adjust it as needed:

{% html5 %} <!-- HTML header with browser directives -->
<head>
  {% snippet 'shared/general/head' %}
</head>
{% body %} <!-- Body with automatic context classes -->
{% snippet 'shared/general/body_tag_manager' %}
<div id="modyo-site-alert-wrapper"></div>
{% snippet 'shared/general/header' %}
<main id="content">
  <div id="breadcrumb" class="mt-8">
    <div class="container breadcrumb-inner">
      {{ site.breadcrumb }}
    </div>
  </div>
  {{ content_for_layout }}
</main>
<script nonce="{{csp_nonce}}">{% snippet "shared/service_worker/register_js" %}</script>
{% snippet 'shared/general/footer' %}
{% endbody %}
{% endhtml5 %}

If you write your own layout, watch out for these three details:

  • <div id="modyo-site-alert-wrapper"></div> is the container where the site injects its alerts. If you leave it out, the alerts are not displayed.
  • <main id="content"> wraps the page content and is the anchor used by the theme and by the site's error views.
  • The nonce="{{csp_nonce}}" attribute is required on every inline <script> or <style> tag when your web app's Content-Security-Policy includes the nonce directive. Without it, the browser blocks the script and the service worker is never registered.

Attention

The path of the snippet that registers the service worker is shared/service_worker/register_js, with an underscore between service and worker. If you write it any other way, the snippet does not resolve and the registration is not injected into the page.

To apply a new layout to a page, follow these steps:

  1. Publish the layout. Only published layouts appear in the pages' Layout selector.
  2. Go to the Pages section and open the page.
  3. Choose the layout in the Layout field. On a widget page, it is in the Properties tab. On a content page, you choose it separately for the Index and the Show, in the Edit tab.
  4. Submit the page for review or publish it, as required.

Attention

If you unpublish or delete a layout, the pages that use it are displayed with the Base layout. Before you unpublish it, if there are published widget pages that use it, Modyo tells you how many. When you delete it, the editable version of the widget pages it was assigned to also switches to the Base layout, and that change stays pending until you publish them.

# Inserting an Image with Liquid

Modyo recommends using the Liquid tag and not the asset URL to insert images into your content. This allows you to resize or replace an image wherever it is in use, and ensure that any changes are immediately reflected.

In addition, Modyo converts the image to webp format with lossless compression quality. This generates lighter images, with shorter load times, and without loss of quality.

# To get the Liquid code from an image:

  1. Click on the media icon above your work area
  2. Click on the image.
  3. Click on the copy icon, next to the Liquid tag in the image.

# To replace an image, follow these steps:

  1. Click on content.
  2. Select the space that the image that you want to modify is in.
  3. Click on media.
  4. Select the image you want to replace.
  5. Click on the upload image icon above the current image.
  6. Select the new image.
  7. Click on update information.

Tip

It is necessary that your account's CDN is in the cloud for changes to be reflected immediately, otherwise you will need to request cache invalidation via a ticket to Modyo (opens new window).

# Errors in Views

In the Views tab, inside the errors group, you can customize the three error views that the site ships with. All of them are rendered with the Error layout:

  • disabled: Displayed when the site you are trying to access is disabled.
  • 404: Displayed when you enter a URL that does not resolve, and also when a signed-in user opens a private page whose segments do not apply to them. If you enable Redirect to home when a URL is not found in the web app settings, the visitor goes to the home page instead of seeing this view.
  • template: Visible when the loaded page has a Liquid syntax error. It is unlikely that you will see this view, as from Modyo 8.1 onwards, the platform performs a syntax check before saving and publishing changes to Templates.

There is no error view for privacy. When a visitor without a session requests a private site or page, the platform does not render any error view: it redirects them to the site's login page, or to the signup page if the web app is configured that way, and returns them to the URL they requested once they sign in.

Tip

As of Modyo 10.2, origination pages also respond with the 404 view and the site's styles when the URL does not resolve. They previously returned an empty body, so any customization you make to this view is also reflected on those URLs.

# CSS and JavaScript

Create custom CSS and JavaScript views to import your libraries to Modyo Platform. To do this, follow these steps:

  1. In the Templates section, click on the Views tab.
  2. Go to the CSS or JavaScript section, below the Layout section.
  3. Click on the corresponding + button.
  4. Add the Route and click Add.
  5. Once you have finished editing the Style Sheet or Javascript, you must include it in your layout. To do this, you can use the following Liquid filters:
  • asset_url: To define the file type
  • stylesheet_tag: Generates a <link> tag to include the CSS view.
  • script_tag: Generates a <script> tag to include the Javascript view.

# Examples

  • A custom CSS view with media: screen
  • A custom Javascript view with asynchronous loading
<head>
  {{ 'my-css' | asset_url: 'css' | stylesheet_tag: media: 'screen', title: 'color style' }}
  {{ 'my-js'  | asset_url: 'js'  | script_tag: async: 'async', defer: 'defer' }}
</head>

Once saved and published, it translates into the following HTML code:

<link href='my-css' rel='stylesheet' type='text/css' media='screen' title='color style' />
<script src='my-js' type='text/javascript' async='async' defer='defer'></script>

To obtain detailed information and learn about the parameters supported by these filters, refer to the Asset URL, Script tag, Stylesheet Tag, Theme Javascript and Theme Stylesheet entries.

# How site CSS and JavaScript are served

Every CSS or JavaScript view you create in Templates is published as a file with its own URL, which the Liquid filters resolve for you. That URL includes a version that updates when you publish the site, which means that:

  • Visitors get the new file as soon as you publish, without you having to rename the view or ask for any cache to be cleared.
  • As long as the version does not change, the browser can reuse the file across the different pages of the site instead of downloading it again on each one.
  • In preview mode the file is never served from cache, so you see your changes right away.

# Controlling how the file loads

By default, a stylesheet blocks the page from painting until it finishes downloading, and a script blocks HTML parsing. The script_tag and stylesheet_tag filters accept any attribute, so you can adjust that behavior while still using the versioned URL:

<head>
  {{ 'base'      | asset_url: 'css' | stylesheet_tag: media: 'screen' }}
  {{ 'print'     | asset_url: 'css' | stylesheet_tag: media: 'print' }}
  {{ 'main'      | asset_url: 'js'  | script_tag: defer: 'defer' }}
  {{ 'analytics' | asset_url: 'js'  | script_tag: async: 'async' }}
</head>
  • defer downloads the script in parallel and runs it once the document has finished parsing, preserving the order in which you declared the scripts.
  • async runs it as soon as it is available, with no guaranteed order. Use it only for scripts that are independent of each other.
  • media limits a stylesheet to a specific context, such as printing.

The theme_javascript and theme_stylesheet filters produce the same versioned URL, but do not accept attributes. If you need any, use the combination above.

# Theme view or inline code

Writing the CSS or JavaScript directly in the template, inside a <style> or <script> tag, saves one network request, but moves those bytes into the HTML document, which is downloaded in full on every page the user visits and is not reused between them. As a general rule:

  • Publish as a theme view all the CSS and JavaScript shared by several pages. It is downloaded once and reused across the rest of the site.
  • Reserve inline code for small fragments specific to one page, or for the minimum styles the first visible screen needs.
  • Keep in mind that an inline <style> block also blocks the page from painting: writing it in the template does not make it free.

# Snippets

Snippets are reusable fragments of HTML, JS, or CSS code for your sites. To use a snippet:

  1. Copy the reference path of the custom snippet. The Liquid code will look like: {% snippet "snippet-name"%}.
  2. Paste the code wherever you want to call this Snippet.

To add a custom snippet:

  1. In the Templates section, click on the Snippets tab
  2. Navigate to the Custom section, at the bottom of the list of snippets.
  3. Click the + button
  4. Add the Route and click Add.

Important

For the system to recognize the programming language to which the snippet belongs, you must add an underscore and then the ending, as follows: "front_css" or "library_js". By default, the system will recognize the snippet as an HTML language.

Tip

All elements of the Template Builder use Liquid as the template engine. For more information about Liquid and how to use it, see the Liquid Markup section.

In the work area, below the tabs, you will find a bar with these elements:

Toolbar items The toolbar below the Template Builder tabs contains the following elements:

  • File Manager: Opens a modal that allows you to access all the files in your account and copy their URL. Select the Upload Files tab to upload new files. For more information about the benefits and features of File Manager, go to File Manager
  • Keyboard Shortcuts: Shows useful keyboard shortcuts for Templates.
  • Snippets: Displays a list with all the snippets and the option to copy their reference code.
  • Changes: Displays a list of all the times and states in which you have saved the current version. By clicking on one of the sub-versions, you change the content of the template to that sub-version.

Tip

When you publish a version, the list of changes disappears, because the new editable version has not changed.

Tip

Subversions are specific to each template, so some may have changes and others may not, and those without changes will not show the change selector. In the same way, if you go back to a previous sub-version of a template, you do not affect the rest of the templates.

Tip

If you restore a previous version to the editable version, you can access the sub-versions of each template in that version. You can learn more about versioning here.

Each template is versioned separately. To return a template to a previous version, open it, click Differences, and use Reset to this version, which brings that version into the editable version, or Rollback to this version, which publishes it directly. For more details, see Revert a Change.

# SEO

SEO (Search Engine Optimization) is essential for positioning your site and content.

In Modyo, you can control how search engines read your site and content, by dynamically adding meta tags, depending on the attributes you add to your pages and content.

Among the templates the site is created with is the shared/general/seo snippet, which the shared/general/head snippet loads in the head of the Home, Base, and Error layouts. You can find it in the Snippets tab, and its initial content is the following:

<!-- Site SEO -->
<meta name="author" content="{{ site.name }}"/>

{{ site.meta_tags }}

{% if page %}
    <!-- Page SEO -->
    {{ page.meta_tags }}
{% endif %}

<!-- END SEO -->

{% if page_scope == 'show' %}
    <!-- Content Page: Show -->
    <meta name="description" content="{{ entry.meta.excerpt }}"/>
    <meta property="og:title" content="{{ entry.title }} | {{ site.name }}"/>
    <meta property="og:description" content="{{ entry.meta.excerpt }}"/>
    <meta property="og:type" content="article"/>
    <meta property="og:url" content="{{ entry.url }}"/>
    {% if site.logo %}
        <meta property="og:image" content="{{ site.logo | asset_url: 'original' }}"/>
    {% endif %}
    <meta property="og:site_name" content="{{ site.name }}"/>
    <link rel="canonical" href="{{ entry.url }}"/>

{% elsif page_scope == 'index' %}
    <!-- Content Page: Index -->
    <meta property="og:title" content="{{ page.title }} | {{ site.name }}"/>
    <meta name="description" content="{{ page.excerpt }}"/>
    <meta property="og:description" content="{{ page.excerpt }}"/>
    <meta property="og:type" content="article"/>
    <meta property="og:url" content="{{ page.url }}"/>
    {% if site.logo %}
        <meta property="og:image" content="{{ site.logo | asset_url : 'original' }}"/>
    {% endif %}
    <meta property="og:site_name" content="{{ site.name }}"/>
    <link rel="canonical" href="{{ page.url }}"/>

{% else %}
    <!-- Widget Page -->
    <meta property="og:title" content="{{ page.title }} - {{ site.name }}"/>
    <meta name="description" content="{{ page.excerpt }}"/>
    <meta property="og:description" content="{{ page.excerpt }}"/>
    <meta property="og:type" content="website"/>
    <meta property="og:url" content="{{page.url}}"/>
    {% if site.logo %}
        <meta property="og:image" content="{{ site.logo | asset_url : 'original' }}"/>
    {% endif %}
    <meta property="og:site_name" content="{{ site.name }}"/>
    <link rel="canonical" href="{{page.url}}"/>
{% endif %}

The snippet first adds the site meta tags and the page's custom meta tags. Then it uses the page_scope variable to generate the meta tags for each view:

  • show: The detail of an entry on a content page. It uses the entry's title, excerpt, and URL, with og:type set to article.
  • index: The entry list on a content page. It uses the page's title, excerpt, and URL, with og:type set to article.
  • In any other case, such as on widget pages, it uses the page's title, excerpt, and URL, with og:type set to website.

In all cases, it adds the canonical URL and, if the site has a logo, uses it as og:image.

You can customize this snippet and define what meta tags you want for specific URLs or types.

# SEO Examples

These examples show you how to use the SEO snippet to improve SEO in different cases:

# Specific meta tags for an Entry

Use this code to use specific meta tags when a user visits an entry:

...
{% if entry %}
<!-- Content SEO -->
<meta name="description" content="{{ entry.meta.excerpt }}" />
<meta property="og:title" content="{{ entry.meta.title }}" />
<meta property="og:url" content="{{ entry.meta.url }}" />
<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.meta.type_uid == 'posts' %}
<meta property="og:type" content="article" />
{% endif %}
{% if entry.meta.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 case, the posts and place entry types share the title, excerpt, and covers attributes and differ in the location field. In addition, it defines a different document type for each one.

# Category-specific meta tags on the Content Page

For specific meta tags when displaying entries from a category, copy the following code:

{% assign category_name = category_path | split: '/' | last | capitalize %}

{% case category_name %}
  {% when 'Category 1' %}
     {% assign category_description = 'This is the meta description for Category 1' %}
  {% when 'Categoría 2' %}
     {% assign category_description = 'This is the meta description for Category 2' %}
{% endcase %}

{% if category_path.size > 0 %}
<!-- Content Page: Index with category -->
<title> {{ category_name }} - {{ site.name }} </title>
<meta name="description" content="{{ category_description }}"/>
<meta property="og:title" content="{{ category_name }} - {{ site.name }}"/>
<meta property="og:type" content="website"/>
<meta property="og:url" content="{{ page.url }}/{{ category_path }}">
<meta property="og:image" content="https://d1dzq2r60kxox4.cloudfront.net/uploads/c82bdfea-3622-4c11-9a20-bea227cbdc60/original/og_image.jpg"/>
<meta property="og:site_name" content="{{ site.name }}"/>
<meta property="og:description" content="{{ category_description }}"/>
{% endif %}

In this code, a category_name variable is created that contains the name of the category taken from the URL. Then, an if on category_path.size > 0 adds the category metadata only when the URL includes one.

Liquid allows you to create dynamic content for your site. To learn more about Liquid and how to use Liquid Objects, visit Liquid Markup.