This tutorial introduces the Magnolia templating mechanism. It covers creating your first page template, rendering content from the repository and creating a dialog for content entry. You also learn how a page is composed of areas and components.

What is templating?

The goal of templating is to render something. Rendering makes the content stored in the content management system visible and accessible to site visitors. In Magnolia you can render a page, a specific area of the page, or a component that displays editable content or performs a function.

Structure

Template gives the rendered element structure. Structure is crucial for presenting content in the correct order and for building a page layout. An example of a simple structure is headers and footers on a page. Header is at the top, footer at the bottom, and content that varies from page to page is in the middle. Templates make it possible to build such structure. And you can be confident that it remains the same across the website.

Control

Templates also allow you to control what is rendered. You can define what components and how many are allowed in a particular area of the page. Without a template it would be difficult to keep the site design consistent.

Think of a typical corporate website. It has carefully designed branding and corporate identity: colors, fonts, images and page layout all contribute to making every page look and feel consistent and part of the whole. You want to safeguard that identity by protecting elements that should not be editable. A template allows you to define which parts of the page are editable and which are not. For example, an area template allows you to define components that are allowed in that area. If only images are allowed, there is no way for editors to introduce text into the area.

Templates

Magnolia provides three types of templates:

  • Page is the highest level template. It renders a page. Pages are the building blocks of a site hierarchy. They create a tree hierarchy of parent pages and child pages that you can see in Magnolia AdminCentral and visualize to site visitors in a sitemap and in navigation. Each part of a URI is also a page. For example, example.com/products/bicycles would have at least three pages: home page, products section page, and a bicycles page.
  • Area is the next level down. Pages consist of areas which can consist of further areas or components. Areas have two purposes: they structure the page and control what components editors can place inside the area. This makes area the most powerful template. It ensures consistency across the site. Areas also provide repeatability. An area template typically loops through the components inside it, rendering the components one by one. Most areas are rendered with containing div elements in the generated HTML so you can control their layout on the page with CSS.
  • Component is the smallest block of content that editors can edit, delete and move as a single unit. Think of a component as content that belongs together. At its simplest, a component may be a heading and some text that belong together. However, it can contain almost anything: text and a related image, list of links, teased content from another page and so on.

Properties

All templates need the following common properties:

  • Type tells the system which renderer to use. Renderer is a program that understands the syntax of the template script and generates HTML output from it. (To be exact, it can generate any kind of output but HTML is the most common.) Think of the renderer as an application that opens a particular type of file. Your computer knows that a .dot file should be opened in Microsoft Word. Similarly, the type property tells Magnolia that a ftl script should be rendered with a Freemarker renderer and a jsp script with a JSP renderer.
  • Script is written in FreeMarker, JSP or a custom templating language. The script instructs the renderer where to place the content and also contains placeholders for content attributes such as headings and images.
  • Dialog is an optional property. Editors use dialogs to enter and edit content. Most templates have a dialog.

These are not the only properties templates can have. But they are the necessary ones.

This tutorial relies on the basic templating framework included in all versions of Magnolia. There is also a better alternative: Standard Templating Kit (STK) is a set of best practice templates for common use cases. It is an out-of-the-box solution designed to speed up the development. After going through this tutorial and understanding how the templating mechanism works, try the STK. You can adapt and modify STK templates to suit your needs.

Pages

Let's start the tutorial with the highest level template which is page. You need three things to create a page template:

  • Page script renders the content.
  • Page definition makes the page template available to the system.
  • Page dialog allows editors to edit content.

Creating a page script

Page script renders the content. The script is written in FreeMarker, JSP or a custom templating language. The script instructs the renderer where to place the content on the page and also contains placeholders for content attributes such as headings and images.

In this exercise you will save the script file in the web application's directory on the file system. This is not the only possible place. Freemarker template scripts can also be loaded from the templates repository or from inside your module's .jar file. JSP templates can only be loaded from the file system since they require pre-compiling by the server before they can be rendered.

To create a page script:

  1. On your computer, browse to the Magnolia webapp's templates folder. You can find it in /<CATALINA_HOME>/webapps/<contextPath>/templates, typically this is /apache-tomcat/webapps/magnoliaAuthor/templates.
  2. Create a new text file helloWorld.ftl.
  3. Open the file in a text editor and paste the following script in it.

Freemarker:

<html>
   <head>
      <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
      <title>Page Title</title>
   </head>
   <body>
      Hello World!
   </body>
</html>

JSP:

<html>
   <head>
      <title>Page Title</title>
   </head>
   <body>
      Hello World!
   </body>
</html>

As you can see, declaring the contentType is unnecessary in JSP. The script is served from the /templates folder within the webapp, not from /docroot, so the content type is established by the servlet. If you use JSP, set the renderType property in the template definition to jsp and templateScript to /templates/helloWorld.jsp.

The script is very simple and merely displays the text "Hello World!" on the page. Your file system should look like this.

Creating a page definition

A page definition assigns the page template a name and makes it available to the system. The name is used to reference the template. The page definition also tells the system which dialog is used to edit page properties and which script is used to render the content.

In this tutorial you will create place the page definition in the Templating module. You can find it in Configuration > /modules/templating. This is the same module that provides the basic templating functionality.

To create a page definition:

  1. Go to Configuration >/modules/templating.
  2. Open the templates folder.
  3. Under templates, create a new child folder pages. Page definitions are always created in a folder named pages.
  4. Under pages, create a new content node helloWorld. This is the page definition.
  5. Under helloWorld, create the following data nodes:
    • renderType defines which renderer is used to render the template. Options are freemarker, jsp and stk. Set value to freemarker. See About scripting languages.
    • templateScript is a path to the corresponding page script. The script renders the content. Set value to /templates/helloWorld.ftl.
    • title is the title of the template. Editors see it in the Template dropdown when they assign the page template to an actual page on the site. Set value to Hello World.
    • visible makes the page template available to editors. Set value to true.

Your definitions do not have to reside in the Templating module. At an advanced level, the best practice is to create your own complete module. To place the configuration into your own module you will need to have a module descriptor that registers the module. In addition you will need a task that bootstraps configurations such as page definitions. This enables you to customize templates independent of other modules.

About scripting languages

Freemarker is the most common templating language used with Magnolia. JSP is also popular. You can use both languages on the same site; Freemarker for some pages and JSP for others. You can even use JSP for a page and Freemarker for areas on the page (or vice versa) as long as you define a renderType for the area separately. Otherwise the area will inherit the page's renderType.

FreeMarker templates can be loaded from the webapp's classpath, the repository or the file system. JSP templates can be loaded only from the file system since they require pre-compiling by the server before they can be rendered. In this tutorial you find code examples in FreeMarker and JSP. Choose your code of preference.

It does not really matter where you put your template scripts as long as they are within the webapps folder of your Magnolia instance. The path to the script file is in the template definition. This is how the system finds the script. By default, the templates folder is in /<CATALINA_HOME>/webapps/<contextPath>/templates. It is generally a good idea to organize your templates into folders.

To keep things simple, this tutorial does not deal with Cascading Style Sheets (CSS). Your template script can reference a CSS file if you wish. For example, to use the samples.css file contained in the Templating Samples module from the file system, add the following line in the <head> section of the script.

<link rel="stylesheet" type="text/css"
href="${pageContext.request.contextPath}/docroot/samples/samples.css"/>

CSS files can also be loaded from the repository. You can find samples in Templating Kit > Resources.

Assigning the page template to a page

Now the page template is defined so the system can find it and editors can assign it to pages. You also have a page script so the system knows how to render content.

To assign the page template to a page:

  1. Go to Website and create a new page. Name it hello.
  2. Double-click the Template column and select the Hello World page template.
  3. Open the page.

The result may seem a little disappointing but this is a very basic page!

Now that basic infrastructure is in place, you can start rendering content from the repository and creating dialogs for content entry.

Rendering content from the repository

To learn how to deal with dynamic content, assign the page a title. The title is stored in a property named title in the repository. You can render it in the browser title bar and on the page.

Assigning a page title

To assign a title to the page:

  1. Go to Website and navigate to your page.
  2. Double-click the Title column and type "Hello Magnolia World" in the box.

Page title is different from template title. Page title ("Hello Magnolia World") is displayed to visitors on the page. Template title ("Hello World") is an internal title of the page template which you defined in the page definition earlier; it is displayed to editors in the Template dropdown in AdminCentral.

The page title is stored with page content and other page properties in the website repository. You can examine these properties with the JCR Browser . Go to Tools > JCR Browser (Website). Pages, and nodes in general, can have an arbitrary number of properties.

Referencing page title in page script

Templating support objects are available to your script implicitly. This means that you can access content and properties stored in the repository using tags in the script. The content object represents the current content node, in this case the Hello page. Page title is available through this object using the dot notation: content.title. Properties are exposed as a map like cms:setNode

To display the page title on the page, edit the script.

FreeMarker:

<html>
   <head>
      <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
      <title>${content.title!}</title>
   </head>
   <body>
      <h1>${content.title!}</h1>
   </body>
</html>

JSP:

<html>
   <head>
      <title>${content.title}</title>
   </head>
   <body>
      <h1>${content.title}</h1>
   </body>
</html>

Now, refresh the Hello page. The page title "Hello Magnolia World" is displayed in the window title and in an h1 element on the page.

As you create new pages based on the Hello World template, the window title and h1 element will change dynamically to display each page's unique title.

The exclamation mark after content.title is the Freemarker default value operator. On the right hand side of the exclamation mark you specify a default value that is substituted if the title property does not have an actual value. This prevents the script from erroring if it encounters a null value. If you leave the substitute out, the exclamation mark alone sets the value to an empty string.

Making the page editable

Each page element has a toolbar that editors use to edit the element's content and move it on the page. The page itself also has a toolbar that allows editors to edit page specific properties such as the title without leaving the page.

Toolbars are added to editable elements automatically. The Tag libraries is a collection of tags that render common elements such as toolbars. Use the cms.init tag to initialize the tag library.

  1. Edit the page script.
  2. Initialize the CMS tag library by adding a cms.init tag in the head element.

FreeMarker:

<html>
   <head>
      [@cms.init /]
      <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
      <title>${content.title!}</title>
   </head>
   <body>
      <h1>${content.title!}</h1>
      <p>My template content</p>
   </body>
</html>

JSP:

<%@ taglib prefix="cms" uri="http://magnolia-cms.com/taglib/templating-components/cms" %> 
<html>
   <head>
      <cms:init/>
      <title>${content.title}</title>
   </head>
   <body>
      <h1>${content.title}</h1>
      <p>My template content</p>
   </body>
</html>

Refresh the page.

The page toolbar is a green bar at the top. It has three buttons:

  • Preview removes all toolbars from the page and displays it exactly as a visitor would see the page on the public instance.
  • AdminCentral locates the page node in AdminCentral
  • Properties edits page-level properties such as title and metadata. If you click this button now you get an error because you have not defined a dialog for editing page properties yet. That comes next.

Defining a page properties dialog

The authoring system uses dialogs to edit content. A dialog is an HTML form with input fields. Editors type content into the fields and the dialog saves it in the repository. It is an agile mechanism in the sense that you can create your own dialogs or customize the standard dialogs that ship with the system.

Like template definitions, dialogs are defined with configuration. The page properties dialog is a very common dialog. You will find it on every STK page for example. It allows editors to edit the page title, navigation title and page metadata without leaving the page.

You could reuse an existing page properties dialog. However, the dialog used in STK pages is not appropriate for the Hello World page because our page will not have navigation or metadata, to keep things simple. Those dialog fields do not make sense in this example. Create a dialog that allows you to edit the page title and enter some page content instead.

Dialogs consist of tabs, which again consist of controls. Each dialog needs to have at least one tab.

To create a page properties dialog:

  1. Go to Configuration >/modules/templating.
  2. Create a new folder dialogs.
  3. Under dialogs, create a content node pageProperties. This is the dialog definition.
  4. Under pageProperties, create a content node tabText. This is the first (and only) tab in the dialog.
  5. Under tabText, create a data node controlType and set its value to tab.
  6. Under tabText, create a data node label and set its value to Page Properties.
  7. Under tabText, create two content nodes: title and text. These are the input fields.
  8. Under title, create two data nodes:
    • controlType and set value to edit. This is a basic text box. For other types see Controls.
    • label and set value to Page title.
  9. Under text, create three data nodes:
    • controlType and set value to edit.
    • label and set value to Page text.
    • rows and set value to 5.

Referencing the dialog from the page definition

Reference the page properties dialog from the page definition so that the system knows which dialog to open when the Properties button is clicked.

  1. Go to Configuration > /modules/templating/templates/pages/helloWorld.
  2. Create a new data node dialog and set its value to templating:pageProperties.

The value of the dialog node has two parts. The first part before the colon (:) is the name of the module folder where the dialog definition resides. The second part is a relative path.

<module name>:<relative path to dialog>

In this case the dialog is defined in the Templating module so the first part is templating. The relative path always starts from inside the dialogs folder. Since the pageProperties dialog definition is right below the dialogs folder, the name of the content node is enough.

templating:pageProperties

Entering page content

Refresh the Hello page and click Properties. The dialog is displayed.

The Page title box already has a value "Hello Magnolia World". The system read the value from the title property in the repository. This is the same value you entered in AdminCentral earlier. Controls store their values in properties named after the control: a control named title stores values in a title property, a control named text stores values in a text property and so on.

For a complete list of properties available in dialog and control definitions, see Dialogs and Controls.

Type some text in the Page text box and save the dialog. The text is stored in a new text property under the page. You can verify this with the JCR Browser.

Rendering page content

To render the text you typed:

  1. Edit the page script.
  2. Add paragraph tags <p> and </p> in the body.
  3. Inside the paragraph tags, read the value of the text property from the content object using ${content.text!}.
  4. Save the script and refresh the Hello page.

Freemarker:

<html>
   <head>
      [@cms.init /]
      <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
      <title>${content.title!}</title>
   </head>
   <body>
      <h1>${content.title!}</h1>
      <p>${content.text!}</p>
   </body>
</html>

JSP:

<%@ taglib prefix="cms" uri="http://magnolia-cms.com/taglib/templating-components/cms" %>
<html>
    <head>
        <cms:init/>
        <title>${content.title}!</title>
    </head>
    <body>
        <h1>${content.title}</h1>
        <p>${content.text}</p>
    </body>
</html>

The text you typed in the Page text box is now displayed on the page.

Areas

Pages are organized into smaller elements called areas. Areas are controllable blocks, rendered as div elements in the generated HTML. Areas make it possible to have exact control over the page layout and over what content can be placed inside the area.

There are three types of areas. The type defines how many components editors can add inside the area.

  • single area can contain one component
  • list can contain many components
  • noComponent cannot contain any editor-added components. The system creates the components automatically.

You can name your areas as you wish but some conventions exist. The main area is typically where primary content resides. For example, on a news page the actual news story would be in the main area. Other page components such as headers, footers, and navigation would reside in their own areas.

Creating an area definition

Areas can be defined globally for the whole site in the site definition or per page template in the template definition.

To create an area definition:

  1. Go to Configuration >/modules/templating/templates/pages/helloWorld.
  2. Under helloWorld, create a content node areas.
  3. Under areas, create a content node main.
  4. Under main, create two data nodes:
    • type and set value to list. This will create a list type area where you can add many components.
    • templateScript and set value to /templates/areas/mainArea.ftl. This is a path to the area script. You will write it in a moment.

Making components available in the area

Each area can define what components are available inside it. You do this by creating a list of components that editors can add into the area. Availability is an important control mechanism. It allows you to control page consistency at a very low level. When you control what components editors can add and where, you ensure that information architecture on the page does not get out of hand.

The system creates the component selector dialog automatically. When an editor selects one component that component's own dialog is displayed.

In this example we make a text block component available in the main area. The component will be configured in a moment.

To make components available in the area:

  1. Go to Configuration >/modules/templating/templates/pages/helloWorld/areas/main.
  2. Under main, create a content node availableComponents.
  3. Under availableComponents, create a content node textBlock.
  4. Under textBlock, create a data node id and set its value to templating:components/textBlock.

The id property works the same way the dialog property you saw above. It locates the component definition. The first part before the colon (:) is the name of the module folder where the component definition resides. The second part is a relative path.

<module name>:<relative path to component>

In this case the component will be defined in the Templating module so the first part is templating. The relative path starts with a components folder, followed by a path to the component content node. Since the textBlock component definition will be right under the components folder, the path is components/textBlock.

templating:components/textBlock

Rendering the area in the page script

To render the main area in the page script:

  1. Edit the page script.
  2. Add the cms.area tag in the body element.
  3. Provide the name of the area that should be rendered in the name attribute. In this case the area is main.

Freemarker:

<html>
   <head>
      [@cms.init /]
      <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
      <title>${content.title!}</title>
   </head>
   <body>
      <h1>${content.title!}</h1>
      <p>${content.text!}</p>
      [@cms.area name="main" /]
   </body>
</html>

JSP:

<%@ taglib prefix="cms" uri="http://magnolia-cms.com/taglib/templating-components/cms" %>
<html>
    <head>
        <cms:init/>
        <title>${content.title}!</title>
    </head>
    <body>
        <h1>${content.title}</h1>
        <p>${content.text}</p>
        <cms:area name="main" />
    </body>
</html>

This instructs the script to render the main area. There is nothing to render yet so we need an area script.

Creating an area script

Like pages, areas have their own scripts. The primary purpose of an area script is to render any components inside the area.

  1. On your computer, browse to /<CATALINA_HOME>/webapps/<contextPath>/templates, typically this is /apache-tomcat/webapps/magnoliaAuthor/templates.
  2. Create a new folder areas.
  3. In areas, create a new text file mainArea.ftl and paste the following script in it.

Freemarker:

<div id="main">
[#list components as component ]
   [@cms.component content=component /]
[/#list]
</div>

JSP:

<%@ taglib prefix="cms" uri="http://magnolia-cms.com/taglib/templating-components/cms" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

<div id="main">
    <c:forEach items="${components}" var="component">
        <cms:component content="${component}" />
    </c:forEach>
</div>

The script includes two new tags:

  • list is a Freemarker directive that evaluates a collection. In this case it is a collection of components inside the area. Any operations defined within the list are executed for each collection item.
  • cms.component renders content. The content attribute determines what that content is, in this case a component inside the area.

If you just want to render components inside the area, you don't need an area script! An area definition alone is adequate. However, if you want to render any custom HTML like the div element in this example, then write an area script.

Save the area script and refresh the Hello page. The page now has a main area. The area toolbar shows the name of the area. Areas also have an end marker, a narrower green bar at the bottom. It helps you see the dimensions of the area. In the middle is a gray placeholder for components. You cannot add the text block component into the area yet because we have not defined it yet. Let's do that next.

Components

 Component is the smallest block of content that editors can edit, delete and move as a single unit. Think of a component as content that belongs together. When you look at a typical Magnolia page, you can identify components easily with that rule of thumb. At its simplest, a component may be just a heading and some text that belong together.

Each component can be used on several pages and in several areas. Within an area, editors choose the components to add from a list. The list is limited to display only components that are available in that particular area as defined in the availableComponents node.

Creating a component definition

The textBlock component is a very simple example. It renders any text entered by the editor.

To create a component definition:

  1. Go to Configuration >/modules/templating/templates.
  2. Create a new folder components.
  3. Under components, create a content node textBlock.
  4. Under textBlock, create the following data nodes:
    • dialog and set value to templating:textBlock.
    • renderType and set value to freemarker.
    • templateScript and set value to /templates/components/textBlock.ftl. This a path to the component script.
    • title and set value to Text Block. The title is displayed to editors when they select from a list of components to add.

Creating a component script

A component script renders the content of the component. For our example component the content is just some text. The script reads the text from the repository and renders it.

  1. On your computer, browse to /<CATALINA_HOME>/webapps/<contextPath>/templates, typically this is /apache-tomcat/webapps/magnoliaAuthor/templates.
  2. Create a new folder components.
  3. In components, create a new text file textBlock.ftl.
  4. Open the file in a text editor and copy the following script to it.

Freemarker:

<p>
    ${content.text!}
</p>

JSP:

<p>
    ${content.text}
</p>

The script renders the value of the text property from the current content object. In this case the content object is not the Hello page node but the component node.

Creating a component dialog

A component dialog allows editors to edit the content of the component. You can find many examples of component dialogs in the Standard Templating Kit. Look in Templating Kit > Dialog Definitions > /components.

To create a component dialog:

  1. Go to Configuration >/modules/templating/dialogs.
  2. Under dialogs, create a content node textBlock.
  3. Under textBlock, create a content node tabText. This it first (and only) tab in the dialog. Remember: you need to define at least one tab for every dialog.
  4. Under tabText, create two data nodes:
    • controlType and set value to tab.
    • label and set value to Text Block.
  5. Under tabText, create a content node text. This the text box control where the actual content entry happens.
  6. Under text, create three data nodes:
    • controlType and set value to edit.
    • label and set value to Component text.
    • rows and set value to 5.

Adding a component on the page

Now you have all that is required to add a component on the page: the component is defined, has a script and a dialog, and it is available in the main area.

To add a component on the page:

  1. Reload the Hello page.
  2. Click the main area placeholder.
  3. Click the plus button in the toolbar to add a component.
  4. Select the Text Block component and click OK.
  5. Type some text into the Component text box.
  6. Save.

The component is rendered on the page.

Components also have toolbars. Click the containing area toolbar to see them.

Since the main area is of type list, you can add multiple components to it. Add a few more more and change their order by dragging the component toolbar.

Component content is stored in the website repository. Each component has a content node and properties under it. You can view them in the JCR Browser.

Summary

This introduction explained the basics of the templating mechanism.

  • Pages, areas and components are defined with configuration.
  • Their definitions are very similar. Each must have a type, a script and optionally a dialog.
  • Area is the most powerful template. It allows you to impose structure and control over content.
  • Component availability defines what components editors can add into an area.
  • Content is entered using dialogs and stored in the repository.
  • A script renders the content. Scripts can be written in Freemarker, JSP or a custom language.
  • Pages, areas and components are edited and moved with toolbars.

What next?

Activate everything to public instance

A typical Magnolia setup consists of an author instance and one or more public instances. Until now you have been working on the author instance. Activate everything you created to the public instance.

  • Activate the Hello page.
  • Activate all configuration under the templating module.
  • Copy the template scripts and their folders to the magnoliaPublic webapp.

Open the Hello page on the public instance and check that everything works correctly. Content should not be editable but it should be rendered in exactly the same way when you click the Preview button on the author instance.

Try STK and Samples

Install the  Standard Templating Kit (STK) and Templating Samples modules. You might already have the STK. Go to Magnolia Store > Installed modules to check.

STK provides a complete best-practice framework with lots of templates, dialogs and scripts. The best way to learn is by example. Look under Templating Kit in AdminCentral. STK scripts are stored in the repository, not on the file system, so you can browse and edit them in Templating Kit > Resources.

 

#trackbackRdf ($trackbackUtils.getContentIdentifier($page) $page.title $trackbackUtils.getPingUrl($page))