Sunday, November 15, 2009

SEO with liferay - required features

Liferay 5.2 came with a couple of improvements regarding SEO (Search Engine Optimization) For example

  • default friendly URLs
  • automatically generated META tags
  • unique titles
That is really good news. And more importantly: To me it shows, that liferay has understood the the future doesn't only lie in intranet-portals but as well in webpages / business models for the internet.
And well - we all know that SEO is key there.

So here are some additional points that are really required from my point of view to catch up with the other big CMS/Portal solutions:

  1. Themes that are SEO friendly by default. This implies usage of headers (H1, H2 etc) - instead of limited meaningfull elements like "Div"
  2. "Related links" portlet. This would allow smart intra-site linking of pages
  3. Pimping of the "Blog" portlets (better customization possibilites) - as this is one of the main means for user generated content
  4. Default google-friendly 404 handling (Not so critical as it can be fixed as described in this blog entry about the 404 customization)

I'm confident, that liferay will pick up some of these ideas. What do you think?

PS:
Talking about catching up with the big cms systems for the internet - like wordpress - a nice "tag cloud" portlet for liferay would be cool. :)

Satisfy google - Create 404 error message to verify page for webmastertools

Now this was a long fight. Pew.

Quite some time ago google changes their rules for page "verification" for their webmastertools which you probably know. Now they ban the usage of redirects when a page is not found - google want's a nice "404" error message.

How does that work with liferay? By default liferay redirects all requested URLs that doen't have a corresponding page to the homepage (e.g. /web/guest/home). That's exactly what google does not like. :o/

There are now two different cases that should be distinguished:

  1. Wrong URLs "behind" the path of the homepage (e.g. www.foo.com/web/guest/hehjoifjal)
  2. Wrong URLs directly at the root path (e.g. www.foo.com/hehjoifjla )
(This difference has been pointed out by Chris Kauffman in the liferay forums - thanks!)

For 1) there are seetings within liferay that customize that behaviour. These work fine - but just for this use case:

layout.show.http.status=true
layout.friendly.url.page.not.found=/errors/my_404error.htm

For 2) This has to be adjusted on the app-server level (for my: tomcat from the bundle)

Two options:
The proper way - change the routing in the web.xml of the liferay application (in tomcat-5.5.27\webapps\ROOT\WEB-INF). There you change the entry for "error-page.

Or you do it quick and dirty :)
The "error-page" tag points to /errors/404.jsp
You can modify this file directly to turn of the redirection. That is you have to remove:
<body onload="javascript: location.replace('<%= homeURL %>')">


and related.

Now you should be friends with google again. :)

Sunday, August 23, 2009

Issue: Blog entry disappears

Final note for today:

Recently I had a strange problem with the Blog feature of liferay (which I heavily use for my intened web 2.0 features - especially letting "Guest" users write content)

"Blog posts" done by the users (with my own EasyBlog portlet) did not appear in the Blog portlets - but could be found with the admin portlets.
Changing the display time helped! Somehow the timezones of the three different timezone-settings
  1. operating system (ubuntu)
  2. virtual machine (set by the statical portal.propoerties at startup of liferay)
  3. liferay portal
got out of synch - maybe during some "daylight saving" change.

After some research on the topic I had to do a complete restart of my "Plesk" environment anyway - and the problem disappeared. :)

But next time when filling time-related parameters in the liferay API I would by carefull filling the Calendar objects with something from System - but rather search for an according (helper) API by liferay..
Eventually. :)

Apache (reverse) proxy for liferay

...by the way (as my last post just described some additional apache tuning) here my full vhost.conf file per each virtual liferay host.

Because there is one additional thing that might be interesting: I use the proxy (actually: Reverseproxy) from apache to map the port 80 to 9080 - and that in a virtual host environment.

So the full vhos.conf looks as follows:

LoadModule proxy_module /usr/lib/apache2/modules/mod_proxy.so
LoadModule proxy_http_module /usr/lib/apache2/modules/mod_proxy_http.so


RewriteEngine On
RewriteOptions Inherit
RewriteCond %{HTTP_HOST} !^www\.traumtube\.de [NC]
RewriteCond %{HTTP_HOST} !^$
RewriteRule ^/(.*) http://www.traumtube.de/$1 [L,R,NE]



Order deny,allow
Allow from all


ProxyPass / http://localhost:9080/
ProxyPassReverse / http://localhost:9080/
ProxyPreserveHost on

Virtual hosts with liferay - handling of "subdomain" www

As you might have noticed there were no major changes lately. But yesterday at least I did a lot of cleanups with the team. Most of them were content related - but one basic thing could be interesting for you as well: Fine tuning virtual hosting.

We are using the "virtual host" feature of liferay a lot.
(Control panel -> Server -> Portal instances)

Unfortunately you can just enter one single virtual host ID here. Usually the domain plus the www subdomain/prefix. (e.g. www.traumtube.de )
If a user now enters the URL without the subdomain (here: http://traumtube.de) he would not get to the intended page but to the first (default) virtual host. Reason is: Liferay doesn't match the HTTP_HOST as it doesn't match including the subdomain.

Finally I came up with a solution using Apaches mod_rewrite to achieve the desired flexibility:

RewriteEngine On
RewriteOptions Inherit
RewriteCond %{HTTP_HOST} !^www\.traumtube\.de [NC]
RewriteCond %{HTTP_HOST} !^$
RewriteRule ^/(.*) http://www.traumtube.de/$1 [L,R,NE]
Whoopie - that helped.

Hope that helps somebody with the same issues.
Cheers!

Sunday, May 17, 2009

Liferay deployment problem: "Deployment will start in a few seconds" ....

One more thing I learned today:

After migrating to the 5.2.2 and from JBoss to tomcat (see my migration entry ) I noticed, that I could not deploy portlets anymore.
(Why did I not fix that earlier? In the beginning I used the workaround to copy the full unzipped folders to the server and restarted the server :) )

So as we started a big "Theme" project today (Note: Watch out for upcoming blog entries about themes! :) ) that problem got annoying.

The result I always got was:

... was copied successfully. Deployment will start in a few seconds.
What I finally found out:

The new control panel is great. Really! Also good to install plugins. (Control Panel->Server->Plugin Installation)
What I did forget though: I still had the good old "Plugin Installer" portlet up and running - from the good old JBoss days.

And there it was. The setting:
Plugin Installer -> Configurations -> Destination Directory

still contained old JBoss setting. (Of course - they were still in the DB).
Removing that column solved my problem - deploying works perfectly now.

Cheers!

Hibernate problem: "MESSAGE: Broken pipe"

Hi all,

short update - after a long while of running smoothly, the portlet with the hibernate DB connection had a small problem (again).

This time the error was:
04:12:22,792 ERROR [JDBCExceptionReporter:101] Communications link failure due to underlying exception:

** BEGIN NESTED EXCEPTION **

java.net.SocketException
MESSAGE: Broken pipe

STACKTRACE:

java.net.SocketException: Broken pipe
at java.net.SocketOutputStream.socketWrite0(Native Method)
at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:92)
at java.net.SocketOutputStream.write(SocketOutputStream.java:136)
at java.io.BufferedOutputStream.flushBuffer(BufferedOutputStream.java:65)
at java.io.BufferedOutputStream.flush(BufferedOutputStream.java:123)
at com.mysql.jdbc.MysqlIO.send(MysqlIO.java:2744)
at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:1612)
at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:1723)
at com.mysql.jdbc.Connection.execSQL(Connection.java:3256)
at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:1313)
at com.mysql.jdbc.PreparedStatement.executeQuery(PreparedStatement.java:1448)
at com.mchange.v2.c3p0.impl.NewProxyPreparedStatement.executeQuery(NewProxyPreparedStatement.java:76)
at org.hibernate.jdbc.AbstractBatcher.getResultSet(AbstractBatcher.java:208)
at org.hibernate.loader.Loader.getResultSet(Loader.java:1808)
at org.hibernate.loader.Loader.doQuery(Loader.java:697)
at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:259)
at org.hibernate.loader.Loader.doList(Loader.java:2228)
at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2125)
at org.hibernate.loader.Loader.list(Loader.java:2120)
at org.hibernate.hql.classic.QueryTranslatorImpl.list(QueryTranslatorImpl.java:935)
at org.hibernate.engine.query.HQLQueryPlan.performList(HQLQueryPlan.java:196)
at org.hibernate.impl.SessionImpl.list(SessionImpl.java:1148)
at org.hibernate.impl.QueryImpl.list(QueryImpl.java:102)
at com.liferay.portal.dao.orm.hibernate.QueryImpl.list(QueryImpl.java:78)
at com.liferay.portal.dao.orm.hibernate.QueryImpl.list(QueryImpl.java:73)
A short webresearch pointed out a problem with transaction handling and hinted at two possible solutions:
  1. Wrong coding regarding "commit" of transactions
  2. Usage of a parameter to "autocommit"
(Sources:
http://www.mikeschubert.com/archives/2006/08/javanetsocketex.html
http://forums.mysql.com/read.php?39,196323,198960#msg-198960)
)

Trying not to focus on hibernate problems but rather on other topics I'm trying solution 2 at the moment.
I will let you know how it worked out. :)