Embedding portlets in themes on Liferay

Liferay has long had the ability to embed portlets in themes. This is convenient for implementors to get highly functional design into the look and feel of a site. In my years at Liferay I've seen and heard many different attempts at doing this with various levels of success. There are a number of things to consider when embedding portlets in the theme and the same method does not apply in all cases.

The original motive behind embedded portlets was for integrating WCM content or simple functional features such as Search or Language selection. As such the complexity of these portlets was understood to be low and without significant performance costs either due to not having any direct service calls (search & language selection portlets don't have any initial service calls), or having service calls which were highly cached (such as is the case with web content).

There is more than one technique for embedding portlets into the theme, and several different issues to consider when choosing any of those.

Method One: Using $theme.runtime()

This is by far the most common method. There are of course a few gotchas with this method.

1) it renders the portlet synchronously in the theme regardless of the ajaxable settings on the portlet ( via liferay-portlet.xml).

This means if the portlet is expensive to render because it a) has lots of data to process on render, b) uses synchronous web service calls, or c) calculates the fibonacci sequence up to a million, DON'T EMBED IT IN THE THEME! You're just killing the performance of your portal whenever that theme is on any page.

Rule of Themes #1: This is a good rule of thumb to follow regardless of embedded portlets or not: "Themes should be SUPER FAST! They should be the fastest component of your portal view at any given time."

If you don't follow this rule how will you expect the experience to be once you start actually putting more things on the page? It's a different topic entirely, but you should generally performance test your theme with no portlets on the page. Once you know it's blazing fast then proceed to test your portlets' performace.

But I digress! Back to portlets embedded in the theme.

2) portlets rendered in the theme don't have their js/css resources loaded at the top of the page with all the rest of the portlets. Liferay doesn't yet implement "streaming portlet" mode (this is optional in the spec, this doesn't mean Liferay is not fast, it's just a name they chose for the feature of calling the portlet's header altering methods separately from the rendering methods). So the issue with this is that if you embed a portlet that uses something like JSF dynamic javascript features and there happens to be more than one of this type of portlet on the page, the ordering of these dynamic resources may get fouled up and cause general mayhem to their behavior.

On the other hand, I would argue that such portlets are already, by their very nature, TOO complex and expensive to be embedded in the theme. They are quickly diverging from the rule above that the theme should be SUPER FAST!

Rule of Themes #2: "Only use $theme.runtime() to embed portlets that are extremely fast. If they make expensive service calls, MAKE SURE those are not calls that happen all the time, and MAKE SURE they use great caching."

 

Method Two: Ajax / Iframe!

This is a "currently" seldom used method, but one that I would HIGHLY recommend using! Why?

1) It's Asynchronous with the rendering of the theme. This is HUGE! It means that regardless how slow your portlet(s) is(are), the general experience of the portal will remain fast!

2) It means that you can still put that fairly complex portlet into the theme without killing the overall performace.

3) It doesn't suffer from the limitation of the resource loading that the $theme.runtime() method suffers from.

So how do I do it?

Ok, so generally what you do to embed a portlet via ajax or iframe is to create a portlet url (either server side or client side) and then request for it, placing it somewhere in the page. With an iframe you can of course interact with the portlet in place. If you use an ajax call and embed the output of the portlet directly it will of course cause page refresh.

Here is the code for doing it with the iframe:

 

One thing you'll note with this code is that it's making the assumption that the portlet is at the current page! But it's not on the current page yet!

There are a couple of ways of handling this.

1) The portlet is specifically designed to be in the theme and should be visible to anyone seeing the page.

In this case I recommend setting these attributes in your liferay-portlet.xml file:

These will allow your portlet to safely added to any page in the portal automatically (otherwise you may get permission issues because the user viewing the portlet may not have permission and all that jazz.)

2) You can't do as above because you still want to control permissions of the portlet using roles.

In this case, you'll have to add the portlet to something like a hidden page, from which you can manage it's permissions. When creating the url in the code above, you'll then use the page "plid" of that target page instead of the current one.

 

Well, I hope that helps!

I hope that I hear far less talk about $theme.runtime()issues and Liferay performance problems that end up being directly related to expensive operations embedded in the theme.

 

And please heed these words:

"Embed portlets with impunity! Just make sure to do it carefully!"

Blogs
Right now I embed portlets in the theme because I haven't found an easy way to "nest" portlet pages so to speak. Say you have a sidebar that contains the same portlets over 30 pages. You don't want to define these same 30 portlets on all the pages. To my knowledge using themes is the only way to avoid this. Are there any plans to come up with a solution for this ?
I don't believe I suggested NOT to embed portlets! In fact I clearly stated "Embed portlets with impunity! Just make sure to do it carefully!" which means DO embed portlets in themes, just make sure to consider the consequences and use the appropriate method for the type of scenario you are planning.
yes that point was quite clear. Let me rephrase my question. The gist of your post is that portlets that take a while to render will cause performance problems when embedded in a theme. Suppose you have a sidebar that is common across 30 pages and it contains a portlet that calculates the fibonacci sequence to 1 million. Then basically using iframes / ajax right now is your only option to make things perform. But there are many reasons why one may not want to do this, seo being one of them. So i was wondering if something is in the works for this. I guess what i am really hoping for is something like apache tiles. that lets you nest and extend layouts. Using themes for this kind of stuff always felt like a hack. Right now it feels like liferay is missing a concept
We have several arguments for this!

1) Simply create a re-usable Page Template.
2) Unless the portlet is the main focus of the page how does SEO become an issue? Also, why does an iframe play a lesser role in SEO? There are two main points here, The URL used for the iframe is as likely to have as much meaning as any other link in the page. Second, using portlet friendly url router for your portlet is also usable in this case as any other, so the iframe will have a meaningful url. Sure the content is not inline, but I don't see the purpose of having expensive portlets that are NOT the focus of the page have significant weight on the SEO of the page to begin with.
3) Why not cache the result of the portlet and re-use it for some time? Even if the portlet is expensive, if you want it's SEO weight to be high, then SURELY you are not changing it so frequently from the page! It must have some direct correlation with the rest on the content of the page in order for SEO to be a relevant argument in my opinion.
4) SEO is never user relative! There is no point because in that case the search bots would behave as a different user and the search engine would have irrelevant results that are not searchable for anyone else! Again, this means that you can either cache the output, or take the content out of line!
The problem with page templates is that applying them is a one off. All the portlets defined in the page template are copied to the page but if the
page template changes afterwards, all pages based on it do not change automatically. To work around this I sometimes embed portlets in the theme

I brought up SEO as just one of many possible reasons why you may not want to use an iframe / ajax based solution. I think the argument is valid if
you're taling about say an rss portlet or perhaps the new "related assets" portlet where the content is meaningful to the page.
And sure often caching can be employed as a workaround.

But I think it would be a lot nicer if other solutions where available that don't make it as easy to shoot yourself in the foot.
Even something as simple as named static layouts that you could assign to a page would go a long way
Liferay also has "copy page" ability... with a single selection you could create your new pages derived from any other existing page in the site!

It doesn't solve the change management issue.

We will have Page Template change management/propagation (not the official name I'm sure) in 6.2.

We already have it in 6.1 for Site template change management/propagation. Perhaps that may help somewhat.

I do see your point! But as you say, it's just not something we've implemented yet.
Yes i am familiar with copy page. A particularly nasty piece of functionality from a usability standpoint. I have yet to come across someone that has not inadvertedly changed the webcontent on the page the content was copied by editing the webcontent on the copied page. But I digress. Yes it also does not solve the change management issue.

So I guess i'll have to wait for 6.2 , but it's good to know it's being worked on. Thanks for the update!
I'm having difficulties understanding why you want to use an iframe here. Why not just create a normal portlet with a fast renderMethod, and then do all the heavy lifting through an ajax-call to a resourceMethod in the portlet. It would achieve the same performance benefits without the extra complexity (and possible usability issues) of an iframe would it not?
Forgot to mention: the ajax call could be done on dom ready. We are currently doing this with some of our portlets that are not embedded in the theme.
@Kyrre, You're absolutely correct!

"Method Two: Ajax / Iframe!"

Any technique that avoids heavy synchronous processing should work! Iframe is simply the easiest for existing portlets. I as I was impling above you could even load those using AJAX with a slight alteration to the example code I provided.
I am not sure of what i am asking makes sense, but can we do other way round where i can have specific themes for my specific portlets configured in my portlet itself.
@Ray : what about redirecting issue from Iframe something like this http://www.liferay.com/community/forums/-/message_boards/message/13967650
Hello Ray, this is quite useful, but can we have the freemarker syntax version?
Hallo!

i try to embedding assetPublisher portlet in my Theme. But this portlet will be showed only if I logged in system. can I change permission for guest-users?
Hi Ray,
Many thanks for your posts,is it possible put multiple portlets in one IFrame ?
I tried your iframe method for Language portlet, It embeds well into theme. But it does not work as expected. It just refreshes the page but does not translate the page. So, purpose of embedding language portlet is defeated.