Adding a JavaScript to Every Page

Have you ever found yourself in a situation where you need to deploy a piece of JavaScript (such as Google Analytics) to every single page in the portal? Up to now, the most common way to accomplish this is to include the JavaScript in your theme. However, this can be really annoying if your site uses multiple themes.

So, in this blog, I want to show you how you can create a very simple portlet to add a piece of JavaScript to every page on your portal. Liferay already has a very convenient way of integrating with Google Analytics (Manage Pages > Settings > Monitoring), so for this example, I'm going to create a portlet that adds RefTagger to every page. RefTagger uses a small piece of JavaScript to scan a page for words it recorgnizes and turns them into a hyperlinks with a tooltip.

So let's get started.

1) First, you'll need to get a copy of the Liferay Plugins SDK if you don't already have it.

2) From a command prompt, navigate to <plugins-sdk>/portlets/ and type

create logos-reftagger "Logos RefTagger"

This will automatically create a barebone portlet from which we can start building our portlet.

3) Navigate to <plugins-sdk>/portlets/logos-reftagger-portlet/docroot/ and open view.jsp

4) Change the content of view.jsp to the following:

<%@ taglib uri="http://liferay.com/tld/util" prefix="liferay-util" %>
<liferay-util:html-bottom>
    <script src="http://bible.logos.com/jsapi/referencetagging.js" type="text/javascript"></script>
    <script type="text/javascript">
       Logos.ReferenceTagging.lbsBibleVersion = "ESV";
       Logos.ReferenceTagging.lbsLinksOpenNewWindow = true;
       Logos.ReferenceTagging.lbsLibronixLinkIcon = "dark";
       Logos.ReferenceTagging.lbsNoSearchTagNames = [ "h1", "h2", "h3" ];
       Logos.ReferenceTagging.tag();
   </script>
</liferay-util:html-bottom>

For you portlet, just replace the the <script> tags with your own script tags.

Now here's the neat part. Take a look at the <liferay-util:html-bottom> tag. This tag will force whatever is within the tag to the bottom of the page (between </body> and </html>).

If you script needs to appear within the <head> section of the page, you can use <liferay-util:html-top> instead.

All that is left to do now is just make sure this portlet appears on every page.

5) Create a liferay-hook.xml in <plugins-sdk>/portlets/logos-reftagger-portlet/docroot/WEB-INF/.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hook PUBLIC "-//Liferay//DTD Hook 5.3.0//EN" "http://www.liferay.com/dtd/liferay-hook_5_3_0.dtd">
<hook>
    <portal-properties>portal.properties</portal-properties>
</hook>

And create a portal.property in <plugins-sdk>/portlets/logos-reftagger-portlet/docroot/WEB-INF/src/

layout.static.portlets.all=1_WAR_logosreftaggerportlet

For more information on the property layout.static.portlets.all, take a look at the portal.properties file in the Liferay source code.

6) Since we don't want users adding this portlet to a page and don't want the portlet border to appear, we need to set "system" to true and "use-default-template" to false in <plugins-sdk>/portlets/logos-reftagger-portlet/docroot/WEB-INF/liferay-portlet.xml.like so:

...
<liferay-portlet-app>
    <portlet>
        <portlet-name>logos-reftagger-demo</portlet-name>
        <icon>/icon.png</icon>
        <use-default-template>false</use-default-template>
        <footer-portlet-javascript>/js/test.js</footer-portlet-javascript>
        <system>true</system>
    </portlet>
    <role-mapper>
...

7) Deploy your portlet with the ant command ant deploy and your JavaScript will be on every page in your portal!

You can get this portlet from our public SVN or download the war below:
    For 5.2.3
    For trunk

Blogs
Nice article, thanks!

Your example is not set to be layout-cacheable, so it will really drop performance, if you are using it on every page. Or the layout.static.portlets.all included portlets are always layout cacheable?
Samuel, thanks for sharing this really useful information.

The technique you describe was used in "Custom Global Markup Portlet" which allows to add markups (javascript, css, html) to every page in given community by providing convenient management interface in Liferay’s control panel.
This is a great idea, but I have one question. I have implemented this in our environment, to enable WebTrends internally. It is nice to be able to configure this as a portlet and have it show on every page, but I dont want the user to actually see the portlet.

Is it possible to attain this functionality without actually showing the portlet to the user? Essentially the portlet is empty except for the script block, so we would want the portlet to be invisible to the user.

Blaine
Blaine, make sure you do step 6.
Thanks for the suggestion, but I did make sure I added that step. I was unaware of the "system" tag at first, but once I added that and made it true, all it did was remove it from the "Add Application" Menu. Meanwhile the portlet was added to every page, via the portal-ext.properties - not a hook, and is visible to users.

Side note, this is being deployed to 5.2.3

Blaine
is there a way to it have it run just on the main page or on one page instead of every page
Stephen - when we needed to do that (on a single page) we went into Manage Pages, selecting the page you wanted. Under the Page tab, at the bottom you see a "JavaScript" area you can click on, select that and you will get 3 input areas where you can place JavaScript code. That will load every time for that page.

I don't know if this is the best practice method, but it is what we have used for this situation.

Blaine
[...] Hi, I'm using Liferay EE version 6.1.10. I've been searching for a way to add my own custom Javascript (also include for external JS files) to every page in the portal. I want to have a way to add JS... [...] Read More