Implementer training - Funnelback templating

The search results produced by Funnelback are fully customizable. This allows the search results to be adapted for any HTML design or text-based formats such as CSV, XML and JSON.

Funnelback uses the Freemarker templating language to define the search templates. The templates look like HTML files with additional custom tags - anyone familiar with editing HTML will be able to understand the Freemarker template code. The Freemarker documentation should be read to assist in understanding the Funnelback templates.

A single search results template in Funnelback must handle two cases covering what to present to the end user before and after a search is run.

Template preview and live modes

The Funnelback search dashboard provides the ability to preview changes made to template files, allowing changes to be made and viewed without the live search being affected.

The changes are then published to make them visible on the live search.

Tutorial: Preview and publish template changes

This exercise looks at a bare-bones search results template and relates the template file to what you see on screen.

  1. Log in to the search dashboard where you are doing your training.

    See: Training - search dashboard access information if you’re not sure how to access the training. Ignore this step if you’re treating this as a non-interactive tutorial.
  2. Locate the female inventors search package.

  3. Manage the linked inventors results page by selecting the results pages tab then clicking on the inventors title.

  4. From the inventors results page management screen, view the template in preview mode. Locate the search box, select the preview item from the drop-down menu then click on the [ ] button. This runs the search and opens the results in a new browser tab.

    exercise preview and publish template changes 01
  5. The search results are loaded in a new browser tab - a very basic search box is displayed, along with some search results. Observe that the URL includes two URL parameters - collection and profile. The Funnelback query processor is accessed by visiting the search.html URL and passing parameters to it that tell Funnelback what search package (collection) and results page (profile) to use. The URL also contains a couple of additional parameters (log and s) which are extra parameters that were added because you ran the search from the results page management screen.

    exercise preview and publish template changes 02
  6. Delete the two additional parameters from the end of the URL (&log=false&s=!FunDoesNotExist:PadreNull) then press enter. This now shows the template’s response when no search query is provided (just a search box). Templates are configured to return certain content only when a search query is provided. View the HTML page source in your web browser. Note that the code returned includes only the HTML form code to call the Funnelback search with basic parameters.

    <!DOCTYPE html>
    <html lang="en-us">
    <head>
       <title>Female inventors, Funnelback Search</title>
    </head>
    <body>
      <form action="search.html" method="GET">
        <input type="hidden" name="collection" value="default~sp-inventors">
        <input type="hidden" name="profile" value="inventors_preview">
        <input required name="query" id="query" title="Search query" type="text" value="" accesskey="q" placeholder="Search Female inventors&hellip;">
        <button type="submit">Search</button>
      </form>
    </body>
    </html>
  7. Close the tabs showing the html source code, and the search results screen. Preview the search again, this time entering invention into the search box before submitting the query. Observe that the URL called is the same as the previous URL, but with one additional parameter, query. This demonstrates that the search results template handles two types of result screens - a screen (normally containing a search box) when no query is present and a screen containing a search results listing when a query has been provided.

    exercise preview and publish template changes 03
  8. Return to the inventors manage results page screen by closing the tab. Load the template manager by selecting edit results page templates from the templates panel.

    manage results page panel template
  9. The template management screen allows you to edit, rename, delete, publish and unpublish existing templates and create or upload new templates for use with the current frontend service. Edit the template by clicking on the simple.ftl link. simple.ftl is the default template.

    exercise preview and publish template changes 05
  10. The template file loads in the built-in template editor:

    exercise preview and publish template changes 06

    If you are familiar with HTML you will probably be able to read the template and get a sense of what it’s doing. Freemarker templates are made up of XML-style tags that look like <@MACRO> (Freemarker macro) or <#DIRECTIVE> (Freemarker directives), and Freemarker variables that look like ${VARIABLE}. Everything else in the template will be returned as is. The HTML code inside the <@s.AfterSearchOnly> macro is rendered only after a search is run. This explains why the first preview of the search only displayed a search box, but after a search for inventors was run the search results were also displayed. It also means that the same template file is used to provide the interface for both use cases - before and after a search has taken place.

  11. Add a heading image to the results page. Locate the <body> tag and insert:

    <div><img src="https://docs.squiz.net/training-resources/inventors/media/images/women_header.jpg" ></div>

    immediately after the (<body>) tag.

  12. Save your changes by clicking the save button (but don’t save and publish at this stage).

  13. Return to the inventors results page manage screen and preview your template again - view the search before and after submitting a query to view the effects of your change.

    exercise preview and publish template changes 07
  14. View the template again, but select the live option from the drop-down menu before submitting the search. Observe that the banner image is not displayed. This is because the change has been made only to the preview mode of the search - to make the change live the template needs to be published.

  15. The template management screen (accessed via the edit results page template link on the inventors manage results page screen) indicates that the template has unpublished changes. The file listing also shows a backup file that was automatically created when you saved the template when you toggle the show backup files option below the file listing.

    exercise preview and publish template changes 08
  16. Publish the template by clicking on the publish button. The status will update to published. Note that the unpublish button is used to completely remove the template from the published (live) view, and not to undo changes that you have published.

    exercise preview and publish template changes 09
  17. View the live mode of the search results page again and confirm that the banner is now displayed. Select live from the view menu to show the published (live view) templates then click the small eye icon on the right hand side of the simple.ftl row to load the search with the live version of the template.

Error logging

Funnelback logs user interface issues to the modern UI log. These are accessible via the log viewer from the collection log files for the search package. The relevant log files are:

  • modernui.Public.log: contains errors for searches made against the public HTTP and HTTPS ports.

  • modernui.Admin.log: contains errors for searches made against the administration HTTPS port.

These files will only get created when some errors occur.

See: Modern UI logging for more information on the modern UI logging, and also for information on how to increase the modern UI log level.

Funnelback also includes some settings that allow this behavior to be modified so that some errors can be returned as comments within the (templated) web page returned by Funnelback.

The following configuration options can be set in the parent search package’s configuration while you are working on template changes:

ui.modern.freemarker.display_errors=true
ui.modern.freemarker.error_format=string

The error format can also be set to return as HTML or JSON comments.

The string error format will return the error as raw text, which results in the error message being rendered (albeit unformatted) when you view the page - this is the recommended option to choose while working on an HTML template as the errors are not hidden from view.

Setting these causes the template execution to continue but return an error message within the code.

Syntax errors in the template resulting in a 500 error are not returned to the user interface - the browser will return an error page.

Data model log object

The data model includes a log object that can be accessed within the Freemarker template allowing custom debug messages to be printed to the modern UI logs.

The log object is accessed as a Freemarker variable and contains methods for different log levels. The parameter passed to the object must be a string.

The default log level used by the modern UI is INFO. To capture more detailed logs you can pass a special HTTP header in with your request to cause the request to be logged at the TRACE level. See: Increasing the log level for a request

When debugging you define the log level for the message to print.

e.g.

<#-- print the query out at the INFO log level -->
${Log.info("The query is: "+question.query)}
<#-- print the detected origin out at the DEBUG log level -->
${Log.debug("Geospatial searches are relative to: "+question.additionalParameters["origin"]?join(","))}
Messages written via the log object will only be logged when accessing the search.html endpoint.

Tutorial: View template error messages

This exercise examines the log files used to hold errors generated by templates.

  1. Log in to the search dashboard where you are doing your training.

    See: Training - search dashboard access information if you’re not sure how to access the training. Ignore this step if you’re treating this as a non-interactive tutorial.
  2. Open the inventors results page that is linked to the female inventors search package.

  3. From the inventors manage results page screen, select edit results page templates, then edit the simple.ftl.

  4. Add the following code below the <body> line then save the template. This introduces an unclosed variable to the template which will break the display.

    ${broken
    exercise view template error messages 01
  5. View the broken template by conducting a search for invention against the preview version of the results page. Observe that an error is now returned.

    exercise view template error messages 02
  6. Return to the search dashboard home, locate the female inventors search package and open the management screen for the search package (click the female inventors title). Select browse log files from the tools panel.

    manage search package panel tools

    Template errors are written to the following logs, which appear beneath the collection logs heading:

    modernui.Public.log

    This log is used when accessing the search results via the public HTTP or HTTPS ports (by default this is for http:// or https:// requests to the search that use standard ports; or ports 9080 and 9443 if you are using the Vagrant training VM).

    modernui.Admin.log

    This log is used when accessing the search results via the admin HTTPS url (normally on port 8443). This URL is normally only accessed when you preview a search from the administration interface.

  7. View the modernui.Admin.log file (as the search has been launched from the administration interface search box) by clicking on the log file name. The end of the log file should provide clues about what caused the error. The log file indicates that the template contains an error at line 11.

    2022-09-09 03:22:33,901 [admin-3723] [default~sp-inventors:inventors_preview] ERROR interceptors.FreeMarkerParseExceptionInterceptor - Error parsing FreeMarker template freemarker.core.ParseException: Syntax error in template "conf/default~sp-inventors/inventors_preview/simple.ftl" in line 11, column 5:
    Encountered ">", but was expecting one of these patterns:
    "."
    ".."
    <DOT_DOT_LESS>
    "..*"
    "?"
    "??"
    "!"
    "["
    "("
    "}"
    <TERMINATING_EXCLAM>
    at freemarker.core.FMParser.generateParseException(FMParser.java:6120)
    at freemarker.core.FMParser.jj_consume_token(FMParser.java:5979)
    at freemarker.core.FMParser.StringOutput(FMParser.java:1675)
    at freemarker.core.FMParser.MixedContentElements(FMParser.java:3968)
    at freemarker.core.FMParser.Root(FMParser.java:4665)
    at freemarker.template.Template.<init>(Template.java:252)
    at freemarker.cache.TemplateCache.loadTemplate(TemplateCache.java:548)
    at freemarker.cache.TemplateCache.getTemplateInternal(TemplateCache.java:439)
    at freemarker.cache.TemplateCache.getTemplate(TemplateCache.java:292)
    at freemarker.template.Configuration.getTemplate(Configuration.java:2836)
    at freemarker.template.Configuration.getTemplate(Configuration.java:2694)
    at org.springframework.web.servlet.view.freemarker.FreeMarkerView.getTemplate(FreeMarkerView.java:375)
    ...
  8. Return to the template editor and correct the error by closing the bracket on the variable added earlier in the exercise before saving the template. If you saved and published in the earlier step make sure you save and publish again now to ensure that the change is applied to both the preview and the live versions of the template.

    ${broken}
  9. Rerun the search. The browser still shows an error, however this time the error is due to the variable being undefined and there is some text providing a clue as to the problem. This error can be investigated in the same way as the previous error.

Tutorial: Enable template debugging

In this exercise the results page configuration will be updated to return errors to the template as plain text.

this approach only works on some types of errors - debugging using log files is still required if the template fails to compile.
  1. Log in to the search dashboard where you are doing your training.

    See: Training - search dashboard access information if you’re not sure how to access the training. Ignore this step if you’re treating this as a non-interactive tutorial.
  2. Open the inventors results page configuration screen.

  3. Select edit results page configuration from the customize panel.

    manage results page panel customize
  4. Check to see if ui.modern.freemarker.display_errors is listed in the currently set keys

    exercise enable template debugging 02
  5. Add the setting by clicking the add new button. Start typing freemarker into the parameter key field and select ui.modern.freemarker.display_errors from the suggested entries.

    exercise enable template debugging 03
  6. Set the value to true then save the setting.

    exercise enable template debugging 04
  7. Repeat to set ui.modern.freemarker.error_format.

    The error format can be set to one of exception, json, html or string. Exception (the default) causes template processing to halt completely if an error is encountered (which will usually result in either a blank screen or a server error page being returned). JSON and HTML return the error messages wrapped in JSON or HTML comments. Set the value to string, which returns the error as a string, so that the errors will appear in the browser display.

    exercise enable template debugging 05
  8. Rerun the query for invention observing the error message that is returned and also that the search results are now returned below the error message.

    exercise enable template debugging 06
  9. View the page source to read the error message with some formatting - as the error message is currently returned as raw text the browser will join all the text into a single paragraph.

    exercise enable template debugging 07
  10. The two results page configuration settings should be removed once testing of the template is complete to avoid errors being exposed to users. Return to the results page configuration screen and remove the two ui.modern.freemarker options added above.

  11. Reset the template by removing the ${broken} parameter that was added above.

  12. Print some custom log messages. Edit the simple.ftl and add the following lines after the <@AfterSearchOnly> tag on (approx.) line 30:

    <#-- print the query out at the INFO log level -->
    ${Log.info("The query is: "+question.query)}
    <#-- print information on the version of Funnelback that is running. -->
    ${Log.debug("Funnelback version:  "+response.resultPacket.details.padreVersion)}
  13. Run a search against the inventors results page and observe the messages written to the modernui.Public.Log (or modernui.Admin.log). Observe that only the INFO level message is displayed. This is because the default log level is INFO (meaning deeper log level messages are suppressed). Refer to the previous exercise if you can’t remember how to access the log files.

  14. Modify the simple.ftl and amend the second log call that prints the Funnelback version to use the INFO log level and observe the messages in the modern UI logs.

  15. Reset the template by removing the two Log calls.

Extended exercise: template debugging
  1. Experiment with the effect of changing the error format on both the template and log files.

Template editor shortcuts

The built-in template editor has a number of keyboard shortcuts that can assist with editing. The keyboard shortcuts will vary depending on whether you are using a Windows PC or Apple Mac computer.

Windows MacOS

Save (but don’t publish) changes

Ctrl+S

control ⌃+S

Jump to a line number

Ctrl+L

command ⌘+L

Find (click + button on find popup for replace)

Ctrl+F

command ⌘+F

the jump to line option only works in some browsers.

Customizing the search results block

Search results are templated according to the code that appears within the <@s.Results> block of code.

<@s.Results>
<#if s.result.class.simpleName != "TierBar">
CODE FOR EACH RESULT
</#if>
</@s.Results>

Basic results item variables available:

  • s.result.title: the result title

  • s.result.summary: the result summary

  • s.result.liveUrl: the URL of the target document

  • s.result.clickTrackingUrl: the URL to use for link actions to make use of Funnelback’s click tracking feature.

  • s.result.cacheUrl: the URL to use to access the cached version of the document

  • s.result.date: the date associated with the document.

  • s.result.fileType: the file type of the document

  • s.result.rank: the position (rank) of the current result item inside the result set.

  • s.result.listMetadata: map of metadata elements available for use in templates. Values for each are returned as a list of strings. Includes only metadata fields that have been configured (using display options) to be returned with the search results.

To print any of these values (except for listMetadata) wrap them in the Freemarker directive ${VARIABLENAME}. E.g. ${s.result.title} will be replaced with the title text for the current result. To print values from listMetadata you need to iterate over the map using the Freemarker <#list> directive.

Before accessing any variable ensure that the variable being printed is defined:

  • by wrapping the variable in an <#if> statement using the missing value operator ??

    <#if s.result.title??>${s.result.title}<#else>No title</#if>
  • or for cases where you are printing variable without surrounding markup an exclamation mark (!) can be used e.g. ${VARIABLENAME!}

    • ${s.result.title}: template returns an error if the variable is not defined.

    • ${s.result.title!}: prints variable if set otherwise nothing

    • ${s.result.title!"Empty"}: prints variable if set otherwise prints Empty or any string you define.

Tutorial: Customize the search results listing

This exercise shows how to make some simple changes to the formatting of the individual search results.

  1. Log in to the search dashboard where you are doing your training.

    See: Training - search dashboard access information if you’re not sure how to access the training. Ignore this step if you’re treating this as a non-interactive tutorial.
  2. Open the template editor for the inventors results page you were using in the previous exercise.

  3. Edit the template for the by selecting edit results page templates from the template panel then clicking on the simple.ftl link. Locate the results block (the code between <@s.Results> and </@s.Results>, starting at approx line 97). Observe that the ordered list container appears outside the <@s.Results> tags. The Freemarker code inside the results block is expanded for each result item in the result set. Variables, such as ${s.result.title} are replaced with the value from the current result item. For example ${s.result.date} is replaced with the date of the current result.

    exercise customise the search results listing 01
  4. Modify the template so that the search results are returned inside a table. When you are finished save the change (but don’t publish yet). Hint: you need to replace the <@s.Results> block and surrounding <ol> tags and replace with the following:

    <table>
      <tr><th>Title</th><th>URL</th><th>Summary</th></tr>
      <@s.Results>
        <#if s.result.class.simpleName != "TierBar">
          <tr>
            <td>
              <a href="${s.result.clickTrackingUrl}" title="${s.result.liveUrl}">
                <@s.boldicize><@s.Truncate length=70>${s.result.title}</@s.Truncate></@s.boldicize>
              </a>
            </td>
            <td>
            <cite><@s.cut cut="http://"><@s.boldicize>${s.result.displayUrl}</@s.boldicize></@s.cut></cite>
            </td>
            <td>
            <#if s.result.summary??>
              <p>
                <#if s.result.date??>${s.result.date?date?string("d MMM yyyy")}:</#if>
                <@s.boldicize><#noautoesc>${s.result.summary}</#noautoesc></@s.boldicize>
              </p>
            </#if>
            </td>
          </tr>
        </#if>
      </@s.Results>
    </table>
  5. Preview your changes. You should see the results reformatted in a table, similar to what’s displayed below. If you receive a server error then check to make sure you haven’t accidentally broken any of the macro or conditional Freemarker tags.

    exercise customise the search results listing 02
Extended exercise: result customization
  1. Experiment and make some other changes to the template to change the result formatting. Try displaying some of the other items listed under the customizing the search results block heading above. For example add the result rank as an additional first column.

The data model - an introduction

Behind every search page is a highly detailed data structure containing all the data relating to the search transaction. This data structure, known as the data model, contains information relating to the search query, response and configuration. Every element that is returned in the data model can be utilised by the search template.

Top-level structure

The Funnelback data model consists of two main objects:

  • question: includes all of the data defining the search question. This includes the search keywords, the collection, configuration, ranking and display options, and other search constraints.

  • response: the response contains all of the information returned by the Funnelback query processor in response to the question object. This includes the search results and associated metadata, faceted navigation and result counts, spelling suggestions, best bets etc.

Tutorial: Viewing the data model for a search as XML or JSON

It is often useful to view the underlying data model for a query when building a search template or debugging search behavior. The data model shows you all the settings that are applied and also all of the data elements and values that you can use within the search template. This exercise shows how to view the underlying data model for a Funnelback query in XML or JSON.

A browser plugin or extension for formatting of JSON (such as JSONView) may be required to view the JSON response.
  1. Log in to the search dashboard where you are doing your training.

    See: Training - search dashboard access information if you’re not sure how to access the training. Ignore this step if you’re treating this as a non-interactive tutorial.
  2. Open the inventors manage results page screen for the female inventors search package.

  3. Run a search for invention: enter invention into the search preview box and execute the search.

    exercise viewing the data model for a search as xml or json 01
  4. Edit the URL in your browser and change search.html to search.xml to view the data model behind the search for invention as XML. This is the XML endpoint for the search and shows the underlying data structure for the query for invention that you just ran.

    exercise viewing the data model for a search as xml or json 02
  5. Edit the URL in your browser and change search.xml to search.json to view the data model behind the search for invention as JSON. Observe that the data structure is the same as the one that you just viewed as XML. If your browser just displays unformatted text then you don’t have a JSON viewer browser extension installed on your computer. If you are seeing unformatted text install a browser extension to enable you to view the JSON.

    exercise viewing the data model for a search as xml or json 03

    Inspect the question object. Observe that there are sub-items, and that each item contains a key and value component.

    The data type is important as Freemarker has different built-in functions that operate on the variable depending on the variable’s type.

    The key is case-sensitive so take care when accessing the variables from Freemarker templates.

    The value component indicates the data type of the field. Funnelback fields are one of the following types:

    • String: indicated by double quotes e.g. title: "example"

    • Number: indicated by an integer without quotes e.g. rank: 0

    • Sequence: (array/list) indicated by square brackets e.g. selectedFacets: []

    • Hash: (map/associative array) indicated by curly brackets e.g. environmentVariables: {}

    While the XML endpoint will work in most browsers, it is recommended that you install a suitable JSON viewer plugin and user the JSON endpoint. The XML is useful for viewing the structure but doesn’t provide you with information on the different variable types so is only of limited use when viewing the data model.

Freemarker macro libraries

Funnelback ships with two libraries of Freemarker macros, providing quick pre-built functions that can be used to build your search interface.

The libraries are loaded into the search template using <#import> directives located at the top of the template file.

<#ftl encoding="utf-8" output_format="HTML"/>
<#import "/web/templates/modernui/funnelback_classic.ftl" as s/>
<#import "/web/templates/modernui/funnelback.ftl" as fb/>

The two import directives above import the funnelback_classic and funnelback macro libraries into the s and fb namespaces respectively.

The macros included within these libraries can be accessed once imported by prefixing the macro call with the namespace. The libraries contain functions that implement conditional logic (e.g. whatever appears inside this tag is run only after a search keyword is entered) or handle logic required to implement the display of a feature.

E.g. <@s.Results> calls the Results macro from the s namespace (which corresponds to the funnelback_classic macro library).

  • funnelback_classic: contains macros providing access to Funnelback’s core functionality.

  • funnelback: contains macros providing access to extended and newer functionality.

Funnelback documentation

Freemarker built-in functions

Freemarker has an extensive set of built-in functions that can be called when a value is printed. A built-in function is called by appending a question mark (?) to the variable name and adding the function. E.g. $+{s.result.title?upper_case}+ prints the result title as an uppercase string. Function calls can also be chained. ${s.result.title?upper_case?html} will convert the title to upper case then html encode it.

The built-in functions provide a rich set of tools that can be used to manipulate or transform the variables allowing a huge amount of flexibility to be built in to the search result templates.

When working with Freemarker it is important to know what version of Freemarker is used by the version of Funnelback you are using as some built-in functions are not available in older versions of Freemarker.

Variable escaping

Freemarker has built-in support for the automatic escaping of variables that are in templates. Escaping is an important tool that ensures template generated-code is valid and is also an important security feature as correct use of escaping mitigates some security issues such as injection style attacks.

Templates should define an output format that specifies what type of content is being returned. The defined output format will apply escaping rules to all variables contained within the template unless you choose to override the default escaping for a section of the template or when expanding specific variables.

Creating additional results pages

A search package can host one or more results pages, each of which support templating, best bets, analytics and so on.

It is also possible for a single results page to support multiple templates, however the most common use case of requiring multiple templates for a search should be setup us as an additional results page so that the supporting configuration can also be tailored for your results page.

Create an additional web page if you are providing a different search (e.g. publications search vs. site search) - this will provide separate analytics and also allow you to configure separate features for your new results page such as facets, best bets etc.

Create an additional template on your results page if you want analytics for this to be captured together and the content that you are searching across is identical

The default template for any results page in Funnelback is the simple.ftl template. Additional templates with arbitrary file names can be defined and created from the template management screen.

Search results templates in Funnelback usually have the following overall logic:

if (search has not been performed)
    display empty search input box and branding
else
    display a search refinement box
    if (search has matching results)
        for each matching result
            display result
    else
        display zero results message

Tutorial: Customize a results template

In this exercise we will create a new results page for the search package and customize the default template to provide basic logic for the presentation of the search results.

  1. Log in to the search dashboard where you are doing your training.

    See: Training - search dashboard access information if you’re not sure how to access the training. Ignore this step if you’re treating this as a non-interactive tutorial.
  2. Locate the female inventors search package. Click the results pages tab then click the add results page button.

    exercise create a custom template 01
  3. Enter basic when prompted for the results page name and click the continue button.

  4. You are then given the option to upload an image thumbnail, which will be displayed for this results page. We’ll skip this now. Click the proceed button.

  5. The review step confirms the information you have entered for your results page and provides you with the chance to go back and make any corrections. Click the finish button to create your results page.

  6. You are redirected to the results page manage screen (the same as what you used in previous exercises, but this time for your basic results page).

  7. Click the edit results page template option in the template panel to access your results page template.

  8. Click the simple.ftl link to edit the default template for the basic results page. The default template for a results page is always called simple.ftl.

  9. Select and delete all the text in the template editor and replace it with the code below, then click save and publish. This will update the template to use the basic logic described above.

    <#ftl encoding="utf-8" output_format="HTML"/>
    <#import "/web/templates/modernui/funnelback_classic.ftl" as s/>
    <#import "/web/templates/modernui/funnelback.ftl" as fb/>
    <!DOCTYPE html>
    <html lang="en-us">
    <head>
    <title>My search template</title>
    </head>
    <body>
     <#-- NO QUERY -->
    <@s.InitialFormOnly>
        <p>No query submitted yet.  Sorry.</p>
    </@s.InitialFormOnly>
    <@s.AfterSearchOnly>
        <#-- DISPLAY RESULTS -->
        <ol>
        <@s.Results>
            <#if s.result.class.simpleName == "TierBar">
                 <#-- TIER BAR FOR PARTIAL MATCHES -->
                <#if s.result.matched != s.result.outOf>
                    <p>Search results that match ${s.result.matched} of ${s.result.outOf} words</p>
                </#if>
            <#else>
                <li><a href="${s.result.clickTrackingUrl}" title="${s.result.liveUrl}">${s.result.title}</a></li>
            </#if>
        </@s.Results>
        </ol>
        <#-- NO MATCHES -->
        <#if response.resultPacket.resultsSummary.totalMatching == 0>
            <p>Sorry.  No matches found.</p>
        </#if>
    </@s.AfterSearchOnly>
    </body>
    </html>
  10. Return to the results page manager by clicking basic in your breadcrumb trail. Preview the search template by running a search for barbie the central search box. This shows what the basic template returns when a valid query is input. Observe that the URL contains a parameter, profile=basic_preview - this tells you that it’s using the basic results page that you just created, and displaying the preview version of the results page. If you rerun the search and select the live option you’ll notice that the URL parameter now points to the live profile profile=basic.

    exercise create a custom template 02
  11. Test the template logic. Update the URL by updating the query parameter to qwerty, a word that won’t match any results. This demonstrates what is returned to a user for the case where there are no search results.

    exercise create a custom template 03
  12. Test the default form case - for what is returned when the template is called with no query. Update the URL by removing the query parameter (delete &query=qwerty) then press enter.

    exercise create a custom template 04
Extended exercises: conditional templating
  1. Define a query that will display partially matching results (results that match some of the words in the query). Replace query=qwerty in URL with query=hair dryer.

  2. Update the text that is presented when there are no search results.

  3. Experiment with some of the Freemarker built-in functions and observe the effect on the search results output.

Web resources

Most templates rely on external resources such as image, JavaScript and CSS files.

These external resources can be stored at web accessible locations such as your public web server and referenced as external resources from the template using absolute URLs.

Funnelback provides web resource folders that can also be used for local storage of these files. Web resource folders are associated with the folders that contain the search template files.

The URL of a web resources folder is constructed using the following pattern: <PROTOCOL>://<FUNNELBACK-SERVER>/s/resources/<SEARCH-PACKAGE-ID>/<RESULTS-PAGE-ID>/<FILENAME>

where:

  • <PROTOCOL> is either http or https

  • <FUNNELBACK-SERVER> is the hostname of the Funnelback server. If referencing from a template the <FUNNELBACK-SERVER> and <PROTOCOL> can be omitted and presented as a relative link.

  • <SEARCH-PACKAGE-ID> is the collection containing the resource. (This can be copied from the collection parameter in the URL of the file manager). When accessing a resource from within a search template <COLLECTION-ID> should be replaced with:

    ${question.collection.id}
  • <RESULTS-PAGE-ID> is the results page containing the resource (this can be copied from the profile parameter in the URL of the file manager). When accessing a resource from within a search template <RESULTS-PAGE-ID> should be replaced with:

    ${question.profile}
  • <FILENAME> is the filename of the web resource.

    E.g. a link to a resource from a template example.css might be:

    <link rel="stylesheet" href="/s/resources/${question.collection.id}/${question.profile}/example.css" />
It is often a good idea to use protocol-independent URLs when linking to web resources to avoid mixed content warnings when working with HTTPS urls.

Tutorial: Web resources

This exercise shows how to manage your web resources and access them from your Funnelback templates.

  1. Log in to the administration interface by visiting https://localhost:8443/d/client/

  2. Open the template editor for the inventors results page (note: not the basic results page from the previous exercise).

  3. Select Edit web resources files from templates panel.

  4. Click the add new button to create a new file named inventor-styles.css. Create a CSS file containing the following code then click the save button:

    body { font-family: Verdana, Arial, Helvetica, sans-serif; background: #5a4a42; margin-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; }
    p { font-size:12px; padding-left: 10px; padding-right: 5px; line-height: 18px; }
    h1 { font-size:16px; color: #61281d; padding-left: 10px; }
    h2 { font-size:14px; color: #cb8366; padding-left: 10px; }
    h3 { font-size:12px; color: #cb8366; padding-left: 10px; }
    table td { background-color: #fff;}
    input#query {width:500px;}
    .tt-menu h5.tt-group {background-color:transparent; text-align:left; border-bottom:1px solid #333;}
  5. Click the back to directory button to return to the web resources file manager. Observe that inventor-styles.css is now listed, but has a status of new. Web resources can be previewed allowing changes to me made to web resources that can be tested without being live.

    exercise web resources 02
  6. Modify the default search template (simple.ftl) to reference the newly added CSS file. Remember that the resource will only be available from the preview version of the template until both the template and the CSS file are published. Add the following to the document’s <head> and click save.

    <link rel="stylesheet" href="/s/resources/${question.collection.id}/${question.profile}/inventor-styles.css" />
  7. Test the search by running some queries and verify that the linked styles are now being applied.

    exercise web resources 03
  8. Publish both the CSS and template files and verify that the changes are live.

  9. Make the CSS file available from a css subfolder. Hint: remove the css file the create a css folder (using the add new button) then upload the css file into the newly created folder. Update your search template to read the CSS file from the new location.

Extended exercises: style the results page
  1. Style the results page for the inventors search to match the styling for the inventors website. This will require additional styles to be defined within the imported stylesheet and additional markup (<div> tags etc.) to be added to the main results template.