Layout Templates

The Layout Template directives allow Freemarker template authors to manage common layouts referenced by multiple pages.

A layout template is a Freemarker template that includes <@t.region> declarations for portions of the template that can be populated by client templates. A region may comprise any portion of the document, from a word or phrase to a large, complex document fragment. Regions are uniquely identified by name. If the same region is mentioned more than once in a layout template, the same content will be rendered everywhere the region is included.

A region declaration may include default content. This is a shorthand for adding content to the region in a client template using <@t.content> directives. Alternatively, the default content may also be used simply for documentation or instructions for users. When the default content is never meant to be rendered, the attribute, @renderDefault should be set to false.

Note these features of the following layout template:

  1. The region named "title" is included twice, once in the <head> and once in the <body> of the document.
  2. The regions named "pageHeader", "pageFooter", and "body" have default content, but only the content of "pageFooter" will be rendered, due to the attribute setting for @renderDefault.
  3. As with all Freemarker templates, the html markup will be emitted as-is. The <@t.region> elements will be replaced with the content supplied by client templates.
  4. Although this simple example does not use any other Freemarker directives or variables, in practice a layout template may include any valid Freemarker constructs.

page_layout.ftl

<html>
  <head>
    <title><@t.region name="title"/></title>
    <@t.region name="head"/>
  </head>
  <body>
    <@t.region name="pageHeader" renderDefault=false>
      PAGE HEADER GOES HERE
    </@t.region>

    <hr>

    <h1><@t.region name="title"/></h1>

    <@t.region name="body" renderDefault=false>
      BODY CONTENT GOES HERE
    </@t.region>

    <hr>

    <@t.region name="pageFooter" renderDefault=true>
      Powered by layout templates!
    </@t.region>
  </body>
</html>

Layout templates are invoked using the <@t.page> custom directive or the <@t.section> directive. Typically, a Freemarker template containing only a <@t.page> directive will be the root template for producing a portal page, as in the following example. Freemarker directives and other content may occur inside or outside the <@t.page> directive; however, within <@t.page>, any content not within a <@t.content>, <@t.prepend>, or <t.append> directive will be discarded.

A simplified description of <@t.page> processing is:

  1. The contents of the <@t.page> directive are processed.
    • Freemarker directives and bare content are processed per normal Freemarker processing. However, any rendered output is discarded.
    • <@t.content> and related directives are captured and stored for later rendering.
  2. The layout template is processed as a Freemarker template, replacing <@t.region> elements with the content specified by the client template.
    Note: If the layout template is (or contains) <@t.page> or <@t.section> directives, the process is recursive. This is explained in more detail below under "Layering Layout Templates."

Directives

Layout templates are implemented using the following directives:

<@t.region>
This directive declares a region to be populated in a layout template by client templates. Attributes:
@name
Required. The name of the region.
@renderDefault
Optional; default is true. Specifies whether the contents of the directive should be rendered if not replaced by a <@t.content> directive in the referencing page.
<@t.region.*>
As a shortcut, regions can be declared with their names as part of the directive name, e.g. <@t.region.body/> instead of <@t.region name="body"/>.
<@t.page>
Surrounds content whose overall structure is defined by a layout template. Attributes:
@layout
Required. A relative path to the layout template to use for the contents defined within this page. (The @master attribute may also be used, though this is deprecated.)
<@t.section>
Surrounds content whose overall structure is defined by a layout template. Attributes:
@layout
Required. A relative path to the layout template to use for the contents defined within this fragment. (The @master attribute may also be used, though this is deprecated.)
<@t.content>
This directive is used within <@t.page> and <@t.section> to define content to populate the regions declared by the referenced layout template. If used outside the context of <@t.page> or <@t.section>, causes an error. Attributes:
@region
Required. The name of the region to be populated.
@action
Optional. The allowable values are "replace", "prepend", or "append". The default is "replace". If there are multiple <@t.content> directives for the same region with an action of "replace", only the first will be executed. Multiple "append" actions will be inserted in the order in which they are declared; multiple "prepend" actions will be applied in reverse order.
defer
Optional boolean attribute. If true, render this content when the matching <@t.region> directive is processed. If false, render the contents immediately when the <@t.content> directive is evaluated. This could affect what variables and macros are in scope when the contents of the directive are evaluated.
<@t.prepend> and <@t.append>
These directives are synonyms for <@t.content>, but with the @region attribute set automatically. For example:
<@t.append region="header">
  More header!
</@t.append>
The above is the same as:
<@t.content region="header" action="append">
  More header!
</@t.content>
<@t.content.*>, <@t.prepend.*>, and <@t.append.*>
These directives are synonyms for their base versions, with the @region attribute included in the directive name instead of as an attribute. For example:
<@t.append.header>
  More header!
</@t.append.header>
<@t.content.body>
  This is body content
</@t.content.body>
This is synonymous with:
<@t.content action="append" region="header">
  More header!
</@t.content>
<@t.content region="body">
  This is body content
</@t.content>

Example Page with a Layout Template

page.ftl

Considering the following page, which contains some content to be rendered using the overall layout specified in another file:

<@t.page layout="relative/path/to/page_layout.ftl">
  <@t.content region="title">Page Title</@t.content>

  <@t.content region="head">
    <link rel="stylesheet" href="style.css">
  </@t.content>

  <@t.content region="pageHeader">
    Overriding page header.
  </@t.content>

  <#-- Uses the simplified, collapse model -->
  <@t.content.body>
    <h2>Page Contents</h2>
    <p>This is where the body goes.</p>
  </@t.content.body>

  <@t.content region="pageFooter" action="prepend">
    Extra, PREPENDED footer for this page.
  </@t.content>

  <#-- Uses the simplified, collapse model -->
  <@t.append.pageFooter>
    Extra, APPENDED footer for this page.
  </@t.append.pageFooter>
</@t.page>

Layouts for Page Sections

Layout templates may also be used for document fragments. Syntactically these fragment layout templates are the same as a page layout template, but will have a top-level element representing some type of HTML division element. Like page layout templates, they will contain <@t.region> directives to place and name regions of replaceable content.

section_layout.ftl

<div>
  <h1><@t.region name="section-title"/></h1>
  <@t.region name="section-contents"/>
</div>

page_with_sections.ftl

<html>
  <head>
    <title>Sections with Common Layout</title>
  </head>
  <body>
    <@t.section layout="relative/path/to/section_layout.ftl">
      <@t.content region="section-title">
        <#-- generate first section title -->
      </@t.content>
      <@t.content region="section-contents">
        <#-- generate first section contents -->
      </@t.content/>
    </@t.section>
    <@t.section layout="relative/path/to/section_layout.ftl">
      <@t.content region="section-title">
        <#-- generate 2nd section title -->
      </@t.content>
      <@t.content region="section-contents">
        <#-- generate 2nd section contents -->
      </@t.content/>
    </@t.section>
  </body>
</html>

Layering Layout Templates

A <@t.page> can reference a @layout which, itself, specifies a <@t.page> directive. Intermediate <@t.page> templates may declare their own <@t.region> directives. Such pages can reference any of the regions at any level of the referenced pages, including the regions in the ultimate layout template.

If a given region is replaced at multiple levels, the first replacing <@t.content> for that region from the outermost page will be used. Prepending and appending content will be applied from all levels, with the outermost page contents coming first for prepending and last for appending.

outerPage.ftl

<@t.page layout="innerPage.ftl">
  <@t.content region="innerPageContent">
    Content from outerPage.
  </@t.content>

  <@t.content region="layoutFooter">
    Footer from outerPage.
  </@t.content>
</@t.page>

innerPage.ftl

<@t.page layout="layout.ftl">
  <@t.content region="layoutContent">
    Content from innerPage.
    <@t.region name="innerPageContent"/>
  </@t.content>

  <@t.content region="layoutFooter">
    This will be overwritten by outerPage.ftl
  </@t.content>
</@t.page>

layout.ftl

<@t.region name="layoutContent"/>
<@t.region name="layoutFooter"/>

Output

Content from innerPage.
Content from outerPage.
Footer from outerPage.

The layout template directives are available in version 4.1 and later.