FreeMarker is the template language used with Funnelback's Modern UI user interface. FreeMarker is a generic template engine popular in the Java world (although you don't need to know Java to write FreeMarker templates).

Its purpose is to generate a HTML output by merging the Data Model with a search form (a "template"). Funnelback will take care of generating a relevant data model based on your query terms and collection and merge it with the template of your choice. All you need to do is write a template to display the search results.

FreeMarker template files ends with the .ftl extension (stands for FreeMarker Template Library). A default form is provided when you create a collection, named simple.ftl. It's usually a good starting point for customisation.


A FreeMarker template contains 3 element types, in addition to HTML code:

  • ${...} statements that will get replaced by data model values (Ex: ${result.title})
  • FreeMarker tags, either core directives like <#if [condition]> ... </#if> or custom tags like <@s.AfterSearchOnly> ... </@s.AfterSearchOnly>.
  • FreeMarker comments: <#-- ... -->

Data model variables

The ${...} syntax allows you to access and display content from the Data Model. You must use the full path of the data model node you want to display, for example:

Searching for ${question.query} on collection ${}
${response.resultPacket.resultsSummary.totalMatching} results found.

Note that since v12.4 FreeMarker templates also have access to a special variable httpRequest which is not part of the Data Model but contains useful information about the HTTP request. This variable is of type HttpServletRequest and its fields can be accessed like other data model nodes, e.g. request.requestURL.

FreeMarker built-ins can be used to format or escape the data by suffixing the data model node name with ?[builtin], for example:

HTML escaped query: ${question.query?html}
Query transformation: ${question.query?replace("cat", "dog")}

The most commonly used builtin is !. It allows you to specify a default value if the value you're looking for is not defined: ${question.query!"No query"}. This will default to "No query" if query is not defined. Note that if question is not defined the template rendering will fail with an error. To use the default value builtin over the whole expression you must use parenthesis: ${(question.query)!"No query"}. This way if question or query is undefined, the default value will be used instead.

FreeMarker core directives

FreeMarker provides several core directives, the most commonly used being <#if /> and <#list />.

Conditional display

The <#if/> directive allows you to conditionally skip a section of the template. For example if you want to display only "PDF" search results you could do:

<#if r.fileType == "PDF">

The block contained inside the <#if > ... </#if> statement will be executed only if the condition specified is true (in that case the file type of the result equals "PDF").

The condition itself is generally:

  • Based on string equality: r.title == "PDF" or r.title != "PDF"
  • Based on numeric comparison: r.rank == 10
    • Note: When using greater than (>) or lesser than (<) operators you must use their encoded form to avoid conflicts with opening or closing FreeMarker tags. For example you must use <#if r.rank &gt; 10> instead of <#if r.rank > 10>. You can alternatively use parenthesis: <#if (r.rank > 10)>
  • Based on FreeMarker built-ins: r.title?exists or r.title?starts_with("document")

<#if /> statements can be nested without limitation:

<#if r.fileType == "PDF">
  <#if r.rank > 10>

FreeMarker also provides an <#else> directive:

<#if r.fileType == "PDF">
  <p class="error">Result ${r.title} is not a PDF document</p>

Iterating over the data model

The <#list /> directives allows you to iterate over a list of items and execute a block for each item. For example if you want to iterate over search results and display the title of each result you could do:

  <#list response.resultPacket.results as r>

The syntax used is: <#list [name of list] as [single item]> ... </#list> with [name of list] being a list of items from the Data Model and [single item] a name you choose that will contain the single item extracted from the list, for each iteration.

Funnelback custom tags

A set of custom FreeMarker tags for Funnelback is provided in $SEARCH_HOME/web/templates/modernui/. They can be easily imported in your templates using the following directive: <#import "/web/templates/modernui/[library].ftl" as [namespace]/>, [library] being the name of the tags library, and [namespace] being the name under which the tags will be imported.

The provided libraries are:

  • funnelback_classic.ftl : contains a re-implementation of Funnelback's (no longer used) Classic UI tags for FreeMarker. Must be imported under the s namespace.
  • funnelback.ftl : contains tags exclusive to the Modern UI. Must be imported under the fb namespace.

Those two libraries documentation can be accessed by following this link: custom FreeMarker tags.

FreeMarker comments

You can use <#-- ... --> to indicate comments to FreeMarker. Those comments will not be processed by the template engine and won't be shown in the resulting HTML output.

For example if your template contains a mix of HTML and FreeMarker comments as in:

<div class="title">
  <!-- This is the title -->
  <#-- We first check that it's not empty -->
  <#if r.title?exists>${r.title}</#if>

Then the HTML output will be (Assuming the title is "Title of the result"):

<div class="title">
  <!-- This is the title -->
  Title of the result

FreeMarker documentation

FreeMarker is extensively documented in its official documentation, the FreeMarker Manual, available here:

The section of interest when writing Funnelback form files are:

See also