FreeMarker (Templating) API

Each page and component content type in Crafter CMS generally has it’s own view. Crafter Engine, which is in charge of rendering this views, uses Freemarker as the template engine to generate the HTML returned to the client. Documentation for Freemarker can be found at http://freemarker.org.

The most important variable available in the page and component Freemarker templates is the contentModel. Through the contentModel you have access to the content itself. So if in the page you defined a variable name title, you can get the value of title with ${contentModel.title}. Or if you defined a repeater named links, and under it url fields, then accessing the url links is just a matter of iterating the list using <#list contentModel.links.url as url>. The type of the contentModel is SiteItem, so you can also call the methods of that class if the nested property access described previously is not enough, or if you need to access other properties like the storeUrl.

Crafter Engine also populates templates with other useful variables, described below.

Name
Description
API
siteItemService

Allows access to the site
content.
urlTransformationService



Service for transforming URLs,
like transforming the content
URL of a page to the web or
render URL.
searchService


Service that can be used to
execute search queries against
Crafter Search.
applicationContext




Provides access to the Crafter
Engine’s Spring beans and site
beans defined in
config/spring/application-
context.xml.
globalProperties



Provides access to global
configuration properties
defined in
server-config.properties.
breadcrumbBuilder



Helper class that returns the
list of path components in an
URL, to create navigation
breadcrumbs.
tenantsResolver


Can be used to retrieve the
Profile tenants associated to
the current site.
siteConfig

The current site Configuration
loaded from /config/site.xml.
siteContext
The current SiteContext
application
The servlet context
request
The current request
requestParameters

The parameter values for the
current request
cookies

The cookie values for the
current request

session
The current session
locale

The current locale for the
current user
authentication



The current authentication (if
the user has logged in),
created by the
Crafter Security Provider
profile



The current profile (if the
user has logged in), created
by the
Crafter Security Provider

Rendering navigation

Crafter Engine provides the option of rendering automatically the navigation for you, just by using the macro renderNavigation:

<#include "/templates/web/navigation/navigation.ftl">

<@renderNavigation "/site/website", 1 />

The first argument of the macro is the root path of the navigation tree, which in this case is the root path of all pages. The second argument is the level of the navigation tree, which in the case of the example, is only the pages of the first level. The Place In Nav field is also used by the renderNavigation macro to determine if a page should be included in the navigation or not.

The renderNavigation macro uses other macros to render the navigation items. Each type of navigation item has it’s own macro:

  • renderNavItem: for items with no sub-items.
  • renderNavItemWithSubItems: for items with sub-items.
  • renderNavSubItem: for sub-items with no other sub-items.
  • renderNavSubItemWithSubItems: for sub-items with other sub-items.

These macros are included in Engine, under templates/web/navigation/main/nav-macros.ftl. If you want to provide your own sets of macros (which you’ll probably want since the navigation HTML is generally specific to the site), you just need to overwrite the file by placing it under the same path in you project (templates/web/navigation/main/nav-macros .ftl). The following is the default markup of the macros:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
    <#macro renderNavItem item active = false>
    <li <#if active>class="active"</#if>><a href="${navFunctions.getNavItemUrl(item)}">${navFunctions.getNavItemName(item)}</a></li>
    </#macro>

    <#macro renderNavItemWithSubItems item active = false>
    <li <#if active>class="dropdown active"<#else>class="dropdown"</#if>>
        <a class="dropdown-toggle" data-toggle="dropdown" href="${navFunctions.getNavItemUrl(item)}">${navFunctions.getNavItemName(item)}</a>
        <ul class="dropdown-menu">
            <#nested>
        </ul>
    </li>
    </#macro>

    <#macro renderNavSubItem item active = false>
    <li <#if active>class="active"</#if>><a href="${navFunctions.getNavItemUrl(item)}">${navFunctions.getNavItemName(item)}</a></li>
    </#macro>

    <#macro renderNavSubItemWithSubItems item active = false>
    <li class="dropdown-submenu">
        <a href="${navFunctions.getNavItemUrl(item)}">${navFunctions.getNavItemName(item)}</a>
        <ul class="dropdown-menu">
            <#nested>
        </ul>
    </li>
    </#macro>

Keeping Templates Simple

You can access all Crafter Engine services directly from the Freemarker templates as described in the previous sections, however it is a good practice to keep logic and complex operations outside of the templates to simplify debugging and maintenance. An easy way to extract logic from the templates is using Groovy’s closures:

Page or Component Script
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
// Add a closure to the templateModel map, in this case it will find if a page has a custom
// nav icon defined in the xml descriptor.

templateModel.getNavIcon = { item ->
  def storeUrl = urlTransformationService.transform("renderUrlToStoreUrl", item.url)
  def siteItem = siteItemService.getSiteItem(storeUrl)
  if(siteItem) {
    def navIcon = siteItem.navIcon?.text
    if(navIcon) {
      return navIcon
    }
  }
  return "fa-file-o"
}
Page or Component Template
1
2
3
4
<!-- Now the closure is available to use in the template, you only have to use the same name
     from the script and use the `call` method. -->

<i class="fa ${getNavIcon.call(navItem)}">

If you have a large amount of closures or operations that need to be shared between multiple templates then you should consider creating a Groovy class instead:

Custom Service Class
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
// Define a class with all the logic

package org.site.service

class NavIconService {

  def urlTransformationService
  def siteItemService
  def defaultIcon

  def getNavItem(item) {
    ...
    return this.defaultIcon
  }

}
Site Application Context file
1
2
3
4
5
6
7
<!-- Add a bean definition using the new class -->

<bean id="navIconService" class="org.site.service.NavIconService">
  <property name="urlTransformationService" ref="crafter.urlTransformationService"/>
  <property name="siteItemService" ref="crafter.siteItemService"/>
  <property name="defaultIcon" value="${nav.defaultIcon}"/>
</bean>
Site Configuration file
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
<!-- If needed the bean can use external configuration for easy management -->

<?xml version="1.0" encoding="UTF-8"?>
<site>
  ...
  <nav>
    <defaultIcon>fa-file-o</defaultIcon>
  </nav>
  ...
</site>
Template
1
2
3
<!-- Now the bean can be use just like Crafter built-in services -->

<i class="fa ${navIconService.getNavIcon(navItem)}">

Note

All beans defined in the Engine Site Application Context file will be available in templates.