0
votes

First of all, I'm a very newbie with Liferay.

It's been some days I'm scratching my head with this, but can't find anything for that, even if it seems easy at first look.

I'm creating a portlet with its own preferences for Liferay 6.2, and one of these preferences is required to be set in the <head> tag of the HTML generated by my FreeTemplate theme.

The most logic approach I was thinking of, is to create a variable from my portlet, so that it can be displayed in my theme, but I couldn't find any way to achieve this.

My current portlet's code:

HttpServletRequest request = PortalUtil.getHttpServletRequest(portletRequest);
Map<String, Object> var = new HashMap<>();
var.put("test", "Hello World");
request.setAttribute(WebKeys.VM_VARIABLES, var);

My theme code:

<#if test??>
    true: ${test}
<#else>
    false
</#if>

I keep getting false.

Is my approach wrong? If yes, what should I do? If it's not, how could I do that?

Note: I'm aware about FreeTemplate's <h:head>, but surprisingly, using it provokes the template to generate a second <head> tag in my <body>, which is, you'll agree, absolutely unacceptable. Maybe I'm not using it correctly?

Edit

To give more about my context, I'm currently working on a social sharing portlet that must allow 1) to share the current page and 2) to configure how the link will appear on Facebook/Twitter (using OpenGraph <meta /> tags). My first attempt was to put this configuration to the theme, but my customer absolutely wants it to be in the portlet.

2
If it is additional functionality (such as social sharing) which your customer wants to have in a portlet. You can also embed your portlet into the theme: See this blogpost about this: embedding-portlets-in-themes-on-liferay - Andre Albert
So, in my case, because OpenGraph mustn't be added via Ajax, I should use the method one, correct? - Deuchnord
I dont know OpenGraph in detail, but yes. I would render your markup server-side with $theme.runtime . Try something like this: #set ($VOID = $velocityPortletPreferences.setValue('display-style', '1')) #set ($VOID = $velocityPortletPreferences.setValue('portletSetupShowBorders', 'false')) $theme.runtime("yourdeployable_WAR_youportlet", '', $velocityPortletPreferences.toString()) #set ($VOID = $velocityPortletPreferences.reset()) - You will also find further info when search for "Liferay theme embed custom portlet" (sorry was not able to format comments) - Andre Albert
What is this velocityPortletPreferences? When I try to use it in my template, I get an InvalidReferenceException - Deuchnord
Sorry my fault. As you are using WebKeys.VM_VARIABLES i wrongly thought your are using Velocity-Markup. In your case there should be a freeMarkerPortletPreferences variable instead. It is used to embed your portlet without any portlet borders. Also note that "yourdeployable_WAR_youportlet" will be your Portlet ID - Andre Albert

2 Answers

1
votes

Yes, the approach is wrong. You can't assume the order of evaluation between a theme and a portlet - both are undefined in their execution (apart from both being executed), and while the output stream gives some hint on the most likely evaluation order, you can't rely on this.

Further, PortalUtil.getHttpServletRequest(portletRequest) will give you a PortletRequest wrapped into the interface of a HttpServletRequest, but not the underlying HttpServletRequest. There's another method (from memory) PortalUtil.getOriginalServletRequest(request) that would give you the underlying HttpServletRequest from the appserver (you'll need to chain both calls). However, there's no guarantee that the theme actually uses this one.

I tell you that to tell you this: What are you actually trying to achieve? Quite often, with a demand like this, there's a simpler way to do what you like. You're asking for alternative suggestions, but you're missing to give us a hint about your underlying problem. You're only outlining the solution (intent) you came up with so far.

Edit: Whatever is in the <head> area of a page belongs into the theme (or requires javascript to add it to the head-area). In your case it seems that this only applies to the current page - and that's possible.

IMHO everything that provides a user interaction belongs into a portlet - and your customer seems to see it just the same way. You can still add a portlet to the theme, so that it's always there, but in general you'll make your life easier to develop a theme with the sharing functionality, while adding the required metadata through the theme.

0
votes

The Theme template can/should not access variables of certain portlets which might be placed on a page with that Theme. If you want to add new Variables to the theme template, you can use a ServicePreAction and place your code:

Map<String, Object> var = new HashMap<>();
var.put("test", "Hello World");
request.setAttribute(WebKeys.VM_VARIABLES, var);

to the run(final HttpServletRequest request, final HttpServletResponse response) method. You need to Implement com.liferay.portal.kernel.events.Action and add your class to: servlet.service.events.pre in your portal properties