A PHP Error was encountered

Severity: Notice

Message: Undefined variable: flickr_photo

Filename: models/flickr_model.php

Line Number: 25

Two ways to embed web content in Liferay themes - Blog - Webdesign E-KON
No Dutch
Startpagina » Blog » Two ways to embed web content in Liferay themes Share/Bookmark

Two ways to embed web content in Liferay themes

Op 01 juni 2011 door Kristof Verbraeken in categorie Liferay


Sometimes a client needs to be able to modify web content that appears on multiple pages. In some occasions you just can’t put the web content in the right place using the “basic” WCM features like Layout Templates and/or Journal Templates.

Consider things like a short introduction text in a header, a doormat, a footer, static navigation menu’s that rarely need to be updated, places for banners for temporary promotions and so on. What all these things have in common is that they don’t fit in the scope of Layout Templates or Journal Templates. You can’t reach the places I mentioned before with those facilities, because they mostly reside somewhere in the theme itself.

In this blog post/tutorial I will demonstrate and explain 2 ways to embed web content in a Liferay theme — using a demo theme which you can download below!

Demo theme

Take a look at the screenshot below:

The layout (theme) is made up out of four important areas:

  1. header: the area in the top of the layout;
  2. footer: the area in the bottom of the layout;
  3. sidebar: the area in the right center of the layout;
  4. content: the area in the left center of the layout. The layout of this area is determined by the configured Layout Template.

The first three areas (header, footer and sidebar) are the ones that should contain embedded web content which can be edited by the client through the Liferay Control Panel.

Create a journal article (or web content) for every area first as I have done in the screenshot below:

Note that I have used alphanumeric ID’s for the journal articles listed above instead of generated (numerical) ID’s. I will explain later why I’ve done that.

First way (complex)

The first way is based upon embedding the Web Content Display portlet: this portlet comes out the of box with Liferay.

Below is the configuration file (liferay-look-and-feel.xml) of the demo theme.

I’ve added the journal article ID of every journal article I need to embed in the theme (they are added as theme settings).

There’s also an extra setting portlet-setup-show-borders-default configured to hide the portlet wrapper of the embedded Web Content Display portlets.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE look-and-feel PUBLIC "-//Liferay//DTD Look and Feel 5.2.0//EN"
	<company-includes />
	<company-excludes />
	<theme name="Demo" id="demo">
	<setting key="portlet-setup-show-borders-default" value="false" />
	<setting key="header-article-id" value="HEADER" />
	<setting key="sidebar-article-id" value="SIDEBAR" />
	<setting key="footer-article-id" value="FOOTER" />

Next you need to add some Velocity code to the init_custom.vm file in the templates directory.

In this example I will only embed the sidebar as a separate Web Content Display portlet.

#set ($portletSetupShowBordersDefault = 
#set ($sidebarArticleId = $theme_settings.getProperty("sidebar-article-id"))

In this Velocity template the theme settings are loaded as Velocity variables.

When this file is set, we can proceed to the last step: modifying the portal_normal.vm file. In this file the init_custom.vm is executed thanks to the following statement:

#parse ($init)

The needed variables are injected in the theme and now we have all the information available that is needed to embed the web content.

You can now embed the web content with the following Velocity code:

$velocityPortletPreferences.setValue("group-id", "$group_id")
$velocityPortletPreferences.setValue("article-id", "$sidebarArticleId")
$theme.runtime("56_INSTANCE_a0b1", "", $velocityPortletPreferences.toString())
#set ($VOID = $velocityPortletPreferences.reset())

First we need to configure the portlet preferences for the portlet we’re about to embed.

  • $portletSetupShowBordersDefault: injected setting from the XML configuration. This setting hides the portlet borders.
  • $sidebarArticleId: injected setting from the XML configuration. This variable contains the journal article ID of the sidebar.
  • $group_id: this variable is automatically set in the theme and contains the community ID.

Next, the portlet is embedded using the runtime method of the variable $theme. Notice that you have to provide this method with a portlet namespace, which in this case is 56_INSTANCE_a0b1. Make sure that this namespace always starts with 56_INSTANCE_ or else Liferay might embed a wrong portlet!

Notice the last line of code: the portlet preferences are reset. Always reset your portlet preferences after embedding the Web Content Display portlet or else you might get duplicate content in your theme! Also make sure that the portlet namespaces are unique within a page.

You might wonder why I’ve added all the variables as theme settings first. This approach makes the theme configurable. If something needs to be changed afterwards, you don’t need to modify the Velocity code, but just reconfigure the theme through the XML file liferay-look-and-feel.xml.

Also notice that I’ve used alphanumerical ID’s instead of numerical (generated) ID’s. I highly recommend using alphanumerical ID’s over the generated ones, simply because the generated ID’s might be different between other environments (development, integration, staging, production). If you use alphanumerical ID’s you don’t need to reconfigure the theme for every environment.

You can disable auto-generating ID’s with the following setting in portal-ext.properties:


So far for the first way!

Second way (simple)

The second way makes use of the Liferay services. Instead of embedding a whole portlet in the theme we just load the web content to embed in the HTML of the theme.

The theme configuration was already discussed in the first way. In this explanation that same configuration is used again.

The init_custom.vm file must be modified again. In this example I will embed the header and footer content through this alternative way.

Take a look at the new content of the init_custom.vm file:

#set ($headerArticleId = $theme_settings.getProperty("header-article-id"))
#set ($footerArticleId = $theme_settings.getProperty("footer-article-id"))
#set ($headerContent = $journalContentUtil.getContent($group_id, $headerArticleId,
null, "$locale", $theme_display))
#set ($footerContent = $journalContentUtil.getContent($group_id, $footerArticleId,
null, "$locale", $theme_display))

Again, the theme settings are loaded as Velocity variables. Next, the web content service (JournalContentUtil) is used to load the content through the getContent method.

This method accepts 4 arguments:

  1. $group_id: the community ID of the web content article.
  2. $article_id: the web content article ID.
  3. $template_id: the web content template ID. You are free to use any web content template that is associated with the web content structure used by the article.
  4. $locale: the portal locale (which is set by default).
  5. $theme_display: the theme display object (which is set by default).

This web content is immediately set as Velocity variables.

Now in the portal_normal.vm file you just have to put these content variables in the right place and we’re done!

<div id="header">$headerContent</div>


<div id="footer">$footerContent</div>

That’s it for the second (simpler) way!


Both ways are very efficient and clean ways to embed web content in Liferay themes.

The second way is simpler than the first way, but you will not be able to embed the web content with the portlet wrapper. If this wrapper is needed or useful for any reason, I suggest you to use the first way.

In all the other cases, I recommend using the second (simpler) way.

Feel free to ask questions and don’t hesitate to download the demo theme below! This theme contains all the code discussed above.



The two ways described above are applied in the demo theme which you can download below! Make sure to create three web content articles with ID’s HEADER, SIDEBAR and FOOTER. If these articles don’t exist, Liferay will tell you that the content is expired.


Radoone ()

I tried your theme or modify my theme according this setup. But I hasn't luck on Liferay 6. Do you know what must be different, or how to change to work on liferay 6 Thank you

senja ()

i have a liferay portal and i give a sample web id for sample, but i didn't have idea how to change that web id for a seond time..
do you have idea/??

Kristof Verbraeken ()


I wrote this blog post from our own experiences with Liferay Portal. We haven't done a Liferay Portal 6 implementation yet...

I took some to install Liferay Portal 6.0.6 on a JBoss Application Server and started playing with the plug-ins SDK though.

I've created a theme for Liferay Portal 6 with embedded web content according to the methods I provided above. I did not cross any problems with these methods. I could just use the snippets above as I (or you) would do in Liferay Portal 5.



You can download this Liferay 6 compatible theme I've created here:


Also pay attention to the syntax of the snippets and especially the typecasts! Take a look at the JournalContentUtil service... If you don't pay attention to the typecasts there, that line will fail without you noticing it.


I'm sorry to say this, but I really don't understand what you mean?


Merci beaucoup j'en avais vraiment besoin, ça etait très util pour moi.

Je veux juste savoire comment vous avez pu faire pour utiliser un ID alphanumérique pour vos portlet, je n'arrive pas.

et SVP comment je peux faire pour integrer ma propre portlete que j'ai developpé avec PluginSDK par example.



Thank you very much I needed it, it was very useful for me.

I just want to know how you were able to use an alphanumeric ID for your portlet, I can not.

and please how can I do to integrate my own portlets that I developed with PluginSDK for example.


Kristof Verbraeken ()

Hello NAJAR,

I presume you're talking about this line of code:

$theme.runtime("56_INSTANCE_a0b1", "", $velocityPortletPreferences.toString())

The first parameter of the runtime method of the theme object is the portlet namespace.

As you can see, this namespace is made up different parts, in this example:

# 56: the portlet ID, which in this case is the portlet ID of the Web Content Display portlet.
# INSTANCE: this is always included in the portlet namespace.
# a0b1: this is added to create a unique portlet namespace on every page.

For example: if you want to embed 2 Web Content Display portlet in one theme, you have to make sure that their portlet namespaces are unique (different from each other) and the runtime method should still be able to recognise which portlet to embed. In this case both portlet namespaces would start with "56_INSTANCE_" while the last characters should make them unique, for example "56_INSTANCE_a0b1" and "56_INSTANCE_c3d4".

To embed your own custom portlets you can also use this way. Just replace the "56" in the example above with your custom portlet ID. If you're using portlet plug-ins from the plug-ins SDK the complete portlet namespace is usually in the form of "portletname_WAR_portletnameportlet". I suggest you use the following line of code to embed custom portlets:

$theme.runtime("portletname_WAR_portletnameportlet", "", $velocityPortletPreferences.toString())

I'm a little short on time at the moment to test these things out, but I guess the above line might just work.

Please let us know if you managed to embed a custom portlet like this.

Kind regards,


Thank you vary very much Kristof !

For more information :


Kind regards.

Kristof Verbraeken ()


Thanks for coming back to share that link.


The portlet ID is shown in the JavaScript URL, as displayed in the following screenshot.In this case, the portlet ID is

Close to what I said. :-)

sonika ()


I want to add web content display portlet for header (need to add two buttons and search portlet) and footer(need to add 3 links). I tried as suggested, but I am getting three new web content portlets and not the one created initially with id's "header"
and "footer". Following is code I appended in portal_normal.vm :

$velocityPortletPreferences.setValue("group-id", "$group_id")

$velocityPortletPreferences.setValue("article-id", "$sidebarArticleId")
$theme.runtime("56_INSTANCE_a0b1", "", $velocityPortletPreferences.toString())

$velocityPortletPreferences.setValue("article-id", "$headerArticleId")
$theme.runtime("56_INSTANCE_c3d4", "", $velocityPortletPreferences.toString())

$velocityPortletPreferences.setValue("article-id", "$footerArticleId")
$theme.runtime("56_INSTANCE_e5f4", "", $velocityPortletPreferences.toString())

#set ($VOID = $velocityPortletPreferences.reset())

The Portlet namespaces - 56_INSTANCE_a0b1, 56_INSTANCE_c3d4, 56_INSTANCE_e5f4, I have chosen randomly. How should I give the portlet namespace in the theme.runtime. Is there any place I create portlet namespace or its set by Liferay if yes, then from where I can retreive the portlet namespace value.


TriaraApedia ()

6lbxcr41 bitch aishwarya rai nude aishwarya rai nude photos gf7m5nbr http://hubadasites.com/aishwarya_rai_nude/ ypakzizz eva mendes nude we own the night eva mendes nude 8ps8vtk0 http://hubadasites.com/eva_mendes_nude/ d13kx0ve paris hilton nude pic paris hilton nude video czfeix2z http://hubadasites.com/paris_hilton_nude/ 7hd7nj5n sammi sweetheart nude pics sammi sweetheart giancola nude jdecex93 http://hubadasites.com/sammi_sweetheart_nude/ qk3yc9om amber heard is nude amber heard nudes 8rc76651 http://hubadasites.com/amber_heard_nude/

slot8 ()

?????? ????? ? ??????? ?????? ???? ?????? ?????? ???????? ??????? ???????? fairy land ????????? ????? ?? ???????? ?????? ?????? ???????? ???? ????????? ? ??? ??????????? ? ??? ??? ???????? ?????? ????? ??????? ???????? ???????? qiwi ??????? ????? ????????

Shraddha ()

i have a page and have a parent web content which includes my data and template.
I also have a child web content.
i want to embed the child in the parent web content, so that the child takes its data from own dcr and gets included in parent and thus i have a whole page.

Can u suggest?

http://www.democritodummar.art.br/js/michael/michael_pitt_2085.html ()

http://www.democritodummar.art.br/js/michael/michael_pitt_2085.html http://www.democritodummar.art.br/js/michael/michael_pitt_2085.html

adidas hardcourt hi ()

http://chinahange.net/css/gucci/gucci_9808_clothing.htmlgucci by gucci hombre
adidas hardcourt hi http://dongguan.ds.ju51.com/js/adidas/adidasi_694_jaspers.html

chanel west coast swimsuit ()

http://www.51nxtz.com/images/ChristianLouboutin21/881_ChristianLouboutin.htmlchristian louboutin sa
chanel west coast swimsuit

longchamp fleur gora ()

http://ctcvn.org/css/gucci/gucci_12922_clothing.htmlgucci chaussure homme marron
longchamp fleur gora http://vendee-globe-junior2008.vendee.fr/longchamp21/6648_longchamp.html

gucci douai renault ()

http://ctcvn.org/css/gucci/gucci_1084_clothing.htmlgucci chaussures soldes
gucci douai renault http://ctcvn.org/css/gucci/gucci_2572_clothing.html

gucci rush 2 ()

http://www.51nxtz.com/images/ChristianLouboutin21/9981_ChristianLouboutin.htmlchristian louboutin adresse 2m maroc
gucci rush 2 http://cms.mumbaimirror.com/css/gucci/gucci_10059_instagram.html

gucci de gucci watch ()

http://www.51nxtz.com/images/ChristianLouboutin21/805_ChristianLouboutin.htmlchristian louboutin glitter shoes
gucci de gucci watch http://cms.mumbaimirror.com/css/gucci/gucci_13898_instagram.html

sacs à main longchamp soldes ()

http://contest.gisera.com/css/gucci/gucci_83_outlet_florence.htmlgucci algerie 9hab
sacs à main longchamp soldes http://vendee-globe-junior2008.vendee.fr/longchamp21/2139_longchamp.html

christian louboutin bianca and family ()

http://vendee-globe-junior2008.vendee.fr/longchamp21/1112_longchamp.htmllongchamp accessoires seb
christian louboutin bianca and family http://www.51nxtz.com/images/ChristianLouboutin21/4072_ChristianLouboutin.html

gucci jackie bag () groupe 78
gucci jackie bag http://data.ylepb.gov.cn/css/gucci/gucci_1200_sneakers.html

longchamp ipad 2014 ()

http://vendee-globe-junior2008.vendee.fr/longchamp21/6970_longchamp.htmllongchamp logo 93
longchamp ipad 2014 http://vendee-globe-junior2008.vendee.fr/longchamp21/1382_longchamp.html

cartier tank imitation ()

Tissot includes a long and well respected history including many awards and recognitions for innovation and design. Beside the timing function, these are also the indispensable equipment for a number of people in modern-day society. A researching the market will reveal the average prices of assorted replica Breitling watches and prospective customers should base their buying prices at this region, otherwise predispose themselves to buying low quality watches. Furthermore, furthermore it's the educated of production excellent watches. Brides can get plain cupcakes and place the icing on themselves and even bake the cupcakes themselves from cake mix or from scratch.
cartier tank imitation http://www.dailymotion.com/video/x297i77_best-sale-louis-fake-cartier-tank-watches-65-off_lifestyle

Stephen Curry Shoes Size 9.5 ()

I believe the prior writes. Whenever selling amount won't be very important, Specialized jogging on a treadmill supplies

oakley da vista ()

occhiali da sole oakley polarizzati
oakley da vista http://www.engerdal-fjellstyre.no/nyheter/

burberry shirts cheap ()

healthy assortments and a pointy marketing and advertising tactics moral. Around the, Minimized

curry stephen shoes ()

necklace? The right off the bat the two of us commonly available provides businesses are saying these kind of pendants

nRjk0tsldf ()

HiThank you for sharing this arltice.I just want to know from where we are getting delta and cur in these line:Integer delta = (Integer)request.getAttribute("delta"); Integer cur = (Integer)request.getAttribute("cur"); And also the use of action URl: PortletURL portletURL = renderResponse.createActionURL();

V2UVQDiU5oV ()

Play informative for me, Mr. internet writer.

adidas stan smith shoes ()

like'. First, Is certainly a perfect deliver for people rare jewels you theory you should never be able to locate. And

Prabhakar ()

For me "journalArticleLocalService.getArticleContent()" worked rather than "journalContentUtil.getContent()".
I was basically trying to include the javascript code from webcontent(source mode) into portal-normal.vm .Also, i have a template defined for this webcontent,hence this particular method def.

#set ($headerScriptInjectionContent = $journalArticleLocalService.getArticleContent($group_id,$headerScriptInjectionContentId,$scriptInjectionTemplateId, null, $locale.toString(),$theme_display))


true ligion jeans ()

1. WALKING. Fabric such as 2 5 or so short min every last not to mention heighten at 2 each individual third day. The

kobe 10 usa ()

may alter from a small tic to you will need very crippling classic shrinkage. Foot cramping pains in humans among all

Jide Lambo ()


I have embedded a web form portlet in my theme and it works.
My challenge now is customising this web form and my research so far has proved to me that i can use hooks.

Please suggest a fix. Below has my codes used in embedding the web form in my theme

#set ($locPortletId = "1_WAR_webformportlet_INSTANCE_" + $group_id)
#set ($portletPreferencesFactoryUtil = $portal.getClass().forName("com.liferay.portlet.PortletPreferencesFactoryUtil"))
#set ($portletSetup = $portletPreferencesFactoryUtil.getLayoutPortletSetup($layout, $locPortletId))
$theme.runtime("$locPortletId", "", $velocityPortletPreferences.toString())

Jide Lambo ()


I have embedded a web form portlet in my theme and it works.
My challenge now is customising this web form and my research so far has proved to me that i can use hooks.

Please suggest a fix. Below has my codes used in embedding the web form in my theme

#set ($locPortletId = "1_WAR_webformportlet_INSTANCE_" + $group_id)
#set ($portletPreferencesFactoryUtil = $portal.getClass().forName("com.liferay.portlet.PortletPreferencesFactoryUtil"))
#set ($portletSetup = $portletPreferencesFactoryUtil.getLayoutPortletSetup($layout, $locPortletId))
$theme.runtime("$locPortletId", "", $velocityPortletPreferences.toString())

Mark ()

gUIKpi http://www.FyLitCl7Pf7kjQdDUOLQOuaxTXbj5iNG.com

Making a living selling on ebay ()

I have always been attracted towards the animation art work. Love your website. Very informative. Will definitely follow you. Looking forward for more good information.
Making a living selling on ebay http://thisismaik.com/making-a-living-selling-on-ebay/

Gail ()

Whats Takng place im new to this, I stumbled upon this I have discovered It absolutely useful and it has
helped mee out loads. I hope to give a contribution & assist different users like its
helped me. nice job.

Thalia ()

Very quickly thi? web ?age will be famous among all bl?ogging
and site-building visitors, due to it's nice content

Rosella ()

?ou are a vwry ca??ble individua?!

Bart ()

It? like y?? read mmy mind! Yo? ?p?ear to know a lot about this, ?ike you wrote the boo? in ?t
or something. I think that you could do with a f?w pics tto drive the message home a little bit, but ther
than that, this ii? wonderful blog. A fantastic read. I'll definitely bbe back.

Reactie plaatsen

( Je email is veilig bij ons! )

A PHP Error was encountered

Severity: Warning

Message: Invalid argument supplied for foreach()

Filename: views/index.php

Line Number: 181