
CMS Internal API
Journal Tokens#
At runtime, several tokens, included in Journal elements (Article, Structure, Template) will be translated to their applicable runtime value at processing time.
Tokens have the following form:
@token_name@
Here is a complete list of tokens and their runtime values:
Token | Value | |
---|---|---|
@cdn_host@ | themeDisplay.getCDNHost() | |
@company_id@ | themeDisplay.getCompanyId() | |
@group_id@ | groupId | |
@cms_url@ | themeDisplay.getPathContext() + "/cms/servlet" | |
@image_path@ | themeDisplay.getPathImage() | |
@friendly_url_private_group@ | themeDisplay.getPathFriendlyURLPrivateGroup() | |
@friendly_url_private_user@ | themeDisplay.getPathFriendlyURLPrivateUser() | |
@friendly_url_public@ | themeDisplay.getPathFriendlyURLPublic() | |
@main_path@ | themeDisplay.getPathMain() | |
@portal_ctx@ | themeDisplay.getPathContext() | |
@portal_url@ | Http.removeProtocol(themeDisplay.getURLPortal()) | |
@root_path@ | themeDisplay.getPathContext() | |
@theme_image_path@ | themeDisplay.getPathThemeImages() | |
@language_id@ | the language_id of the current request | |
@layout_set_friendly_url@ | Added rev.32249 5.1.x, 5.2.x+ |
i.e.
@main_path@ will be replaced (usually) by /c
The
@layout_set_friendly_url@token was added to eliminate the need for fairly complex decision of how to render a URL pointing at some layout in the same community|org by friendlyURL of the layout. Simple! Just use
@layout_set_friendly_url@/{layoutFriendlyURL}and the urls will work in all cases.
@layout_set_friendly_url@
will behave as:
- when there IS a virtual host assigned to the layout set:
return BLANK
- when the layout set does NOT have a virtual host
return (/web|/group|/user) + @group_friendly_url@
- when the current serverName passed for the request does NOT match the virtual host
return (/web|/group|/user) + @group_friendly_url@
This allows for a JournalArticle to always properly form a proper URL regardless of where it is used; in Staging, Live, or copied to some other Community.
<a href="@layout_set_friendly_url@/home">Home</a>will work in all scenarios. And will remove the need for complex processing of these cases in templates.
Reserved Elements#
There are several meta elements (called 'reserved elements') which are added to an article's xml before they are processed by the template.
They have the following xpath:
/root/dynamic-element[@name='reserved-article-????']/dynamic-content
As such they can be retrieved as follows:
From XSL
<xsl:value-of select="/root/dynamic-element[@name='reserved-article-????']/dynamic-content" />
From Velocity
$reserved-article-????.getData()
Here is the complete list of 'reserved elements'
reserved-article-id 13307 reserved-article-version 1.0 reserved-article-title First blog post reserved-article-description This is a very cool Blog post. reserved-article-create-date 2007-08-08 19:25:41.0 reserved-article-modified-date 2007-08-09 16:47:10.0 reserved-article-display-date 2007-08-08 19:23:00.0 reserved-article-small-image-url # added in 4.3.5+ reserved-article-author-id 2 reserved-article-author-name Joe Bloggs reserved-article-author-email-address reserved-article-author-comments reserved-article-author-organization # removed in 4.3.5+ reserved-article-author-location # removed in 4.3.5+ reserved-article-author-job-title Software Engineer
Journal Request Element (4.3.1+)#
Included in the pre-template-processed article content is the following request element, which contains various useful sub-elements. Here is the RAW form it takes once attached to the article's xml.
<root> <request> <container-type>portlet</container-type> <container-namespace>/</container-namespace> <content-type>text/html</content-type> <server-name>localhost</server-name> <server-port>8080</server-port> <secure>false</secure> <auth-type/> <remote-user>2</remote-user> <context-path>/</context-path> <locale>en_US</locale> <portlet-mode>view</portlet-mode> <portlet-session-id>0539B7801C66CE6030F2EF770D949134</portlet-session-id> <scheme>http</scheme> <window-state>normal</window-state> <action>false</action> <portlet-namespace>_56_INSTANCE_tJfy_</portlet-namespace> <render-url>...</render-url> <render-url-exclusive>...</render-url-exclusive> <render-url-maximized>...</render-url-maximized> <render-url-minimized>...</render-url-minimized> <render-url-normal>...</render-url-normal> <render-url-pop-up>...</render-url-pop-up> <parameters> <parameter> <name>name</name> <value>Ray</value> </parameter> </parameters>
New in 4.3.5+
<attributes> <attribute> <name></name> <value></value> </attribute> </attributes> <portlet-session> <portlet-attributes> <attribute> <name></name> <value></value> </attribute> </portlet-attributes> <application-attributes> <attribute> <name></name> <value></value> </attribute> </application-attributes> </portlet-session>
</request> </root>
Of notable significance are the following paths:
/root/request/portlet-namespace /root/request/render-url /root/request/render-url-exclusive /root/request/render-url-maximized /root/request/render-url-minimized /root/request/render-url-normal /root/request/render-url-pop-up
Access to request parameters
/root/request/parameters
New in 4.3.5+
Access to request attributes
/root/request/attributes
Access to portlet session attributes (portlet scope)
/root/request/portlet-session/portlet-attributes
Access to portlet session attributes (application scope)
/root/request/portlet-session/application-attributes
By accessing the request element it is possible to create portlet urls linking back to the portlet displaying the article. Parameters can be used to alter the backend API calls and/or they can be used for affecting the rendering logic, you can check the Window State, Portlet Mode, Locale, etc.
Accessing these from XSL or VM is simple.
For example, getting the current Window State of the portlet:
From XSL:
<xsl:variable name="windowState" select="//request/window-state" />
From Velocity:
#set ($windowState = $request.get('window-state'))
or simply:
#set ($windowState = $request.window-state)
Accessing a request parameter:
From XSL:
<xsl:variable name="param" select="//request/parameters/parameter[name/text() = 'param']/value" />
From Velocity:
#set ($param = $request.get('parameters').get('param'))
or simply:
#set ($param = $request.parameters.param)
Accessing a request attribute:
From XSL:
<xsl:variable name="attr" select="//request/attributes/attribute[name/text() = 'attr']/value" />
From Velocity:
#set ($attr = $request.get('attributes').get('attr'))
or simply:
#set ($attr = $request.attributes.attr)
Accessing a portlet scoped session attribute:
From XSL:
<xsl:variable name="pSAttr" select="//request/portlet-session/portlet-attributes/attribute[name/text() = 'pSAttr']/value" />
From Velocity:
#set ($pSAttr = $request.get('portlet-session').get('portlet-attributes').get('pSAttr'))
or simply:
#set ($pSAttr = $request.portlet-session.portlet-attributes.pSAttr)
Accessing an application scoped session attribute:
From XSL:
<xsl:variable name="aSAttr" select="//request/portlet-session/application-attributes/attribute[name/text() = 'aSAttr']/value" />
From Velocity:
#set ($aSAttr = $request.get('portlet-session').get('application-attributes').get('aSAttr'))
or simply:
#set ($aSAttr = $request.portlet-session.application-attributes.aSAttr)
Request Handling Example#
Here is a small example demonstrating request handling.
Structure#
<root> <dynamic-element name='text' type='text_box'></dynamic-element> </root>
XSL Template#
<xsl:template match="/"> <xsl:variable name="url" select="//request/render-url" /> <xsl:variable name="namespace" select="//request/portlet-namespace" /> <xsl:variable name="paramName" select="//request/parameters/parameter[name/text() = 'name']/value" /> <xsl:variable name="friendlyUrl" select="//request/attributes/attribute[name/text() = 'FRIENDLY_URL']/value" /> <!-- BEGIN OUTPUT --> <xsl:value-of disable-output-escaping="yes" select="//dynamic-element[@name='text']" /> <xsl:text>Current Page: </xsl:text> <xsl:value-of disable-output-escaping="yes" select="$friendlyUrl" /> <xsl:choose> <xsl:when test="$paramName != ''"> <xsl:text>Hello </xsl:text><xsl:value-of select="$paramName" />! <a href="{$url}">Back</a> </xsl:when> <xsl:otherwise> <form action="{$url}" name="{$namespace}fm"> Please enter your name: <input type="text" name="{$namespace}paramName" /> <input type="submit" /> </form> </xsl:otherwise> </xsl:choose> </xsl:template>
Velocity Template#
#set ($url = $request.get('render-url')) #set ($namespace = $request.get('portlet-namespace')) #set ($paramName = $request.get('parameters').get('name')) #set ($friendlyUrl = $request.get('attributes').get('FRIENDLY_URL')) <!-- BEGIN OUTPUT --> $text.getData() Current Page: $friendlyUrl #if ($paramName) Hello ${paramName}! <a href="$url">Back</a> #else <form action="$url" name="${namespace}frm"> Please enter your name: <input type="text" name="${namespace}paramName" /> <input type="submit" /> </form> #end
Combined with the backend API calls, this is a powerful mechanism for creating complex, dynamic, and customized displays of journal content using one of two powerful templating languages.
Use it for building "Read More..." teaser views, etc.
Backend Journal Service Calls#
The Journal has 4 calls which can be made to it's backend services. These allow a journal template designer to retrieve Structures, Templates, and Articles for use in various ways. These might be internally loaded through xsl:import/xsl:include or xpath:document(URI) methods
Getting a structure:
@main_path@/journal/get_structure?groupId={GID}&structureId={SID}
Where {GID} is the groupId and {SID} is the structureId of some Structure.
Getting a template:
@main_path@/journal/get_template?groupId={GID}&templateId={TID}[&transform={true|false}]
Where {GID} is the groupId and {TID} is the templateId and optional 'transform' is true or false. False means the template will not be pre-processed such that tokens will not be translated.
The content type of the returned template will depend on the type of template:
css = text/css vm = text/plain xsl = text/xml
So, clients should play nicely with the types they expect. E.g. If you create a CSS template to be loaded in your theme, the file type will agree with the browser.
Getting an article:
@main_path@/journal/get_article?groupId={GID}&articleId={AID}
where {GID} is the groupId and {AID} is the articleId. For internationalization, you can add &languageId={LID} where {LID} = @language_id@
Getting a list of articles:
@main_path@/journal/get_articles?groupId={GID}[&type={TYPE_NAME}] [&structureId={SID[,SID]}][&templateId={TID}][&displayDateGT={ISODateFormat}] [&displayDateLT={ISODateFormat}][&delta={deltaInt}][&orderBy={display-date}]
Where {GID} is the groupdId, {TYPE_NAME} is the type as defined in (portal.properties)journal.article.types, {SID[,SID]} is comma delimited list of structureIds, {TID} is the templateId, {ISODateFormat} for displayDateGT|displayDateLT is an ISO date format signifying a boundary for the display date of the returned articles, {deltaInt} is the max number of articles to return, and {display-date} for orderBy means that the articles should be ordered by displayDate as opposed to modifiedDate (the default).
JournalContentFriendlyURLMapper#
Quite often you want to provide access to Journal Content dynamically without having to publish each and every article on its own page. Imagine a News service which generates new content frequently. It would be very cumbersome to have to create a new page for every article. To this end, there is a very handy mechanism which allows us to strategically and dynamically position content on page. This is done using Liferay's JournalContentFriendlyURLMapper feature.
This feature is a simple URL handling mechanism built into the Journal Content portlet, but you don't have to directly use the Journal Content portlet in order to leverage some of it's features (but you can to utilize the more advanced targetting feature).
Suppose you have a template which lists the 10 most recent articles (probably of some type and based on some structure). The list may contain the title, date, description, author and probably a link to the full article. A simple way to create this link is to create it based on a friendly layout path along with some path details about the article in question.
For example (using Velocity):
#set ($targetPortletID = "56") #foreach ($article in $articles) #set ($articleUrl = "/web/guest/news/-/journal_content/" + $targetPortletID + "/" + $article.groupId + "/" + $article.articleId) <h3>$article.title</h3> <span>$article.userName</span> <p>$article.description</p> <a href="${articleUrl}">Read More...</a> #end
The links above will cause the articles in question to dynamically open up on the layout "/web/guest/news" maximized in a Journal Content portlet, even if the portlet does not exist on this layout.
This might be what you want, it might not. Suppose though that you would prefer for the article to appear in a specific location on some specified layout, so that can surround it by ads and other related content. You could customize a page with all the ads and related portlets you want, and in the position where you want to target the full article, place an empty Journal Content portlet. Once the Journal Content portlet is positioned, click the "Configuration" icon and on the "Setup" tab locate the "Portlet ID" and take note of it.
Once you have to Portlet ID of the target portlet noted, go back to your template and in place of the "56" for the
$targetPortletIDset it to the Portlet ID you noted.
e.g. Suppose that the portlet ID of the positioned Journal Content portlet was "56_INSTANCE_56Ht".
The resulting code would be:
#set ($targetPortletID = "56_INSTANCE_56Ht") #foreach ($article in $articles) #set ($articleUrl = "/web/guest/news/-/journal_content/" + targetPortletID + "/" + $article.groupId + "/" + $article.articleId) <h3>$article.title</h3> <span>$article.userName</span> <p>$article.description</p> <a href="${articleUrl}">Read More...</a> #end
The syntax for the
JournalContentFriendlyURLis as follows:
<layout_friendly_url>/-/journal_content/{PID}/{GID}/{AID}[/{TID}]
Where {PID} is the Portlet ID ("56" will cause the article to be opened in a maximized Journal Content portlet), {GID} is the groupId of the article you want to display, {AID} is the articleId of the article you want to display, and optionally {TID} is the templateId of a template to be used for rendering the article (the template must be associated with the structure of the article, otherwise it will be ignored). Omitting {TID} will simply use the default template associated with the article.