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
|
Type
|
---|---|---|
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.
|
|
navBreadcrumbBuilder
|
Helper class that returns the
list of path components in an
URL, to create navigation
breadcrumbs.
|
|
navTreeBuilder
|
Helper class that creates
navigation trees to
facilitate rendering.
|
|
tenantsResolver
|
Can be used to retrieve the
Profile tenants associated to
the current site.
|
|
modePreview
|
Flag that indicates that Engine is
being executed in preview mode
(also the value of the
crafter.engine.preview property) |
Boolean
|
crafterEnv
|
Indicates the value of the
crafter.engine.environment property
|
String
|
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 Breadcrumbs¶
Crafter also offers a renderBreadcrumb
macro to easily generate a dynamic list with all the
parent pages of a specific url.
1 2 3 | <#import "/templates/web/navigation2/breadcrumb.ftl" as breadcrumb>
<@breadcrumb.renderBreadcrumb contentModel.storeUrl "/site/website/articles" />
|
- The first argument is the full url of the item to generate the breadcrumb.
- The second argument is the root path that will be skipped in the list of items returned, if no value is given the default is “/site/website” (usually this is the home page).
Using Custom Macros¶
Both renderNavigation
and renderBreadcrumb
use other macros to render the items.
In the case of navigation each type of item has it’s own macro:
renderRootItem
: for the top level item.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.
For breadcrumb there is only one type of item:
renderBreadcrumbItem
Engine includes a default implementation that can be found in templates/web/navigation2/nav-macros.ftl
and templates/web/navigation2/breadcrumb-macros.ftl
but it also provides the option to use your
own sets of macros, which you’ll probably want since the navigation HTML is generally specific to the site.
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 26 27 28 29 | <#macro renderNavItem navItem>
<li <#if navItem.active>class="active"</#if>><a href="${navItem.url}">${navItem.label}</a></li>
</#macro>
<#macro renderRootItem navItem>
<@renderNavItem navItem/>
</#macro>
<#macro renderNavItemWithSubItems navItem>
<li <#if navItem.active>class="dropdown active"<#else>class="dropdown"</#if>>
<a class="dropdown-toggle" data-toggle="dropdown" href="${navItem.url}">${navItem.label}</a>
<ul class="dropdown-menu">
<#nested>
</ul>
</li>
</#macro>
<#macro renderNavSubItem navItem>
<@renderNavItem navItem/>
</#macro>
<#macro renderNavSubItemWithSubItems navItem>
<li class="dropdown-submenu">
<a href="${navItem.url}">${navItem.label}</a>
<ul class="dropdown-menu">
<#nested>
</ul>
</li>
</#macro>
|
1 2 3 4 5 6 7 | <#macro renderBreadcrumbItem item >
<#if item.active>
<li class="active">${item.label}</li>
<#else>
<li><a href="${item.url}">${item.label}</a></li>
</#if>
</#macro>
|
You can define your own macros in an additional Freemarker template and include and optional
parameter with the namespace that was given in the import
tag:
1 2 3 4 5 6 7 | <#import "/templates/web/navigation2/navigation.ftl" as nav>
<#import "/templates/web/navigation2/breadcrumb.ftl" as breadcrumb>
<#import "/templates/web/components/custom-nav-macros.ftl" as customNav>
<@nav.renderNavigation "/site/website", 1, false, customNav />
<@breadcrumb.renderBreadcrumb contentModel.storeUrl, "/site/website/articles", customNav />
|
Note
If you use custom macros for navigation, you need to define each one with the same name as shown in the list and include all parameters according to the default implementation provided by Engine.
In case the structure provided by the macros is not suitable for your need you can also use the beans to get the navigation tree or breadcrumb list in a Groovy script:
1 2 3 | def rootPath = "/site/website"
templateModel.navTree = navTreeBuilder.getNavTree(rootPath, 2, contentModel.storeUrl)
templateModel.breadcrumb = navBreadcrumb.getBreadcrumb(contentModel.storeUrl, rootPath)
|
Note
These beans are the same used internally by the builtin macros, they will return NavItem objects.
Running Scripts/Controllers¶
Crafter Engine allows executing scripts/controllers from inside Freemarker templates by using the tag @crafter.controller
. It requires a single parameter, path
, which is the path of the script/controller in the site:
<@crafter.controller path=“/scripts/plugins/MyPlugin/1/get-tweets.groovy” />
<@crafter.controller path=“/scripts/plugins/MyPlugin/1/get-fbs.groovy” />
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:
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"
}
|
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:
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
}
}
|
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>
|
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>
|
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.