Velocity Templates
Apache Velocity is a Java-based server-side templating language. ISML templates are contained in your code cartridge and can't be changed without activating a new version of code. But you can change Velocity templates simply by uploading a new version of the file to a WebDAV directory on your instance. Using Velocity templates, you can publish section or page layouts and their content assets to your storefront. You don't have to change your storefront code, effectively decoupling code development and content design.
Velocity templates are most useful for content rich sections of your site whose functionality doesn't change. For example: the home page, category pages, designer blogs, lookbooks, sponsored event pages, or loyalty program pages. You can also publish layouts to external communications, such as email or social media posts. Velocity templates are treated like content and not code. You can change them frequently without the considerations necessary when changing code that can affect the functionality of a site.
This feature is most useful with an external Content Management System (CMS), which allows you to design the layout and publish it as a Velocity template.
If you have another way to generate the Velocity templates used by B2C Commerce, a CMS isn't required. For example, you can work with a web design firm that can provide Velocity templates as part of their design
The process for creating and publishing a new layout is:
-
Design the layout. If you are using a CMS, you can design the layout and preview the page as it appears in the storefront. A CMS to B2C Commerce connector gets information from B2C Commerce via OCAPI.
To preview the page for both the current storefront and the next version of the storefront, use different connectors for staging and production instances.
-
Publish the layout and images to your Staging instance for testing via WebDAV and the content assets via import or export. You can choose to automate this functionality in your CMS, so that you can publish in a single step.
-
After testing, transfer data to your production site. Replicate Velocity templates and images to your Production Instance and use import or export to add content assets to B2C Commerce.
Velocity Template Limitations
- While it's technically possible to include content slots in Velocity templates, it isn't officially supported. Slots added to Velocity templates are not listed in Business Manager and can't be previewed in the Storefront Toolkit.
- Page tracking and active data aren't supported for Velocity templates.
- UX Studio doesn't support editing Velocity templates. Velocity templates are shown in the Storefront Toolkit, but the toolkit links to the template location in WebDav, rather than opening it in Studio.
- All variables must be passed to the template for rendering. Velocity has no access to the B2C Commerce API or the implicit variables (such as pdict) available to any ISML template. This situation is similar to the way that ISML is rendered in controllers.
Velocity Template Quotas
- Include depth: 10
- Loop limit: 1000
- Max template size: 100 KB
- Timeout: 100 sec
All quotas are enforced. All other quotas, such as the 10-MB web adapter limit, still apply.
Velocity and Performance
B2C Commerce performance tests found that the performance of Velocity and ISML is comparable for both cached and uncached pages.
Velocity and Content
Velocity templates can contain text directly and also include text from content slots. If you are using a CMS, it's usually more convenient to edit text in your preview page and publish the Velocity template with the text from your CMS.
-
Create the Velocity files, content assets, and image files you intend to use. If you have a CMS, obtain and configure the CMS connector. Consult the connector documentation for information on how to configure the connector.
-
Upload Velocity templates to use for your content layout into the Dynamic WebDAV directory. Velocity templates can be generated from a CMS or developed independently. If you are using a CMS, it must meet the requirements for a system that can integrate with B2C Commerce and provide a B2C Commerce connector. See the following sections for information on selecting a CMS and uploading Velocity templates.
-
Create code to render the Velocity template or snippet. You can use either a pipeline or a controller to render Velocity. You can render Velocity templates stored in the WebDav directory, template snippets included inline in a script or controller, or Velocity as part of an ISML template.
-
Create jobs to replicate images and templates from Staging to production. You might also need to add content assets created by your CMS to your import/export jobs.
Ask your CMS vendor to provide a connector to B2C Commerce that lets you do the following:
- contextual editing of content sections within pages
- managing and previewing pages in the CMS
- a media library that is integrated in the content editing process
- including data from the media library into the publishing process
- Velocity template output
- WebDAV capability
The vendor must offer a B2C Commerce connector to let them integrate with B2C Commerce to achieve this functionality.
You can upload Velocity templates via WebDAV or site import.
Upload via WebDAV
-
Select Administration > Development Setup.
Take note of the WebDAV path under the Velocity Templates section. Add the name of your site to this path. For example:
https://www.mystore.com/on/demandware.servlet/webdav/Sites/dynamic/SiteGenesis
-
Upload your templates using WebDAV. You can upload a file structure as well as individual templates. All paths in code are always relative to the dynamic WebDAV directory.
Upload via Site Import
Use site import to publish a hierarchy of templates as a .zip file to the dynamic directory.
You can render Velocity templates using controllers or pipelines. If you want to share functionality between new and legacy cartridges, we recommend adding your rendering functionality in a utility script that can be used from either controllers or pipeline script nodes. We encourage you to use a controller, even if you intend to overwrite existing functionality that is currently in a pipeline.
Render the Velocity template using the dw.Template.Velocity.render
method. If you use a B2C Commerce script to render a template, you can call the script from either pipelines or controllers.
Hello World - Inline Velocity in a Script File
The following example renders an inline Velocity template using the dw.Template.Velocity.render
class in a script module file. This code can be included directly in a controller or required as a script module from a controller or pipeline script node.
Hello World - Rendering a Template Stored in the Dynamic WebDav Directory
The second example shows a similar 'hello world' example that relies on the Velocity template being located in the file system. You can supply the file name directly:
You can also look up the file manually, which allows you to check whether the file exists.
There is no caching involved in this example.
Velocity Hello World - Callbacks
You can pass any objects that are used by the Velocity template during rendering in a JavaScript Map as a parameter of the rendering method. These include, but aren't limited to, B2C Commerce Script API objects. The engine also supports invoking methods on those objects. The following example passes the B2C Commerce Script API URLUtils
object to render a B2C Commerce product URL within a Velocity template. In the example, this is passed as string literal for better readability.
This example shows how to invoke the template and render the generated content into a string for further processing. For example, if you want to use it in an email.
Calling URLUtils in Templates
Localizing Text
Add the Resource class as a parameter to localize text from a resource bundle.
It is possible to deploy text resource bundles alongside the Velocity templates in the dynamic
file location on WebDAV in a resources
directory. Just like Velocity templates, they follow the content lifecycle and are not part of a code deployment. These text resource bundles are used with the normal dw.web.Resource class
, as they would be in ISML template. You add dw.web.Resource
as a parameter to the template and then call it.
The resource bundles in your code cartridges assigned to your site are checked first and then the dynamic
file location on WebDAV. B2C Commerce uses the first resource bundle it finds with a specific ID. B2C Commerce searches cartridges in the order set by the cartridge path and then the dynamic
file location on WebDAV. This means if there are two resource bundles with the same ID, the resource bundle in the cartridge wins over the resource bundle in the WebDAV location.
Escaping and VelocityTools
In ISML, all values written to the response are automatically escaped based on the response MIME type, except when the encoding is turned off in ISPRINT. However, Velocity requires the template developer to explicitly escape all dynamic values using the VelocityTools EscapeTool. B2C Commerce supports the EscapeTool in context. To escape a value, add a line similar to the following to your Velocity template:
esc
in the example is the EscapeTool.
Supported Velocity Tools
B2C Commerce supports the following Velocity tools:
- AlternatorTool
- ComparisonDateTool
- ConversionTool
- DisplayTool
- EscapeTool
- MathTool
- NumberTool
- ResourceTool
- SortTool
- LinkTool
- LoopTool
For more information about Velocity Http://Velocity.Apache.Org/Tools/Devel/Generic.Html
Adding Remote Includes to Your Velocity Template
You can add a remote include to your Velocity template using the Velocity.remoteInclude
method.
Using caching with Velocity
You can use caching with Velocity by setting the expiration on the response.
Wrapping Velocity with ISML
Most of your storefront is written in ISML, because of the features that ISML offers in terms of consistent styling and caching (isdecorate
and iscache
tags). ISML also supports content slots, which let promotions be scheduled and associated with specific customer groups and previewed for any date. Velocity doesn't support content slots.
In some cases, you might want to wrap your Velocity template in ISML, to take advantage of the features of ISML and the ability to change your layout without affecting code functionality. The following example renders a Velocity segment and includes it in an ISML template.
ContentRender.ds
The script renders the Velocity template and writes it to an object available to the ISML template. The following is added to the ISML template to include the segment if it exists. The script assumes you are using a pipeline to render the ISML.
Writing out the rendered Velocity Template
If you don't want to write the result directly to the response, include a string writer. This is useful for email templates or including snippets of rendered Velocity in ISML templates.
Example: writing a template to the "contact us" Email
This example can be used with the SiteGenesis contact us email template.
email/contactus.isml
Replace the contactus.isml template in your SiteGenesis instance with an identically named template with the following contents:
contactus.vs
This example assumes you have a Velocity template file named contactus.vs
with the following contents:
This template illustrates:
- rendering localized messages (
$res.msg('contactus.name', 'email', null)
) - displaying values (
$form.email
or$!form.phone
) - rendering URLs (
$url.abs('Account-StartRegister')
) - using decisions (
#if(...) ... #else ... #end
) - accessing object data (
!$customer.isAuthenticated()
)
This template must be uploaded via WebDAV to /on/demandware.servlet/webdav/Sites/Dynamic/SiteGenesis
Testing Information
$res.msg('contactus.email', 'email', null)
gets the localized message for contactus.email from the email resource bundle without using a default message (null).
$!form.phone
shows the phone number only if provided. Without the exclamation mark and no phone number provided, it shows the text '$form.phone'
.
To test the contactus template:
-
Open the contactus page in SiteGenesis (/
SiteGenesis/contactus
). -
Fill in the form.
-
Click submit.
You receive the updated email at the specified address with the template information.
A controller can render a Velocity template directly or call a script to render the template. A pipeline must call a script to render a pipeline, either through a script node or in the isscript
tag of an ISML template.
Creating a controller to render a Velocity template or Snippet
Create a controller with a public function that contains the same code as a script or requires a script module. Salesforce recommends creating a script module as a helper function and calling it from your pipeline. The following is a sample helper function:
Creating a pipeline to render a velocity template or Snippet
Salesforce recommends using controllers rather than pipelines,. However, this section describes what to do if you want to add the ability to publish a layout to your existing storefront, which uses pipelines.
If you want to enhance an ISML template with sections of the page rendered using Velocity snippets, create a pipeline with an:
- interaction node - use this to render the ISML template and include the snippets in the ISML template.
- interaction continue node - use this to render the ISML template and include the snippets in the ISML template for forms.
If you want to render a Velocity directly, create a pipeline with:
-
one or more script nodes and a stop node - In general, if you don't want to use an existing pipeline or ISML, it's highly recommended that you use a controller in place of this solution. However, if you don't want your Velocity template wrapped in an ISML template and you want to use an existing pipeline, you can use one or more script nodes to render different parts of the page, such as the header, body, and footer.
Rendering different parts of the page in different script nodes effectively replaces the way
isdecorate
is used in ISML. You can use script logic to select different templates for different sections of a page, such as different header templates for an event-driven sale category or an exclusive page for members of a loyalty program.
When referencing property values in Velocity, make sure to use the correct case for the actual property name. Using an uppercase letter when the property name starts with a lowercase letter generates an error.
ISML Patterns
The # notation in ISML and ISPRINT replace references that can't be resolved with an empty string. Velocity by default prints the reference itself. To avoid that, use the $!VAR notation.
ISML by default escapes all dynamic content written to the output according to the content type (HTML by default) to avoid any XSS problems. Velocity doesn't do that. So all dynamic content needs to be handled by the EscapeTools provided by Velocity. The syntax then becomes: $esc.html($!VAR)
.
Comments in ISML are converted to lines starting with '##
' in Velocity.
The notation for conditions is:
An 'isDefined(VAR)
' test is now '#if($VAR)
', and "hasLoopElements(ITER)
' gets replaced as '#if($IT.hasNext())
'.
For remote includes, a directive needs to be written manually.
ISML tag | Velocity tag |
---|---|
isactivedatacontent | NONE |
isactivedatahead | NONE |
isanalyticsoff | NONE |
isbreak | #break inside a #foreach |
iscache | use Response.setExpires() and Response.setVaryBy() |
iscomment | comments in Velocity start with ## |
iscomponent | '<wainclude>' |
iscontent | use Response.setHeader('Content-Disposition') to set the content type, use $esc.html($VAR) to handle HTML escaping |
iscontinue | NONE |
iscookie | Response.addHttpCookie() |
isdecorate | NONE |
iselse | #if(CONDITION)true#else false#end |
iselseif | #if(COND1)true #elseif(COND2)more true#end |
isif | #if(CONDITION)true#else false#end |
isinclude | #parse for template includes <wainclude> for remote includes |
isloop | #foreach(ITERATOR) |
ismodule | NONE, use Velocity Macros. Calling ISMODULES from Velocity templates is not supported. |
isnext | NONE |
isobject | NONE |
isprint | $VAR syntax. For formatting, use the Velocity Tools |
isredirect | Response.redirect() |
isremove | NONE, removing variables isn't supported in Velocity |
isreplace | NONE |
isscript | NONE, scripting isn't supported in Velocity |
isselect | NONE, can be done with Velocity |
isset | #set |
isslot | NONE |
isstatus | Response.setStatus() |