Magnolia 5.4 reached end of life on November 15, 2018. This branch is no longer supported, see End-of-life policy.
In this beginner tutorial you create a simple template in Magnolia. You learn how to get content from the repository and display it on a page.
java -version
in a terminal or command prompt. If the system reports a version number, Java is installed on your computer.$ java -version java version "1.8.0_51" Java(TM) SE Runtime Environment (build 1.8.0_51-b16)
If you don't have Java, install it:
Download a Magnolia bundle or use the Magnolia CLI.
Extract the zip to your computer.
magnolia-x.y/ ├── add-ons/ └── apache-tomcat-x.y/ ├── bin/ ├── conf/ ├── lib/ ├── logs/ ├── temp/ └── webapps/ ├── ROOT/ ├── magnoliaAuthor/ └── magnoliaPublic/
Where to extract:
Magnolia Community Edition software is distributed free-of-charge and without any warranty under the terms of the GNU General Public License (version 3), a license that permits you to redistribute and modify the software under certain terms and conditions. It is important that you read the license to understand your rights and obligations.
If you are familiar with Magnolia's CLI use the jumpstart
command to download, unpack and pre-configure the Magnolia Community Demo bundle. The bundle includes the Travel Demo and a Tomcat server.
cd
to magnolia-x.y/apache-tomcat-x.y/bin. If you installed the Magnolia bundle with Magnolia CLI jumpstart, cd
to apache-tomcat/bin.Execute the start command:
./magnolia_control.sh start
Note: If you get an error due to a low "max open files" limit, try executing the command with the --ignore-open-files-limit
option:
./magnolia_control.sh start --ignore-open-files-limit
Detailed instructions:
http://localhost:8080
Magnolia installs its modules. When the installation is complete on the author and public instances, click Start up Magnolia on both.
http://localhost:8080/magnoliaAuthor/.magnolia/admincentral
and sign in as:superuser
superuser
The app launcher is displayed.
superuser
is a system administrator account that has permissions to do everything. It is useful for testing.
Having problems? See Known issues.
Create a module for your templates.
Create the structure hello-magnolia (including subfolders) under apache-tomcat/webapps/magnoliaAuthor
:
webapps/ └── magnoliaAuthor/ └── hello-magnolia/ ├── dialogs/ ├── webresources/ └── templates/
This is a typical Magnolia module structure where hello-magnolia
is the name of your module.
é
, à
, ç
, ä
, ö
, ü
or special characters such as slashes /
, \
and so on. The name must match the regular expression [a-zA-Z0-9-_]
.Magnolia scans directories inside the web application, in this case inside magnoliaAuthor
, and registers your module automatically. It detects new and modified templates, dialogs and (web)resources.
Download the zip and extract it to
apache-tomcat/webapps/magnoliaAuthor/hello-magnolia
.
Remove any version number from the extracted folder name. It should be just
hello-magnolia
.
The complete example does not include the intermediate build stages as below, only the final module structure. You can use the template on a page right away.
The first template we create is a page template.
Beware invalid characters
It is common to start with a static HTML document. You can view the static HTML document directly in your browser. It does not need to be processed by Magnolia.
Copy the HTML code below and save it to a new file hello-magnolia/templates/pages/hello.html
<!DOCTYPE html> <html> <head> <title>Hello :-)</title> <link rel="stylesheet" href="//fonts.googleapis.com/css?family=Raleway:200" type="text/css"> <link rel="stylesheet" href="../../webresources/css/style.css"> </head> <body> <div class="container"> <header> <h1>Hello Magnolia :-)</h1> <p>We will use this page as a starting page to create our first page template.</p> </header> </div> </body> </html>
Copy the CSS below and save it to a new file hello-magnolia/webresources/css/style.css
. We reference this stylesheet in the HTML page and the template script (later on).
Every Magnolia template needs a definition and a script. A template definition gives the template a name and makes it available to the system. It also tells the system which script renders the content. Here we use YAML to create template definition.
Copy the template definition code below.
templateScript: /hello-magnolia/templates/pages/hello.ftl renderType: freemarker visible: true title: Hello
Save it to a new file hello-magnolia/templates/pages/hello.yaml
.
hello-magnolia/ ├── dialogs/ ├── webresources/ │ └── css/ │ └── style.css └── templates/ └── pages/ ├── hello.html └── hello.yaml
A template script contains the rendering instructions. A script can be completely static but it usually includes editable content fragments or other dynamically assigned values provided by Templating functions (for instance cmsfn to fetch content) or Rendering context objects.
hello.ftl
. The extension .ftl
turns it into a FreeMarker script.${ctx.contextPath}
. This template directive ensures that the path is correct on both author and public instance.${def.name}
. (def is a context attribute, see Rendering context objects).<!DOCTYPE html> <html> <head> <title>Hello Magnolia :-)</title> <link rel="stylesheet" href="//fonts.googleapis.com/css?family=Raleway:200" type="text/css"> <link rel="stylesheet" href="${ctx.contextPath}/.resources/hello-magnolia/webresources/css/style.css"> </head> <body> <div class="container"> <header> <h1>Hello Magnolia :-)</h1> <p>This page has been created with the template named ${def.name}</p> </header> </div> </body> </html>
Your file system should now look like this:
hello-magnolia/ ├── dialogs/ ├── webresources/ │ └── css/ │ └── style.css └── templates/ └── pages/ ├── hello.ftl └── hello.yaml
As of version 5.4.7 of Magnolia, a page template such as this one will be instantly available to the editor. To be able to use the template in a page on pre-5.4.7 version of Magnolia, you must add the template to the list of available templates in the site.
templates/availability/templates
.hello
.id
with the value hello-magnolia:pages/hello
to the node.Hello
template you just created.Congratulations! You created your first Magnolia template. You turned a static HTML document into a processed FreeMarker template.
Magnolia 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 CMS.
A dialog definition defines the editable properties of the template.
Copy the dialog definition below and save it to a new file hello-magnolia/dialogs/pages/hello.yaml
.
form: tabs: - name: tabText label: Texts fields: - name: title class: info.magnolia.ui.form.field.definition.TextFieldDefinition label: Title - name: introText class: info.magnolia.ui.form.field.definition.TextFieldDefinition label: Introduction text actions: commit: class: info.magnolia.ui.admincentral.dialog.action.SaveDialogActionDefinition cancel: class: info.magnolia.ui.admincentral.dialog.action.CancelDialogActionDefinition
The dialog has two fields:
title
: Edits the page title using a simple text field. We will render the content in the <title>
and <h1>
elements on the page.introText
: Edits an introduction paragraph. We will render the content in the first <p>
element on the page.dialog
property on line 5. The value is an id to the dialog definition. The id follows the pattern <module name>:<relative path within the dialogs folder>
.templateScript: /hello-magnolia/templates/pages/hello.ftl renderType: freemarker visible: true title: Hello Magnolia dialog: hello-magnolia:pages/hello
Edit the template script to render the content entered in the dialog. The content
variable represents the root node of the content element, in this case the page.
[#assign title = content.title!"Hello Magnolia :-)"] <!DOCTYPE html> <html> <head> <title>${title}</title> <link rel="stylesheet" href="//fonts.googleapis.com/css?family=Raleway:200" type="text/css"> <link rel="stylesheet" href="${ctx.contextPath}/.resources/hello-magnolia/webresources/css/style.css"> [@cms.page /] </head> <body> <div class="container"> <header> <h1>${title}</h1> [#if content.introText?has_content]<p>${content.introText}</p>[/#if] </header> </div> </body> </html>
Changes:
content.title
retrieves the title of the page from the CMS and assigns it to a FreeMarker variable title
. The variable allows us to reuse the content in the <title>
and <h1>
elements. The FreeMarker expression also provides a default value "Hello Magnolia" we can fall back on if the page has no title.[@cms.page /]
adds toolbars and makes the page properties dialog available.${content.introText}
renders the introduction paragraph. We wrap it in an if
directive which checks that the content exists in the CMS. Your file system should now look like this:
hello-magnolia/ ├── dialogs/ │ └── pages/ │ └── hello.yaml ├── webresources/ │ └── css/ │ └── style.css └── templates/ └── pages/ ├── hello.ftl └── hello.yaml
To use the template on a page:
In Magnolia, refresh the page.
Click Edit page properties.
Edit the page title and introduction paragraph.
Save.
You now have an editable page. Authors can enter content in the CMS and render it on the page.
Areas and components help to modularize a project and structure pages. Once defined, you can reuse areas and components in many page templates.
Let's create an area with one component to add quotations. At the end it should look like this:
Typically you organize pages into smaller elements called areas. Areas allow you to control the page layout and restrict what content editors can place inside the area. Areas are rendered as div
elements in the HTML so you can style them with CSS. Areas also provide repeatability. An area template typically loops through the components inside it, rendering them one by one.
A 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 is just a heading and some text that go together.
Areas are defined in the page template definition. You don't need to create a separate area definition file.
Edit the hello-magnolia/templates/pages/hello.yaml
template definition and add the main
area:
templateScript: /hello-magnolia/templates/pages/hello.ftl renderType: freemarker visible: true title: Hello template dialog: hello-magnolia:pages/hello areas: main: renderType: freemarker availableComponents: quotation: id: hello-magnolia:components/quotation
You don't need to create an area template script. Magnolia uses a default script that looks like this:
[#list components as component ] [@cms.component content=component /] [/#list]
The FreeMarker expression [@cms.area name="main"/]
on line 18 includes the area.
[#assign title = content.title!"Hello Magnolia :-)"] <!DOCTYPE html> <html> <head> <title>${title}</title> <link rel="stylesheet" href="//fonts.googleapis.com/css?family=Raleway:200" type="text/css"> <link rel="stylesheet" href="${ctx.contextPath}/.resources/hello-magnolia/webresources/css/style.css"> [@cms.page /] </head> <body> <div class="container"> <header> <h1>${title}</h1> [#if content.introText?has_content]<p>${content.introText}</p>[/#if] </header> <div class="main"> [@cms.area name="main"/] </div> </div> </body> </html>
hello-magnolia/templates/components/quotation.yaml
.hello-magnolia/templates/components/quotation.ftl
.hello-magnolia/dialogs/components/quotation.yaml
.templateScript: /hello-magnolia/templates/components/quotation.ftl renderType: freemarker dialog: hello-magnolia:components/quotation title: Quotation
When rendering content you should test whether it exists. At least the quotation must exist, otherwise the whole component will not be rendered.
[#if content.quotation?has_content] <blockquote> ${cmsfn.decode(content).quotation} [#if content.citedPerson?has_content]<cite>${content.citedPerson}</cite>[/#if] </blockquote> [/#if]
We use a rich text editor to enter the quotation on line 7 in the dialog definition below. It stores text in a way that every paragraph is surrounded with a <p>
tag. That's also the reason to decode the content using the
cmsfn.decode
function, line 3 above.
form: tabs: - name: tabTexts label: Quotation fields: - name: quotation class: info.magnolia.ui.form.field.definition.RichTextFieldDefinition label: Quotation - name: citedPerson class: info.magnolia.ui.form.field.definition.TextFieldDefinition label: Cited person actions: commit: class: info.magnolia.ui.admincentral.dialog.action.SaveDialogActionDefinition cancel: class: info.magnolia.ui.admincentral.dialog.action.CancelDialogActionDefinition
Your file system should now look like this:
├── dialogs/ │ ├── components/ │ │ └── quotation.yaml │ └── pages/ │ └── hello.yaml ├── webresources/ │ └── css/ │ └── style.css └── templates/ ├── components/ │ ├── quotation.ftl │ └── quotation.yaml └── pages/ ├── hello.ftl └── hello.yaml
Congratulations!
You now know the basics of Magnolia content templating. Using these techniques you can build websites where non-technical authors can manage content using dialogs.
Next steps: