Adding custom classes to Theme Velocity context

To make some custom class available inside a theme velocity template, you need to put it's instance into com.liferay.portal.kernel.util.WebKeys#VM_VARIABLES request attribute. And it will be populated to the velocity context automatically (in com.liferay.portal.velocity.VelocityTemplateContextHelper#prepare method), see:

// Insert custom vm variables

Map<String, Object> vmVariables =
   (Map<String, Object>)request.getAttribute(WebKeys.VM_VARIABLES);

if (vmVariables != null) {
   for (Map.Entry<String, Object> entry : vmVariables.entrySet()) {
      String key = entry.getKey();
      Object value = entry.getValue();

      if (Validator.isNotNull(key)) {
         template.put(key, value);

To achieve this, you can use custom service pre action:

Inside this action you can put required objects into WebKeys#VM_VARIABLES request attribute map:

public class VMPopulateServicePreAction extends Action {

    public void run(HttpServletRequest request, HttpServletResponse response) {
        Map vmVariablesMap = (Map) request.getAttribute(WebKeys.VM_VARIABLES);
        if (vmVariablesMap == null) {
            vmVariablesMap = new HashMap<String, Object>();
        vmVariablesMap.put("categoryService", new CategoryServiceImpl());
        request.setAttribute(WebKeys.VM_VARIABLES, vmVariablesMap);


And now you can use those object in your theme, like:

#set ($categoryNav=$categoryService.getCategoryNav($categoryId))

Hope, this will help smiley


That's a great and easy to miss detail. Thanks.

It'd be even better if the demo code had a @Reference to the CategoryService, rather than instantiating a new object (assuming that this is Liferay's CategoryServiceImpl or follows the ServiceBuilder best practices. In fact, I'd expect that you won't have access to CategoryServiceImpl anyway.