
CMS Template (Velocity)
This article is legacy. The information is not up-to-date and should not be used unless you are on a legacy install of Liferay. For recent information, please see Web Content Management Portlet.
Introduction #
Journal/CMS Portlet was renamed to Web Content Portlet in Liferay 5.
This page is designed for people using the Liferay Journal (CMS Portlet) features which allows velocity macros to be used for displaying structured content.
The aim of this page to be a simple resource upon which non-programmers can create and adapt velocity templates within their CMS systems. Essentially it should provide a few examples and ideas on how you can get information out of Liferay and dynamically onto a webpage based upon the content you have created.
We'll talk a bit about Velocity and then create an example that allows someone to create an article with a drop down status list that is translated into a traffic-light image when displayed on the website.
Themes #
If you are looking for velocity information and what you can do with it when creating themes, this is not the document you want. However, take a look through this wiki page and then have a look at the class com.liferay.portal.velocity.VelocityVariables. Everything here applies, except you have whole bunch more stuff available to you when developing themes.
Assumptions #
I am assuming you know how to actually use the liferay CMS, how to create structured content and templates but wish to further your knowledge and learn how to use velocity.
Quick Velocity Overview #
Basically each velocity template is a plain text file with some simple 'special characters' in it. In the case of Liferay and other websites, those special characters are translated just prior to the server sending the requested web page to the clients browser. Velocity can be used to script any type of text file -- for instance, an email -- and in fact Velocity is also used for this within Liferay. I've used velocity to create test data for databases, transform telephone contact lists and so on. It's a useful piece of kit.
Basic Template #
So taking the example from a default Liferay installation, the developers kindly created a nice piece of content called SAMPLE-ARTICLE. Make sure you have access to the Guest community then you can search for this SAMPLE-ARTICLE. This article is based upon the structured content SAMPLE-STRUCTURE and is associated with two templates SAMPLE-VM-TEMPLATE and SAMPLE-XSL-TEMPLATE.
Once you have found the SAMPLE-ARTICLE, edit it and you will see that you can choose between the two templates, however choosing one or the other will not be visibly different. The difference is only the technology used to 'render' the SAMPLE-ARTICLE. One being XSL and the other VM, or Velocity Macro.
So open up the Template SAMPLE-VM-TEMPLATE and click on the 'Launch Editor' button. You will see a script pop up in a window. The script should look suspiciously like a web page with a load of lines which start with ## before it. Any line beginning with ## is a comment and is ignored by velocity. Lets take a look at the section
<table border="1" cellpadding="8" cellspacing="0" width="600"> <tr> <td>Sample Text</td> <td>$sample-text.getData()</td> </tr> <tr> ...
Here you can see we have access to the structured content, which has a row of data on it called sample-text. We have to ask sample-text for it's data and in fact we can simplify this quite a bit as velocity provides a bit of magic for us.
<table border="1" cellpadding="8" cellspacing="0" width="600"> <tr> <td>Sample Text</td> <td>$sample-text.data</td> </tr> <tr> ...
If you insert the sample article on a page somewhere and view it, then edit it to ensure it is using the SAMPLE-VM-TEMPLATE, you should see the article rendered in a big single column table.
What exactly is happening? Well you need to understand the relationship between Articles, Structures and Templates. The article is associated with a structure. The structure defines which fields are available to people creating articles. You can also choose a template, which defines how you want the article to appear.
Here you can see on the SAMPLE-ARTICLE that we have chosen a structure (SAMPLE-STRUCTURE), plus a template (SAMPLE-VM-TEMPLATE). In addition to providing us with fields to fill in, the structure also names those fields and we can access the fields in our velocity template using the special notation $ followed by the field name.
The following code snippet should actually be meaningful to you now. Quite simple we can access the fields provided by the structure and format them using plain old HTML.
<table border="1" cellpadding="8" cellspacing="0" width="600"> <tr> <td>Sample Text</td> <td>$sample-text.data</td> </tr> <tr> ...
Getting data out of different types of fields #
From the previous section you can open up the example and it will show you how to obtain data from the various types of fields available in the structured content.
<table border="1" cellpadding="8" cellspacing="0" width="600"> <tr> <td>$sample-text.data</td> <td>$sample-text-box.data</td> <td>$sample-text-area.data</td> <td><img src="$sample-image.data"/></td> <td>$sample-boolean-flag.data</td> <td>$sample-selection-list.data</td> <td>$reserved-article-id.data</td> <td>$reserved-article-version.data</td> <td>$reserved-article-title.data</td> <td>$reserved-article-create-date.data</td> <td>$reserved-article-modified-date.data</td> <td>$reserved-article-display-date.data</td> <td>$reserved-article-author-id</td> <td>$reserved-article-author-name</td> <td>$reserved-article-author-email-address</td> <td>$reserved-article-author-comments</td> <td>$reserved-article-author-organization</td> <td>$reserved-article-author-location</td> <td>$reserved-article-author-job-title</td> <td>$reserved-article-description</td> </tr> </table>
Note the special notation <strong>$reserved-article-XXXX</strong>. All of these give you access to the default fields such as the article ID, its title and description (abstract), creation date, last modified date and version number. All useful stuff, no?
More Detail #
Iterating #
One thing I didn't deal with in the last section was iterating, that is doing things one after another in a loop. This is clearly useful for walking over a list of items and doing stuff with each item. Take a look at this section.
<tr> <td>Sample Multiple Selection List</td> <td> <b> #foreach($selection in $sample-multi-selection-list.getOptions()) $selection <br/> #end </b> </td> </tr>
The special notation #foreach does exactly what it says on the tin. It moves, one item at a time over a list of items. In this case each item is called $selection and the list is grabbed from inside the multiple select box using the getOptions() method. This is diving into the realms of programming, but you should be able to mindlessly follow the example, a bit of copy and pasting and you'll be right! So if there are three items selected, the velocity macro above will produce something like this.
item1<br/> item2<br/> item3<br/>
Status Report Example #
Looking at the SAMPLE-ARTICLE you can the image is picked up quite cleverly as the URL of the image is stored one of the fields. As the URL is just a piece of text, we can manipulate it using velocity.
<tr> <td>Image</td> <td><img src="$sample-image.getData()"/></td> </tr>
Let say we've uploaded three images to a gallery called 'images'. I can obtain the links to those three images and they happen to be in:
/image/image_gallery?img_id=1006 /image/image_gallery?img_id=1007 /image/image_gallery?img_id=1008
And in this case they are little traffic lights, red, amber and green.
Note: <strong>Must request friendly urls for images. That extra level of indirection would greatly enhance the galleries</strong>
Now I've created a drop down list box in my structured content as follows:
... <dynamic-element name='status' type='list'> <dynamic-element name='1007' type='OK'> </dynamic-element> <dynamic-element name='1006' type='attention'> </dynamic-element> <dynamic-element name='1008' type='problem'></dynamic-element> </dynamic-element> ...
And my velocity template can render the image as follows:
... <tr> <td>$title.getData()</td> <td>$detail.getData()</td> <td><img src="/image/image_gallery?img_id=$status.getData()"/></td> <td>$reserved-article-version.getData()</td> </tr> ...
Ok this is great, we've dynamically picked up some images, but what if I wanted the image to be displayed along with the text. Well as we cannot create friendly URLs for images, we're forced to do a bit of hard coding (hard-core liferay-ers may know of other ways, but I don;t). And to avoid making our template really messy, we'll create a little macro. Here are the full listings of my structured content and my template.
<root> <dynamic-element name='title' type='text'></dynamic-element> <dynamic-element name='detail' type='text_area'></dynamic-element> <dynamic-element name='status' type='list'> <dynamic-element name='OK' type='OK'> </dynamic-element> <dynamic-element name='Attention' type='attention'> </dynamic-element> <dynamic-element name='Problem' type='problem'></dynamic-element> </dynamic-element> </root>
<html> <head> <title>$title.getData()</title> </head> <body> #set ( $iurl = "/image/image_gallery?img_id=" ) #macro( tlight $tl-status ) #if ($tl-status) #if ($tl-status.equals("OK")) <img src="$iurl 1007"/><br/>OK #elseif ($tl-status.equals("Attention")) <img src="$iurl 1006"/><br/>Attention #elseif ($tl-status.equals("Problem")) <img src="$iurl 1008"/><br/>Problem #end #else No Status Given #end #end <table border="0" cellpadding="3" cellspacing="2" width="600"> <tr> <td>Title</td> <td>Description</td> <td align="center">Status</td> <td>Version</td> </tr> <tr> <td>$title.getData()</td> <td>$detail.getData()</td> <td align="center" valign="center"> #tlight( "$status.getData()" ) </td> <td>$reserved-article-version.getData()</td> </tr> </table> </body> </html>
Velocity macro includes #
Having put the traffic light image selector into a Velocity macro is really useful, we can extract that piece of code and place in a file of it's own so we can include it and re-use it anywhere. Let's face it dynamic web pages reporting traffic light status's are quite a useful thing to have! I've now created a new VM template called TRAFFIC-LIGHT-MACRO, however it is not associated with any structured content. The TRAFFIC-LIGHT-MACRO template looks like this:-
#set ( $iurl = "/image/image_gallery?img_id=" ) #macro( tlight $tl-status ) #if ($tl-status) #if ($tl-status.equals("OK")) <img src="$iurl 1007"/><br/>OK #elseif ($tl-status.equals("Attention")) <img src="$iurl 1006"/><br/>Attention #elseif ($tl-status.equals("Problem")) <img src="$iurl 1008"/><br/>Problem #end #else No Status Given #end #end
Notice there is no HTML in there at all. The SERVICES-BULLETIN macro is now quite short and sweet:-
<html> <head> <title>$title.getData()</title> </head> <body> <table border="0" cellpadding="3" cellspacing="2" width="600"> <tr> <td>Title</td> <td>Description</td> <td align="center">Status</td> <td>Version</td> </tr> <tr> <td>$title.getData()</td> <td>$detail.getData()</td> <td align="center" valign="center"> #parse("$journalTemplatesPath/TRAFFIC-LIGHT-MACRO") #tlight( "$status.getData()" ) </td> <td>$reserved-article-version.getData()</td> </tr> </table> </body> </html>
Services #
Creating a status report #
From the previous example, we can create individual pieces of content along with dynamically generated traffic light icons showing a graphical representation of the status. We've built ourselves a little macro which goes off and finds the right image based upon a piece of text and that text is selected from a drop down list box so the end user can easily see create pieces of structure content.
We've also created some external macros and included them.
It would be nice however, to use velocity to generate a list for us. Unfortunately within Journal, we have limited access to the underlying system and cannot really go any further, without dropping out to code. As this is a tutorial for non-programmers, I will address these issues with the liferay developers and see if we can get the desired hooks into a later version.
If you have some programming knowledge and want to rebuild yourself another installation of liferay take a look at the class com.liferay.portlet.journal.util.JournalVmUtil. I'd suggest using an xml tool that will allow you to query the rss feed as in the ABOUTUS-NEWS example which uses XSL.
Velocity Variables #
Looking at the source, the following variables being placed in the context, at least for 5.1.1. For technical details on the class type of each variable, see the method insertHelperUtilities(VelocityContext,String[]) in the class com.liferay.portal.velocity.VelocityVariables Additional variables are placed in the context by com.liferay.portlet.journal.util.JournalVmUtil.transform()
From JournalVmUtil #
- request (not the http request so do a $request to see what's there)
- company
- companyId
- groupId
- journalTemplatesPath
- locale
- randomNamespace
From VelocityVariables #
utility classes #
- arrayUtil
- browserSniffer
- dateFormats
- dateTool
- dateUtil
- escapeTool
- expandoColumnLocalService
- expandoRowLocalService
- expandoTableLocalService
- expandoValueLocalService
- getterUtil
- htmlUtil
- httpUtil
- imageToken
- iteratorTool
- languageUtil
- unicodeLanguageUtil
- listTool
- localeUtil
- mathTool
- numberTool
- paramUtil
- portalUtil
- portal
- prefsPropsUtil
- propsUtil
- portletURLFactory
- randomizer
- serviceLocator
- sessionClicks
- sortTool
- staticFieldGetter
- stringUtil
- unicodeFormatter
- validator
permissions #
- accountPermission
- commonPermission
- groupPermission
- layoutPermission
- locationPermission
- organizationPermission
- passwordPolicyPermission
- portalPermission
- portletPermission
- rolePermission
- userGroupPermission
- userPermission
tilesVariables #
- attributeId / value pair
more work needs to be done to document the methods available in these objects
See Also #
- How To Access Objects From A Velocity Template
- Access to Liferay services in Velocity
- Calling a service in velocity