Ask Questions and Find Answers
Important:
Ask is now read-only. You can review any existing questions and answers, but not add anything new.
But - don't panic! While ask is no more, we've replaced it with discuss - the new Liferay Discussion Forum! Read more here here or just visit the site here:
discuss.liferay.com
RE: Rendering custom navigation menus in theme
I've made a custom Liferay Theme and by default it will render the navagation.tpl based on the site pages. I want to change that to leverage the Navigation menus that are custom built in the interface and designated as Primary/Secondary/Social, and bake them into the theme in the Freemarker templates. I can't seem to find any examples of how to accomplish that, and I'm struggling to find where navigation_menu portlet is documented or where the code resides in Github.
- Can the navigation_menu portlet be told what Navigation to render?
- Can I load the list of navItems for the navigation.tpl to process differently so that it is based on the custom Navigations instead of the site pages?
Hi,
You can add navigation portlet and configure which all pages needs to be shown in it and also build freemarker template for customising UI.
Can the navigation_menu portlet be told what Navigation to render? - You need to set this in navigation portlet configuration
Can I load the list of navItems for the navigation.tpl to process differently so that it is based on the custom Navigations instead of the site pages? - For this u have to add the navigation portlet onto the page and select type of navigation menu and template for UI (U can define your own template )
For Embedding Navigation Menu in theme u can use
<@liferay.navigation_menu default_preferences="${preferences}" />
You can add navigation portlet and configure which all pages needs to be shown in it and also build freemarker template for customising UI.
Can the navigation_menu portlet be told what Navigation to render? - You need to set this in navigation portlet configuration
Can I load the list of navItems for the navigation.tpl to process differently so that it is based on the custom Navigations instead of the site pages? - For this u have to add the navigation portlet onto the page and select type of navigation menu and template for UI (U can define your own template )
For Embedding Navigation Menu in theme u can use
<@liferay.navigation_menu default_preferences="${preferences}" />
Hey Jeff,Embedding the portlet in the theme, along with the portlet preferences , as Mohammed has suggested, will in fact add the portlet with said configuration to all the pages. Note that there are some nuances with embedded portlets and preferences so if you go this route and have problems setting or updating those preferences, come back here. If there is a case however where you need to have the portlet on several pages, with several configurations, then you are possibly stuck with a manual configuration. With that said, if your scenario is one where you have "3 use cases" .. so I need it configured one of these 3 ways on any given page, then I would maybe try using a Page templates. You could create a page template for each of your (3) scenarios and then within each template you configure the navigation menu accordingly. When you create a new page moving forward, choosing from one of those templates will control how the menu is rendered for that page. Make sense?
I've used what Mohammed suggested to get closer. I can now load the navigation portlet and have it load a specific navigation. The next piece of the puzzle for me was to try to tell it to use one of the OOB templates. That I have unfortunately not been successful with. My code is thus:
<#assign preferencesMap2 = {"displayDepth": "1", "portletSetupPortletDecoratorId": "barebone", "siteNavigationMenuId": "38338", "displayStyleGroupId": "20127", "displayStyle": "LIST-MENU-FTL"} />
<@liferay.navigation_menu
default_preferences=freeMarkerPortletPreferences.getPreferences(preferencesMap2)
instance_id="footer_navigation_menu_2"
/>
My biggest challenge right now is figuring out what the preferences are and how to set them correctly. I've tried using "ddmTemplate_LIST-MENU-FTL" as the value for the displayStyle without success. Are those preferences documented anywhere for what the options are and how to set them? Are there any code examples that set the display template for the navigation in this manner?Just to get ahead of myself a bit, is it possible to use the Resources Importer or Site Initializer (since it appears the importer is deprecated in 7.2 where I am running) to preload my primary and footer navigation?
Hey Jeff,
You're getting closer! You're at the part that most people get stuck on here. Two things -- let's start with getting the preferences.
1. Create a new page called test
2. Navigate to that page and configure the portlet the way you want (decorator, menu, template etc)
3. Go to your database and SELECT * FROM Layout where friendlyURL like '%/test%';
4. The result should have a PLID in it -- copy that number and then run a second query
5. SELECT * FROM PortletPreferences where plid = <plid>;
6. You will likely have multiple rows .. find the one that references your portlet, and copy the "<preferences/>" value out of the column
7. I use an online XML formatter to make it readable
8. Now you can see the key/value pairs you need
Ok, that's part 1. Part 2 now. Because you have embedded a portlet in the theme, any page you have already gone to has now created this record in the database. The records are only ADDED if they are missing, there no sync for checking to make sure that the embedded values match the preferences record. So when you CHANGE the preferences that have been embedded, you need to nuke the existing portlet preferences.
!!DISCLAIMER!! THIS IS ONE OF THE FEW TIMES I WOULD RECOMMEND YOU TAKE ANY DIRECT DATABASE UPDATE/DELETE ACTION. YOU SHOULD ALWAYS USE THE API FIRST!!
OK, big red text out of the way.
1. Update the theme with your new preferences based on part 1
2. Go back to the database and run a DELETE FROM PortletPreferences WHERE portletId = ""; // the portlet id should be the same on every page (plid record but you could do a SELECT * before the DELETE to be sure)
3. Once the records are dumped you need to also clear the caches -- go to Control Panel > Configuration > Server Administration
4. Clear the caches you see there -- I just clear them all to be safe, but I think the Database one is the only one you "need" to do.
5. Deploy your theme
Now every page you go to should have your new configuration. If you messed it up, rinse and repeat.
You're getting closer! You're at the part that most people get stuck on here. Two things -- let's start with getting the preferences.
1. Create a new page called test
2. Navigate to that page and configure the portlet the way you want (decorator, menu, template etc)
3. Go to your database and SELECT * FROM Layout where friendlyURL like '%/test%';
4. The result should have a PLID in it -- copy that number and then run a second query
5. SELECT * FROM PortletPreferences where plid = <plid>;
6. You will likely have multiple rows .. find the one that references your portlet, and copy the "<preferences/>" value out of the column
7. I use an online XML formatter to make it readable
8. Now you can see the key/value pairs you need
Ok, that's part 1. Part 2 now. Because you have embedded a portlet in the theme, any page you have already gone to has now created this record in the database. The records are only ADDED if they are missing, there no sync for checking to make sure that the embedded values match the preferences record. So when you CHANGE the preferences that have been embedded, you need to nuke the existing portlet preferences.
!!DISCLAIMER!! THIS IS ONE OF THE FEW TIMES I WOULD RECOMMEND YOU TAKE ANY DIRECT DATABASE UPDATE/DELETE ACTION. YOU SHOULD ALWAYS USE THE API FIRST!!
OK, big red text out of the way.
1. Update the theme with your new preferences based on part 1
2. Go back to the database and run a DELETE FROM PortletPreferences WHERE portletId = ""; // the portlet id should be the same on every page (plid record but you could do a SELECT * before the DELETE to be sure)
3. Once the records are dumped you need to also clear the caches -- go to Control Panel > Configuration > Server Administration
4. Clear the caches you see there -- I just clear them all to be safe, but I think the Database one is the only one you "need" to do.
5. Deploy your theme
Now every page you go to should have your new configuration. If you messed it up, rinse and repeat.
This was very helpful and got me to where I needed to be, just not fully the way you describe. The fact that the database retains my preferences explains why my displayStyle changes never took effect -- I had added that after deploying the theme with the "siteNavigationMenuId" figured out. My challenge is that I am developing locally using the in-memory Hypersonic DB, so querying that is a tough nut to crack.
Instead, now knowing that the preferences get added to the DB for the portlet, I changed the instanceId for my portlet and BAM! the displayStyle I wanted took effect. I might make a build ID datestamp part of the instanceId for this portlet just to help me remember if I make a preferences change I need to do some cleanup.
Instead, now knowing that the preferences get added to the DB for the portlet, I changed the instanceId for my portlet and BAM! the displayStyle I wanted took effect. I might make a build ID datestamp part of the instanceId for this portlet just to help me remember if I make a preferences change I need to do some cleanup.
Hey Jeff,That's one option for sure. An alternative that I have used in the past is I have actually stored a "version" with the preference and then in the template added the logic to check the version variable in the theme against the portlet preference. Its a touch more processing but it did mange automagical updates without creating orphaned records. That's the only thing to note with you approach -- it will leave dead records lying around in the database -- AND, I think that would only work for instanceable portlets. If you were to use the same embedded technique in the future with a non-instanceable portlet, you'd actually be stuck with orphaned portlets. At any rate, glad to hear you got it solved.

Andrew that's interesting, can you expound on that solution a little bit more? I'm missing something in your description in how it prevents or cleans up the orphaned rows. When you say "template" are you referring to the .ftl in the theme or a Page Template or something different altogether?
Hey Jeff,I haven't done it for years to be honest -- I think the last time I used it was 6.2 but it was something like this. 1. In your FTL file, just before you embed your portlet -- use an <#assign version = 1/> .. now leave it for a minute2. Write the code to embed the portlet, but make sure you add a key-value-pair that will add "version": version .. so that you store the version you assigned above with the portlet preferences3. Test it out and make sure (using the db) that it is being stored 4. Now, go back to the template file. Basically what you want to do is use the portletpreferences service (its a service builder guy - so I think PortletPreferencesLocalService is something you can get a handle on with the serviceLocator) to get the preferences for the portlet that you are trying to embed.5. IF you get a result, it means the portlet has been embedded already. If you have a result, then you can check the stored version on the preferences, against the number in the assign statement, and if they are not the same, you update the preferences and set the version on the preferences to match your freemarker var. It was a long time ago so I can't recall if I updated the preferences, or I deleted the record.
Anyway, it was something like that but I certainly am not going to win any awards for my fantastic memory and God knows where the source for THAT project is now lolFreemarker + service locator is pretty powerful though. I bet you could do something like that. The only gross part will be that you have to work with XML as that is how the preferences are stored (barf).
Anyway, it was something like that but I certainly am not going to win any awards for my fantastic memory and God knows where the source for THAT project is now lolFreemarker + service locator is pretty powerful though. I bet you could do something like that. The only gross part will be that you have to work with XML as that is how the preferences are stored (barf).
Slightly off topic but 7.2 has seemed to ignore the fact that there is a "global site" in which things like shared and globally needed things like navigation menus could be placed. There are no navigation menus in the global site ... will this finally be fixed in 7.3?
Copyright © 2025 Liferay, Inc
• Privacy Policy
Powered by Liferay™