« Back

Theme JSP Overrides

Company Blogs August 22, 2011 By Ray Augé Staff

Ok, so in the last post I talked about JSP Include Buffer.

That post talked about how you'd override JSPs from Liferay's core in a maintainable way. Now I'd like to introduce you to a Liferay Theme feature, new in 6.1, that will grant you much more power when it comes to manipulating portal views from your theme using that plus this additional feature.

From your theme you can now include templates (following the same path maning as they are found in the core) in your themes which override those of the core, provided they have a template extension matching that of your themes. They will override the default view of the portatl but only where and when your theme is applied.

Now think about this! When you apply a theme onto any page of your portal, you can alter the view of any portlet on just those pages!

Let me illustrate with an example. I'll use the exact same example that was intriduced in the previous post just so it easier to follow along.

Assuming for the moment that our theme is a Freemarker theme, we add the following template to our theme:

<SDK_ROOT>/themes/my-theme/docroot/_diffs/templates/html/taglib/ui/page_iterator/start.ftl

In this template we place the following code (using the buffer pattern):

<#assign liferay_util = PortalJspTagLibs["/WEB-INF/tld/liferay-util.tld"] />

<@liferay_util["buffer"] var="html">
    <@liferay_util["include"] 
        page="/html/taglib/ui/page_iterator/start.jsp" 
        strict=true 
        useCustomPage=false 
    /> 
</@> 
 
<div style="border: 4px solid red; padding: 4px;">
    ${html}
</div>

So, you should note two things.

First, unlike in the previous post I don't have to use the .portal encoded name for the jsp because it's still where it started, the portal didn't relocate it since my override is in the theme (it only does that when using hook plugins).

Second, the attribute strict=true. As I mentioned before, but will again, this is to prevent the portal from doing a lookup for overrides when making the call to the underlying JSP (this is to avoid infinite recursion since we're in an override right now).

Ok, I can noew enhance or alter this view no problem without having to reproduce the whole of the original logic and I'm doing it from my theme no less!

What more could you ask for?

Well it turns out there IS more that could be asked and since it was asked for, we made it reality (that's what we do at Liferay, we make wishes come true).

The question was "Could you override a JSP, but only for a particular portlet?"

Since overriding a blog JSP only in blogs doesn't really make sense, nor does overriding a blog JSP only for message boards, the main case here is with taglib JSPs. Liferay has a vast number of tags and their view logic are largely implemented with JSPs.

So, the answer to that is, "Yes, now you can override a JSP in your theme for only specific portlets!"

How do you do it?

Simple! All you need to do is add the portlet Id of the target portlet, between the file name of the original JSP and the extension of the template like so:

<SDK_ROOT>/themes/my-theme/docroot/_diffs/templates/html/taglib/ui/page_iterator/start.19.ftl

Using a similar template containing (note the green border instead):

<#assign liferay_util = PortalJspTagLibs["/WEB-INF/tld/liferay-util.tld"] />

<@liferay_util["buffer"] var="html">
    <@liferay_util["include"]
        page="/html/taglib/ui/page_iterator/start.jsp"
        strict=true 
        useCustomPage=false 
    />
</@>

<div style="border: 4px solid green; padding: 4px;"> 
    ${html} 
</div>  

Now, you'll note that we have two new tempalate files in our theme:

_diffs/templates/html/taglib/ui/page_iterator/start.ftl
_diffs/templates/html/taglib/ui/page_iterator/start.19.ftl  

These two files do not conflict, and the precendence will be:

1. portlet specific template
2. non portlet specific template
3. (no file) default

If your template is trying to override the JSP for a portlet that is in a plugin, make sure to use the fully qualified portletId (which is encoded using the pattern portletid_WAR_plugincontextname).

Now if you place two portlets on the page while this theme is in effect on it, and each of those portlets use the liferay-util:page-iterator tag, and one of those portlets is the Message Boards Portlet (19) then you should see both red and green boxes around those parts of the page.

 

Oh, and remember that you CAN do the same from a Velocity theme:

_diffs/templates/html/taglib/ui/page_iterator/start.vm
_diffs/templates/html/taglib/ui/page_iterator/start.19.vm

The template (using the buffer pattern) would look more like this:

#set ($bufferTagClass = $portal.class.forName("com.liferay.taglib.util.BufferTag"))
#set ($includeTagClass = $portal.class.forName("com.liferay.taglib.util.IncludeTag"))
 
#set ($bufferTag = $bufferTagClass.newInstance())
#set ($V = $bufferTag.setPageContext($pageContext))
#set ($V = $bufferTag.setParent(null))
#set ($V = $bufferTag.setVar('html'))
 
#if ($bufferTag.doStartTag() == 2)
    #set ($V = $bufferTag.setBodyContent($pageContext.pushBody()))
    #set ($V = $bufferTag.doInitBody())
    #set ($includeTag = $includeTagClass.newInstance())
    #set ($V = $includeTag.setPageContext($pageContext))

    #set ($V = $includeTag.setPage('/html/taglib/ui/page_iterator/start.jsp'))

    #set ($V = $includeTag.setStrict(true))
    #set ($V = $includeTag.setUseCustomPage(false))
    #set ($V = $includeTag.runTag())
    #set ($V = $bufferTag.doAfterBody())
    #set ($V = $pageContext.popBody())
    #set ($V = $bufferTag.doEndTag())
#end
 
<div style="border: 4px solid red; padding: 4px;">
    ${pageContext.findAttribute('html')}
</div>

Now, I hope you find more uses for these features that colourful boxes. Good luck!

Threaded Replies Author Date
Awesome, although I does raise the question... Jonas Fonseca August 23, 2011 4:12 AM
Well, it's not hard to work out where a change... Ray Augé August 23, 2011 8:29 AM
The instance portletId fix is now in trunk (and... Ray Augé August 23, 2011 8:54 PM
Thanks for the update. Can't wait to put this... Jonas Fonseca August 24, 2011 5:57 AM
[...] Basically you can't:... Anonymous April 8, 2013 6:48 AM
hello, I have followed your tutorial and got my... dauphine laure June 27, 2013 8:15 AM
hello, I have followed your tutorial and got my... dauphine laure June 27, 2013 8:15 AM
Yes it's possible! Simply do not delegate to... Ray Augé June 27, 2013 8:19 AM
agree but I can't put code "jsp" directly into... dauphine laure June 27, 2013 8:35 AM
You can't use the jsp direct include at all... Ray Augé June 27, 2013 9:04 AM
I'm trying to apply this approach in Liferay... Víctor Ponz February 18, 2015 5:37 AM
Did you enable the portal property? ... Ray Augé February 18, 2015 5:44 AM
Which property? Thanks Víctor Ponz February 18, 2015 5:48 AM
Please follow the link I posted above. Ray Augé February 18, 2015 5:49 AM
The link on the previos comment didn't work,... Víctor Ponz February 18, 2015 9:34 AM
Sadly the comments don't support real links..... Ray Augé February 18, 2015 9:37 AM
I know, but if you try to copy and paste that... Víctor Ponz February 18, 2015 9:47 AM
true... weird! Ray Augé February 18, 2015 9:51 AM
Hi Ray. With the property... Víctor Ponz February 19, 2015 12:08 AM

Awesome, although I does raise the question where to put an extension if it needs to both change the style (theme specific) and some logic (hook specific). Any thoughts on that? I am also curious as to whether it is possible to use an instance portlet ID, if for example I wanted to change only the look and feel of the asset publisher on my front page?
Posted on 8/23/11 4:12 AM.
Well, it's not hard to work out where a change should go.

- If it should affect the whole portal, put it in a hook
- if it should not affect the whole portal, put it in a theme

You can use instance portletIds. To make sure I tested (and fixed) the scenario of applying first to all instanceable portlets on a page (include no instance in the naming) as well as overriding a single portlet with a more specific change (using the instanceId).

e.g.
_diffs/templates/html/taglib/ui/page_iterator/start.101_INSTANCE_0dmaduACd9V­6.ftl
_diffs/templates/html/taglib/ui/page_iterator/start.101.ftl

The change should appear in trunk today once https://github.com/brianchandotcom/liferay-portal/pull/1046 is accepted.
Posted on 8/23/11 8:29 AM in reply to Jonas Fonseca.
The instance portletId fix is now in trunk (and will be in 6.1).
Posted on 8/23/11 8:54 PM in reply to Ray Augé.
Thanks for the update. Can't wait to put this to good use.
Posted on 8/24/11 5:57 AM.
[...] Basically you can't: http://www.liferay.com/community/forums/-/message_boards/message/14269385 BUT, if you take a look here: http://www.liferay.com/web/raymond.auge/blog/-/blogs/jsp-include-buffer... [...] Read More
Posted on 4/8/13 6:48 AM.
hello,
I have followed your tutorial and got my red box ^ ^

For cons, I wondered if it was possible, to follow this to overload an entire jsp?
I think about : ROOT\html\taglib\ui\search\start.jsp

thanks
Posted on 6/27/13 8:15 AM.
hello,
I have followed your tutorial and got my red box ^ ^

For cons, I wondered if it was possible, to follow this to overload an entire jsp?
I think about : ROOT\html\taglib\ui\search\start.jsp

thanks
Posted on 6/27/13 8:15 AM.
Yes it's possible! Simply do not delegate to the original jsp emoticon

i.e. don't use the buffer logic. Just output whatever you need.
Posted on 6/27/13 8:19 AM in reply to dauphine laure.
agree
but I can't put code "jsp" directly into the template.
For example, if I put the first line <% @ include file = "/ html / taglib / ui / search / init.jsp '%>
it is not analyzed, but just displayed.
I should not use the right tag for that ... ?
Posted on 6/27/13 8:35 AM in reply to Ray Augé.
You can't use the jsp direct include at all from a template.

It "might" work if you simply use the dispatched include with only the init.jsp

#set ($V = $includeTag.setPage('/html/taglib/ui/page_iterator/init.jsp'))

.. but that's a long shot.
Posted on 6/27/13 9:04 AM in reply to dauphine laure.
I'm trying to apply this approach in Liferay 6.2 ga3 but nothing happens. What can I do to override a jsp from a theme?
Thanks
Posted on 2/18/15 5:37 AM.
Did you enable the portal property?

https://github.com/liferay/liferay-portal/blob/6.2.x/portal-impl/src/po­rtal.properties#L656-L660
Posted on 2/18/15 5:44 AM in reply to Víctor Ponz.
Which property?
Thanks
Posted on 2/18/15 5:48 AM in reply to Ray Augé.
Please follow the link I posted above.
Posted on 2/18/15 5:49 AM in reply to Víctor Ponz.
The link on the previos comment didn't work, but the one on the e-mail did
Thanks,
Posted on 2/18/15 9:34 AM in reply to Ray Augé.
Sadly the comments don't support real links.. you have to copy paste!

Let's call it a "security feature"!
Posted on 2/18/15 9:37 AM in reply to Víctor Ponz.
I know, but if you try to copy and paste that one, doesn't work, at least on my browser emoticon
Posted on 2/18/15 9:47 AM in reply to Ray Augé.
true... weird!
Posted on 2/18/15 9:51 AM in reply to Víctor Ponz.
Hi Ray.
With the property theme.jsp.override.enabled=true I can use this approach. But now the question is that I'm unable to make it works because I only get ${pageContext.findAttribute('html')} printed, like on this forum post
https://www.liferay.com/es/web/raymond.auge/blog/-/blogs/jsp-include-buffer
T­hanks in advance
Posted on 2/19/15 12:08 AM in reply to Ray Augé.