Embedding portlets and setting preferences in a Liferay 7.2 theme

How to embed a Navigation Menu portlet in a theme's freemarker template and set portlet preferences

I recently came across a requirement to embed a Navigation Menu portlet in a Liferay 7.2 theme and to make the navigation display a specific set of pages.

Here are the steps that I took to accomplish this task:

  • As an Administrator, go to the Control Panel and click on Site Builder > Pages
  • Added three widget pages: P1, P2, and P3
  • Clicked on "Go to Site" and then added a "Navigation Menu" widget to the home page
  • Added a new navigation menu named "MyMenu" and added P1, P2, and P3
  • Clicked on the "..." ellipses for the portlet and click on "Configuration"
  • Clicked on the "Choose Menu" radio button
  • Clicked on the "Select" button and clicked on "MyMenu"
  • Clicked on the "Save" button

At this point the navigation menu looked like the following:

When I clicked the "Save" button, Liferay persisted some portlet preferences to the database. Knowing this, I shut down the portal in order to look at the $LIFERAY_HOME/data/hypersonic/lportal.script database in order to find out what the preferences looked like.

WARNING: Looking directly in the Liferay database isn't a best practice. I only show it here to help the reader understand what's going on behind the scenes. Olaf Kock developed the layout-info-web module that you can use to read the portlet preferences for everything on a page. You can also find out the preference names in the OSGi configuration Java source. For example:

After viewing the lportal.script file and searching for "MyMenu", I found this:

INSERT INTO SITENAVIGATIONMENU VALUES(0,'46b6d781-ed21-8c5d-dd36-6518a89bc1e1',36622,35019,20101,20130,'Admin User','2020-05-01 17:07:20.523000','2020-05-01 17:07:20.523000','MyMenu',0,'1',NULL)

I took note of "36622" as the primary key and then searched the file for that value:

INSERT INTO PORTLETPREFERENCES VALUES(1,36621,20101,0,3,18,'com_liferay_site_navigation_menu_web_portlet_SiteNavigationMenuPortlet_INSTANCE_RjnkBjOsupLW','<portlet-preferences><preference><name>displayStyle</name><value>ddmTemplate_NAVBAR-BLANK-FTL</value></preference><preference><name>siteNavigationMenuId</name><value>36622</value></preference><preference><name>displayDepth</name><value>0</value></preference><preference><name>rootMenuItemType</name><value>absolute</value></preference><preference><name>siteNavigationMenuType</name><value>-1</value></preference><preference><name>expandedLevels</name><value>auto</value></preference><preference><name>rootMenuItemLevel</name><value>0</value></preference><preference><name>displayStyleGroupId</name><value>35019</value></preference></portlet-preferences>')

With this information, I learned exactly which portlet preference name+value pairs that I needed for my embedded navigation portlet.

The next step was to create a custom theme:

npm install -g yo
yo liferay-theme

After setting the theme name, Liferay version, etc. the aforementioned command generated a theme project for me.

I then copied node_modules/liferay-frontend-theme-unstyled/templates/portal_normal.ftl to src/templates/portal_normal.ftl and modified it with the following:

        <#assign myNavPrefs = freeMarkerPortletPreferences.getPreferences({"displayStyle": "ddmTemplate_NAVBAR-BLANK-FTL", "siteNavigationMenuId": "36622", "displayDepth": "0", "rootMenuItemType": "absolute", "siteNavigationMenuType": "-1", "expandedLevels": "auto", "rootMenuItemLevel": "0", "displayStyleGroupId": "35019"}) />

After deploying the theme with gulp deploy I was able to apply the theme to my site, and the Navigation Menu portlet appeared on every page.




Instead of looking at the database: Look at this: i.e. use the API to read the portlet preferences for everything on a page. Looks ugly (as you can expect), but gets the job (of extracting the information) done.


I'd be interested to  know if this works for the global navigation menus so that all pages can have the same footer navigation without using fragments on each page.

Olaf, is there a replacement for <#assign VOID = freeMarkerPortletPreferences.reset()> this no longer seems to work and throws an error.