In my previous article I showed you how you can optimize SEO from within a portlet. Today we will take it one step further: I will show you how you can optimize portlet URLs. By default the URLs generate by Liferay are quite messy; it contains the portlet ID, the state and several other options. This doesn’t really look nice for Google.
However, Liferay has a nice method of controlling the URL the portal generates for a portlet, the ‘FriendlyURLMapper‘. You can implement this interface, registerd it in the liferay-portlet.xml and you will have nice URLs. In the following example I will show how to implement it and what each individual method does.
I assume you have installed Liferay and the plugin SDK and that you know how to develop Liferay portlets.
The first step is to create a new class which will implement the ‘FriendlyURLMapper‘ interface. To make things easies we will derive that class from ‘BaseFriendlyURLMapper‘. You have to implement several methods yourself but don’t worry I will show you how.
The getMapping method
The ‘getMapping‘ method must return an identifier for the mapping. The mapping identifier is used by Liferay to map URLs to instances of the ‘FriendlyURLMapper‘. For example Liferay will resolve the following URL ‘/seoPortlet/123/view’ to a ‘FriendlyURLMapper‘ instance with mapping ‘seoPortlet‘. You can choose whatever mapping you want, just make sure your custom URLs always start with the mapping identifier.
To implement the ‘getMapping‘ method just return an unique identifier for the URL mapper.
public String getMapping() {
return "seoPortlet";
}
The buildPath method
The ‘buildPath‘ method builds the actual URL. Here you implement the URL generation logic. You have access to the ‘LiferayPortletURL‘ object for which the URL is generated. You can extract the portletId, parameters, window state, etc. from it. The method should return a string containing the friendly URL for that particular portletURL, when the method returns null the default portletURL is used.
For each parameter (p_p_id for example) you move from the query string to the URL, you need to call ‘portletURL.addParameterIncludedInPath(“p_p_id”)‘. This will tell Liferay to not include the parameter in the query string. Parameters who are not marked as ‘included in path’ will be added to the query string automatically by Liferay.
Here is an example which maps URLs with a parameter named event to a friendly URL.
public String buildPath(final LiferayPortletURL portletURL) {
String friendlyURLPath = null;
// get the value
final String portletId = portletURL.getPortletId();
final String eventName = GetterUtil.getString(portletURL.getParameter("event"));
if (Validator.isNotNull(portletId) && Validator.isNotNull(eventName)) {
friendlyURLPath = StringPool.FORWARD_SLASH + "seoPortlet"+ StringPool.FORWARD_SLASH + portletId + StringPool.FORWARD_SLASH + eventName;
portletURL.addParameterIncludedInPath("event");
}
// add other pararmeters
if (Validator.isNotNull(friendlyURLPath)) {
portletURL.addParameterIncludedInPath("p_p_id");
}
return friendlyURLPath;
}
Notice that we are including the mapping prefix ‘seoPortlet’ and that we are excluding the ‘p_p_id’ and ‘event’ parameters from the URL.
The getPortletId method
This method is used by the ‘BaseFriendlyURLMapper‘ super class to retrieve the portlet id. This will be used by ‘populateParams‘ method.
To implement the ‘getPortletId‘ method just return the value of a backing field with the name portletId. See example:
private String portletId;
public String getPortletId() {
return portletId;
}
The populateParams method
This method will be called by Liferay each time a request is made with the mapping identifier in the URL. This method is responsible for mapping the parameters we removed from the query string and added to the path back to parameters: reversing the work we did in the ‘buildPath’ method.
Here is an example implementation.
public void populateParams(final String friendlyURLPath, final Map<String, String[]> params) {
// get the values
final String[] parts = StringUtil.split(friendlyURLPath, StringPool.SLASH);
portletId = parts[2];
final String event = parts[3];
final String namespace = getNamespace();
params.put("p_p_id", new String[]{portletId});
params.put("p_p_state", new String[]{WindowState.NORMAL.toString()});
params.put(namespace + "event", new String[]{event});
}
The method takes apart the ‘friendlyURLPath‘ and assembles parameters from it’s parts. Notice that in order to avoid parameter clashes between portlets the event parameter is prefixed with the portlet namespace, generated by the ‘BaseFriendlyURLMapper”s ‘getNamespace‘ method. The ‘getNamespace‘ method consumes the portletId using the ‘getPortletId‘ method.
liferay-portlet.xml
Now that the mapper is finished we need to tell Liferay to start using it. Add the friendly-url-mapper-class declaration to the portlet declaration and set its content to point to the class you just wrote:
<friendly-url-mapper-class>com.sample.FriendlyURLMapper</friendly-url-mapper-class>
That is it, know you can assemble your own FriendlyURLMapper now. I hope this article was useful to you. Please let me know if you have any questions or comments.
4 Replies to “SEO Friendly URLs for Liferay Portlets”
April 4th, 2010 at 11:43
[...] is it for now. You can find a tutorial on how to create portlet SEO friendly URLs here. Share and [...]
April 7th, 2010 at 10:25
Nice article Bert! I will keep in mind for some improvements that I want to implement in a site!
August 6th, 2010 at 20:48
Hi, I am developing a friendly url class for document library, so following are my steps.
I created a class inheriting from basefriendlyurlmapper, and compiled it and created a new jar file, placed in the liferay root/web-inf/lib folder. now when I open my web pages, Liferay servlet filter throws exception. Could you please tell me where am i wrong?
thanks,
Ashish
August 13th, 2010 at 16:13
I’m wondering about the getNamespace method. It seems to be missing from the article, or maybe I missed something . . .