VirtueMart: remove duplicate content

December 9th, 2010

VirtueMart is a powerful and free Joomla! component for creating eCommerce websites.

It has a lot of very interesting features and, in my two cents opinion, it’s a complete solution to manage your online store.

In a SEO point of view, VirtueMart has some problems with duplicate content and this article will try to teach you how to edit your .htaccess file to use 301 permanent redirects to fix duplicate products in your online store.

I had to fix this problem in a customer website. These are the duplicate urls I found on their default virtuemart installation:

  1. /index.php?option=com_virtuemart&page=shop.browse&category_id=29&lang=it&Itemid=233&vmcchk=1
  2. /index.php?option=com_virtuemart&page=shop.browse&category_id=29&lang=it&Itemid=233
  3. /index.php?option=com_virtuemart&page=shop.browse&category_id=29&lang=it
  4. /index.php?option=com_virtuemart&page=shop.browse&category_id=29
  5. /shop?page=shop.browse&category_id=29&lang=it&Itemid=233&vmcchk=1
  6. /shop?page=shop.browse&category_id=29&lang=it&Itemid=233
  7. /shop?page=shop.browse&category_id=29&lang=it
  8. /shop?page=shop.browse&category_id=29

As you can see, each product has 8 different URLs search engines can reach it. The store had 1.000 products so Google and other search engines saw about 8.000 duplicate pages.

Analyzing URL structure gave me a pattern to redirect progressively every URL to the last one.

You can see which are the problems in the query string and what could be a work flow to fix the duplicates problem:

  1. vmcchk parameter to be ignored
  2. Itemid parameter to be removed
  3. lang parameter to be removed
  4. index.php?option=com_virtuemart to be redirected to shop

VirtueMart Itemid parameter can be safely removed: it’s useless and it creates lot of duplicates. The lang parameter had been put by Joomfish plugin, not in use, and can be removed. The vmcchk parameter shouldn’t beremoved and you can instruct Googlebot to ingore it in Google Webmaster Tools. Last, but not least, we need to redirect index.php?option=com_virtuemart to shop.

Even if there are some plugins like sh404SEF to switch VirtueMart to a more SEF (Search Engine Friendly) URL structure, I prefer using Apache mod_rewrite and permanent redirects to explain Googlebot and other spiders how to crawl the shop.

This kind of solution, which works for me but WILL NOT WORK FOR YOU without a deep understanding of the statements, tells search engines how to permanently redirect each page to the last URL.

  1. RewriteEngine On
  2. RewriteCond %{QUERY_STRING} (.*)(^Itemid=[a-zA-Z0-9]+&?|^&Itemid=[a-zA-Z0-9]+&|&Itemid=[a-zA-Z0-9]+)(&?.*)
  3. RewriteRule (.*) %{REQUEST_URI}?%1%3 [L,R=301]
  4. RewriteCond %{QUERY_STRING} (.*)(^lang=[a-zA-Z0-9]+&?|^&lang=[a-zA-Z0-9]+&|&lang=[a-zA-Z0-9]+)(&?.*)
  5. RewriteRule (.*) %{REQUEST_URI}?%1%3 [L,R=301]
  6. RewriteCond %{QUERY_STRING} ^(.+&)option=com_virtuemart(.+)?$ [NC]
  7. RewriteRule ^index\.php$ http://%{HTTP_HOST}/shop$1?%1%2 [R=301,L]
  8. RewriteCond %{QUERY_STRING} ^(.+&)?option=com_virtuemart&(.+)?$ [NC]
  9. RewriteRule ^index\.php$ http://%{HTTP_HOST}/shop$1?%1%2 [R=301,L]

I try to explain what every htaccess statement means:

  1. RewriteEngine On
    Enables Apache mod_rewrite for URL rewriting
  2. RewriteCond %{QUERY_STRING} (.*)(^Itemid=[a-zA-Z0-9]+&?|^&Itemid=[a-zA-Z0-9]+&|&Itemid=[a-zA-Z0-9]+)(&?.*)
    Looks for Itemid= inside the query string
  3. RewriteRule (.*) %{REQUEST_URI}?%1%3 [L,R=301]
    Remove Itemid= string from the URL, using a 301 permanent redirect
  4. RewriteCond %{QUERY_STRING} (.*)(^lang=[a-zA-Z0-9]+&?|^&lang=[a-zA-Z0-9]+&|&lang=[a-zA-Z0-9]+)(&?.*)
    Looks for lang= inside the query string
  5. RewriteRule (.*) %{REQUEST_URI}?%1%3 [L,R=301]
    Remove the string from the URL using a 301 permanent redirect
  6. RewriteCond %{QUERY_STRING} ^(.+&)option=com_virtuemart(.+)?$ [NC]
    Looks for the string option=com_virtuemart in the middle and at the end of the query string
  7. RewriteRule ^index\.php$ http://%{HTTP_HOST}/shop$1?%1%2 [R=301,L]
    Rewrites option=com_virtuemart to /shop and remove /index.php, using a 301 permanent redirect
  8. RewriteCond %{QUERY_STRING} ^(.+&)?option=com_virtuemart&(.+)?$ [NC]
    Looks for option=com_virtuemart just after index.php
  9. RewriteRule ^index\.php$ http://%{HTTP_HOST}/shop$1?%1%2 [R=301,L]
    Rewrites index.php?option=com_virtuemart to shop, using a 301 permanent redirect

With those rewrites, we have removed all the duplicates products, moving from the url /index.php?option=com_virtuemart&page=shop.browse&category_id=29&lang=it&Itemid=233 to the url /shop?page=shop.browse&category_id=29

Since we have used permanent redirects, Google and other search engines will know the duplicate pages have moved permanently to the last one and in some weeks your VirtueMart website won’t have any duplicate anymore.

WARNING: this htaccess needs to be deeply understood before you can use it in your website; it WILL NOT WORK in your VirtueMart store just copying-pasting it!

The original post, in Italian, is located here: How to remove duplicate products in virtuemart.

Joomla 1.5 center banner modules

June 8th, 2009

A common problem with Joomla 1.5 is centering banners placed in the left or on the right side.
We create a new banner from COMPONENTS -> BANNER , the banner is displayed but never centered.
The solution to this problem is editing the file modules/mod_banners/tmpl/default.php : we need to tell Joomla to center each element.

You must edit this portion of the file

foreach($list as $item) :
?><div class=”banneritem<?php echo $params->get( ‘moduleclass_sfx’ ) ?>”><?php
echo modBannersHelper::renderBanner($params, $item);
?><div class=”clr”></div>
<?php endforeach; ?>

and we must add the <center> … </center> directive, thus having:

foreach($list as $item) :
?><center><div class=”banneritem<?php echo $params->get( ‘moduleclass_sfx’ ) ?>”><?php
echo modBannersHelper::renderBanner($params, $item);
?><div class=”clr”></div>
<?php endforeach; ?>

Save the file and exit, it should work fine ;)

Joomla 1.5 – 500 Internal Server Error

April 28th, 2009

After installing Joomla on a Godaddy shared server (Deluxe plan which allow unlimited websites), I renamed htaccess.txt into .htaccess to allow url rewriting.

Home page is fine, but the first article created and linked to the main menu returned this error
Internal Server Error
The server encountered an internal error or misconfiguration and was unable to complete your request.

Please contact the server administrator, and inform them of the time the error occurred, and anything you might have done that may have caused the error.

More information about this error may be available in the server error log.

The solution to the INTERNAL SERVER ERROR problem is uncommenting the following line in .htaccess (or in htaccess.txt if you didn’t already rename it).

# RewriteBase /

You must remove the # , thus having in your .htaccess

RewriteBase /

Reload the page and everything should be fine !

Upgrading Joomla 1.5 for multiple websites

April 14th, 2009

Upgrading joomla to the latest version is very easy

  1. Download the patch to the current stable version (joomla download page)
  2. Unpack the patch
  3. Upload the patch to your server overwriting old files

Few days ago Joomla has been updated to version 1.5.10 because of some security vulnerabilities.

Upgrading to Joomla 1.5.10 from Joomla 1.5.9 is straightforward, the required patch is 1.5.9 to 1.5.10 Upgrade Package

Upgrading Joomla 1.5 for multiple websites

My problem was upgrading 20 joomla installations automatically, not manually.

Each website has the Joomla SEO Patch, which has to be upgraded too, after the Joomla core upgrade.

I created a bash script to do everything automatically.

I use this directory structure for my websites: every domain is linked to a directory of my dedicated server, located in /var/www/websites

So I have




I downloaded the 1.5.9 to 1.5.10 Upgrade Package to /root directory, I unpacked it using the command unzip in the directory /root/PATCH-1.5.9–1.5.10

I also downloaded the Joomla 1.5.10 SEO PATCH and unpacked it into the directory /root/PATCH-SEO

The script for a Joomla automatic upgrade is the following

cd /var/www/websites

for F in `ls -1`; do chattr +i $F/robots.txt; chattr +i $F/.htaccess; done

for D in `ls -1`; do cp -r /root/PATCH-1.5.9–1.5.10/* $D ; done

for D in `ls -1`; do cp -r /root/PATCH-SEO/* $D ; done

The first line changes your CWD (current working directory)

The second makes your robots.txt and .htacces immutable, thus avoiding overwriting.

The third line patches Joomla

The last line applies the Joomla Seo Patch

Have fun

BE CAREFUL, those commands worked for my dedicated server, your configuration and/or installation paths and versions will probably be different!!!

MCrypt – phpmyadmin: cannot load mcrypt extension

January 11th, 2009

Using phpmyadmin frontend to manage your database is straightforward. Just put in the address bar of your browser your server ip address followed by /phpMyAdmin (for example: .

Using it on my Godaddy Virtual Dedicated Server (VDS) showed a little warning: “cannot load mcrypt extension”

What is mcrypt?
Mcrypt is an encryption library which supports various algorithms like DES, TripleDES, Blowfish, TWOFISH, 3-WAY, SAFER-SK64, SAFER-SK128, TEA, RC2 and GOST in CBC, OFB, CFB and ECB cipher modes.

How to install mcrypt under Fedora Core 7 ?
Very easy, simply write these commands as root:

yum install libmcrypt
yum install php-mcrypt*
yum install php-mhash*
service httpd restart

Reload your phpMyAdmin page, and the warning won’t show again.

Godaddy Virtual Dedicated Server

January 9th, 2009

Like me, hundred of persons were wasting their money with 10 or 20 different shared hosting accounts at godaddy.
Once one figures out how much a VPS – Virtual Private Server (or VDS – Virtual Dedicated Server) costs, the following question arise: why am I paying $100 per month for 20 different shared hosting accounts when I can purchase a Virtual Dedicated Server for a cheap price?!?

The decision involves an analysis of dedicated server pros and cons.

VDS pro:
- unlimited website hosting (just realize how to use Apache Virtual Hosts – VHosts)
- very large bandwidth
- very large disk space
- ssh, ftp, mysql, phpmyadmin, … access
- unlimited root access
- no bad neighbours (spam, casino or porn sites)

VDS cons:
- you must achieve security yourself
- you are responsible about all aspects of your server

I decided to switch from shared hosting to VDS and I am very happy with it!

If you need help in choosing your godaddy package or simply need additional informations, leave a comment!

Joomla: “Error loading Modules”

December 15th, 2008

I’ve been playing with the generic and useless message generated by Joomla 1.5.8 : “Error loading Modules
This problem appeared while using Jumi, a Joomla plugin enabling custom scripts and file inclusion into articles, to include a php script which performs several sql queries.
I used Joomla + Jumi for a long time, without any problem. Now that I’ve moved from a Godaddy Shared Hosting to a Godaddy Virtual Dedicated Server, this problem has appeared.
What the hell was causing that weird message? And why no modules were showing in my page?
After wasting lot of time googling, I realized something with the MySql connection wasn’t fine.
I tried modifying all settings in my.cnf with no luck, I rewrote the script, I reinstalled Jumi… Nothing!
Before giving up, I looked into the manuals.
Mysql has a “weird” behaviour: if you open 100 connections to 100 different databases in the same server, MySql uses the same connection id for each connection!
So if you do
$db1 = mysql_connect($host, $user, $pass);
$db2 = mysql_connect($host, $user, $pass);
mysql_select_db(‘db1′, $db1);
mysql_select_db(‘db2′, $db2);
you get a race condition: only db2 is selected.
That’s why my modules didn’t show !

What to do?
My workaround to fix the “multiple connections problem” with MySql is the following:
$host1 = “localhost”;
$host2 = “″;
$host3 = “″;
$host4 = “localhost:3306″;
$db1 = mysql_connect($host1, $user, $pass);
$db2 = mysql_connect($host2, $user, $pass);
$db3 = mysql_connect($host3, $user, $pass);
$db4 = mysql_connect($host4, $user, $pass);

Hope it helps!
Any comment is welcome!

References: (Italian)