App Templates

Each app on your website has it's own templates and folder for templates. Generally, the template files would go into a folder within the templates folder that corresponds with the app instance name.

For example, let's say that the website has the blog app and its app instance key is "blog". The site also has the calendar app and its app instance key is "calendar".

If your theme was called "Custom" then this would be an example folder structure:

  • themes
    • custom
      • theme.json
      • templates
        • home.twig
        • one-column.twig
        • two-column.twig
        • blog
          • api-recent-posts.twig
          • archive.twig
          • categories.twig
          • category.twig
          • home.twig
          • post.twig
          • posts.twig
          • tag.twig
          • tags.twig
        • calendar
          • agenda.twig
          • event.twig
          • home.twig
          • search.twig
          • search-results.twig

All of the blog app templates are within the blog folder and the calendar app templates are within the calendar folder.

Every app page has it's own template that it uses. For example, the blog post detail page looks for the post.twig template within the blog folder.

However, not every app template has to correspond with an app page. The api-recent-posts.twig template above is for a Recent Posts API call. See the API templates section for more information.

Building app templates

There are to ways to build app templates.

  1. Build them as full templates where you set the full HTML for the page.
  2. Extend an existing template that has the full HTML for the page.

Build a full template

Building an app page like a full template is very similar to building a template for a regular page. The only difference is that instead of using the {{ _page.content() }} tag to output the content of the page, you simply use the appropriate tags for that app template to output the content.

Below is a really simple example of the blog post detail template.

<!doctype html>
<html>
    <head>
        <meta charset="utf-8">
        <title>{{ _page.title }}</title>
        <meta name="viewport" content="width=device-width, initial-scale=1">
        {{ _page.meta() }}
        <link type="text/css" rel="stylesheet" href="/layout/css/main.css">
        {{ _page.css() }}
        {{ _page.js('head') }}
        {{ _page.head() }}
    </head>
    <body>
        <div class="Container">
            <div class="Header">
                <a href="/"><img src="/layout/images/logo.png" width="200" height="100" alt="My Company"></a>
            </div>
            <div class="Nav">{{ _api.site.navigation.get.key('main') }}</div>
        </div>
        <div class="Content">
            <div class="Content-sidebar">
                {# Display the category links using the blog APIs #}
                {{ _app.blog.categories.template('api-category-templates') }}
            </div>
            <div class="Content-main">
                {# Display the main content for the blog post detail page #}
                <h1>{{ post.postTitle }}</h1>
                <p>By {{ post.author.fullName }} on {{ post.publishedOnDate }}</p>
                {{ post.content }}

                {# Post Comments #}
                {% if post.comments %}
                    <h2>Comments</h2>
                   {% for comment in post.comments %}
                   <p>
                       {{ comment.anchor.tag }}<a name="{{ comment.anchor.name }}">{{ comment.number }}</a><br>
                       {% if comment.title %}<b>{{ comment.title }}</b><br>{% endif %}
                       {% if comment.website %}
                           <a href="{{ comment.website }}" target="_blank">{{ comment.name }}</a><br>
                       {% else %}
                           {{ comment.name }}<br>
                       {% endif %}
                       {{ comment.createdOnDate }} at {{ comment.createdOnTime }}<br>
                       {{ comment.comments }}
                   </p>
                   {% endfor %}
                   <h2>Add Your comment</h2>
               {% else %}
                   <h2>Add the first comment</h2>
               {% endif %}
               {{ post.commentForm.content }}
            </div>
        </div>
        <div class="Footer">
            {{ _api.site.navigation.get.key('footer') }}
            <div class="Footer-copyright">Copyright {{ _core.date.year }} My Company</div>
        </div>
        <script src="/layout/js/main.js"></script>
        {{ _page.js() }}
    </body>
</html>

Extend an existing template

You can also extend an existing template. If the design of your site is fairly consistent then this is the recommended approach.

There are two important components necessary when extending an existing template.

  1. The parent template needs to use the {% block %} {% endblock %} tags.
  2. The child app template would use the {% extends %} tag to extend the primary template and the {% block %} {% endblock %} tags to overwrite the default content in the parent template.

Here is a simple example for the parent template. We'll use the same structure as the template above. In this case, the name of this template will be called "two-column.twig".

<!doctype html>
<html>
    <head>
        <meta charset="utf-8">
        <title>{{ _page.title }}</title>
        <meta name="viewport" content="width=device-width, initial-scale=1">
        {{ _page.meta() }}
        <link type="text/css" rel="stylesheet" href="/layout/css/main.css">
        {{ _page.css() }}
        {{ _page.js('head') }}
        {{ _page.head() }}
    </head>
    <body>
        <div class="Container">
            <div class="Header">
                <a href="/"><img src="/layout/images/logo.png" width="200" height="100" alt="My Company"></a>
            </div>
            <div class="Nav">{{ _api.site.navigation.get.key('main') }}</div>
        </div>
        <div class="Content">
            <div class="Content-sidebar">
                {% block sidebar %}
                    {{ _page.content('sidebar') }}
                {% endblock %}
            </div>
            <div class="Content-main">
                {% block main %}
                    {{ _page.content('main') }}
                {% endblock %}
            </div>
        </div>
        <div class="Footer">
            {{ _api.site.navigation.get.key('footer') }}
            <div class="Footer-copyright">Copyright {{ _core.date.year }} My Company</div>
        </div>
        <script src="/layout/js/main.js"></script>
        {{ _page.js() }}
    </body>
</html>

You'll notice in the above template that the {% block %} {% endblock %} tags are used around the {{ _page.content() }} tags. Your own templates can be more complicated and you can have other HTML and/or tags within the block tags as you need. 

It's also pure coincidence that the block names "sidebar" and "main" are the same as the content areas that are included within those blocks. That is not necessary. Your block names do not have to match the name of the content area that they represent. In fact, you don't have to have a content area to represent a block. The {% block %} {% endblock %} tags are simply placeholders that get overwritten by the child template.

Now for the blog post detail template that extends the main template. 

Remember that our parent template is called "two-column.twig". Since it's a main site template it's stored in the "templates" folder. 

Our blog post detail page template is going to be called "post.twig" since that's what's required by the system. It'll be stored in the "blog" folder. Below is a sample folder structure.

  • themes
    • custom
      • theme.json
      • templates
        • two-column.twig
        • blog
          • post.twig

Below is the blog post detail template.

{% extends "two-column" %}

{% block sidebar %}
    {# Display the category links using the blog APIs #}
    {{ _app.blog.categories.template('api-category-templates') }}
{% endblock %}

{% block main %}
    {# Display the main content for the blog post detail page #}
    <h1>{{ post.postTitle }}</h1>
    <p>By {{ post.author.fullName }} on {{ post.publishedOnDate }}</p>
    {{ post.content }}
    
    {# Post Comments #}
    {% if post.comments %}
        <h2>Comments</h2>
        {% for comment in post.comments %}
            <p>
                {{ comment.anchor.tag }}<a name="{{ comment.anchor.name }}">{{ comment.number }}</a><br>
                {% if comment.title %}<b>{{ comment.title }}</b><br>{% endif %}
                {% if comment.website %}
                    <a href="{{ comment.website }}" target="_blank">{{ comment.name }}</a><br>
                {% else %}
                    {{ comment.name }}<br>
                {% endif %}
                {{ comment.createdOnDate }} at {{ comment.createdOnTime }}<br>
                {{ comment.comments }}
            </p>
        {% endfor %}
        <h2>Add Your comment</h2>
    {% else %}
        <h2>Add the first comment</h2>
    {% endif %}
    {{ post.commentForm.content }}
{% endblock %}

Note the {% extends "two-column" %} tag. That is what tells the template engine to start with the template called "two-column.twig" within the "templates" folder in our theme folder. In this case we don't use the ".twig" extension when referencing the "two-column.twig" template. We could, but it's not necessary.

The {% block sidebar %} {% endblock %} and {% block main %} {% endblock %} tags are then use to wrap around the content that will replace those respective blocks in the parent template.

Reusing Code

Not every app template has to correspond with an actual app page. Sometimes you may want to share code between multiple templates. You are free to create as many templates within each app folder as you want. You can even include templates from other app folders if you want.

You can even go so far as to create custom folders that do not correspond to an app and include templates from there.

An example scenario would be to create a folder called "macros" within the theme folder to hold any macro template files.

API Templates

Most apps have APIs where you can display app content in different areas of your website. A simple example would be to display recent blog posts on the home page.

Typically the templates for the APIs are contained within the app's folder.  While app templates that correspond with app pages have to have specific pages, app API templates can be named whatever you want. It's recommended, however, to name them something that indicates what API call they are used for.

For example, you might call the template to output recent blog posts api-recent-posts.twig.