Preferences for embedded portlets in Freemarker

4 minuten lezen

For as long as I know Liferay, it has been possible to embed portlets in Freemarker and Velocity templates, be it in your own MVC portlets, or in themes.
Since DXP 7.1 I guess, the syntax has changed a little due to some reordering of macros, taglibs etc, but the concept has stayed the same.
It works, and it's not that hard to use (even though there's a myriad of community forum threads about perceived complexities... :-) )

One clunky thing of configuring these embedded portlets however, is the way you have to pass preferences to them.

If you have used embedded portlets yourself, you are probably familiar with this.
First a few weird assignment statements, then the actual portlet rendering, and then some kind of reset statement.

In Velocity this looks like:

#set ($VOID = $velocityPortletPreferences.setValue("includedLayouts", "auto"))
#set ($VOID = $velocityPortletPreferences.setValue("displayStyle", "[custom]"))
#set ($VOID = $velocityPortletPreferences.setValue("nestedChildren", "1"))
#set ($VOID = $theme.runtime("71_INSTANCE_MAIN", "", $velocityPortletPreferences.toString()))
#set ($VOID = $velocityPortletPreferences.reset())

Or its counterpart in Freemarker:

<#assign VOID = freeMarkerPortletPreferences.setValue("portletSetupPortletDecoratorId", "borderless")>
<#assign VOID = freeMarkerPortletPreferences.setValue("displayStyle", "ddmTemplate_838501")>
<#assign VOID = freeMarkerPortletPreferences.setValue("displayStyleGroupId", "10180")>
<@liferay_portlet["runtime"]
  defaultPreferences="freeMarkerPortletPreferences"          
  portletProviderAction=portletProviderAction.VIEW          
  portletProviderClassName="com.liferay.portal.kernel.servlet.taglib.ui.BreadcrumbEntry"     />
<#assign VOID = freeMarkerPortletPreferences.reset()>

(Examples taken from the community forums)

Apparently in 6.2 and below this was the only way to get a set of preferences that could be used in an embedded portlet declaration.
The template variable freeMarkerPortletPreferences is an instance of TemplatePortletPreferences and in 6.2 and before that was quite a limited implementation (TemplatePortletPreferences branch 6.2 in Github).
In effect, it took a number of void method calls to set some values, and afterwards you had to reset() because the freeMarkerPortletPreferences object is shared and the same preferences would be left over for other portlets/theme invocations, possibly causing nasty side effects.

But the good news is: in 7.0, this class has been revamped and now you can actually have a lot cleaner way of defining a set of preferences. (TemplatePortletPreferences branch master in Github)

Instead of altering the shared variable freeMarkerPortletPreferences and resetting it, you can now use it as a util and retrieve fresh instances of preferences from it. Use it like this:

<#assign myPreferences = freeMarkerPortletPreferences.getPreferences({
  "portletSetupPortletDecoratorId": "barebone",
  "groupId": theme_display.getCompanyGroupId()?string,
  "articleId": myArticleId
}) />
<@liferay_portlet["runtime"] defaultPreferences="${myPreferences}" 
 portletProviderAction=portletProviderAction.VIEW
 portletName="com_liferay_journal_content_web_portlet_JournalContentPortlet" />

Yup, that's right, you can even pass a native Freemarker hash to getPreferences().
This is probably the most used form, because in most cases, more than 1 preference has to be set. But there is another convenience method in freeMarkerPortletPreferences:

<#assign myPref = freeMarkerPortletPreferences.getPreferences("groupId", "20152") />

So in case of 1 preference, you can pass key and value as separate string arguments.

There is no shared state between invocations, the class TemplatePortletPreferences has no instance variables anymore. And therefore the reset() call also is not necessary anymore.

Liferay's documentation silently started using the new syntax, from 7.1 onwards. But one thing to note is that the old way (using setValue(), setValues() and reset()) all got deprecated in 7.0 and were actually removed in 7.2. Without mention in the lists of Breaking Changes. So it would have been nicer had Liferay themselves draw some attention to it...

Conclusions

  • In your templates, never use the old clunky way of setting portlet preferences anymore, but use the cleaner and more concise way with getPreferences(). Available since 7.0, mandatory since 7.2
  • Liferay, please update the existing documentation for 7.0+ to reflect this better

Further information

Meer weten

Geert van der Ploeg

Solution Architect[email protected]LinkedIn
Meer van Geert van der Ploeg

Meer artikelen

liferay
dxp
freemarker
fragments
webcontent

Using Liferay Fragments as modular webcontent templates

Danielle Ardon
9 minuten lezen
Lees het artikel Using Liferay Fragments as modular webcontent templates
liferay
dxp
theme
inheritance

Liferay themes with a custom base theme

Geert van der Ploeg
6 minuten lezen
Lees het artikel Liferay themes with a custom base theme
drupal
decoupled

Decoupled Drupal — The holy grail! Or not!

Fabian de Rijk
18 minuten lezen
Lees het artikel Decoupled Drupal — The holy grail! Or not!