[ic] Rewriting URLs for SEO purposes - help!

Jamie Neil jamie at versado.net
Mon Apr 11 08:20:37 EDT 2005


Cameron G wrote:
> Which is nice, except I'm still left with a URL that isn't terribly search
> engine happy. That's why when a client wants to buy a claw hammer, I'd like
> the url for him to read
> 
> http://www.store.com/hammers/clawhammer.htm
> 
> Or even
> 
> http://www.store.com/hammers.htm
> 
> And have that invisibly map to whatever it needs to in the background, all
> the while presenting that clean, simple, keyword happy URL to both the
> client and the SE bots. 

There's two stages to this:

1) Use URL rewriting to clean up the root path.

2) Use an actionmap to convert the rest of the path to a search.

Here's how we do it:
--------------------

httpd.conf
----------
...
RewriteEngine on
RewriteRule ^$ /cgi-bin/domain/index.html [PT,L]
RewriteRule ^/$ /cgi-bin/domain/index.html [PT,L]
RewriteRule ^/index\.html$ /cgi-bin/domain/index.html [PT,L]
RewriteRule ^/.*\.css - [PT,L]
RewriteRule ^/.*\.ico - [PT,L]
RewriteRule ^/robots.txt - [PT,L]
RewriteRule ^/cgi-bin/domain/.* - [PT,L]
RewriteRule ^/stats/.* - [PT,L]
RewriteRule ^/images/.* - [PT,L]
RewriteRule ^/js/.* - [PT,L]
RewriteRule ^/interchange-5/.* - [PT,L]
RewriteRule ^/(.*) /cgi-bin/domain/$1 [PT,L]
...

catalog.cfg
-----------
...
ActionMap  dept  <<EOR
sub {
   my ($action, $deptid, $categoryid, $mfrid) = split ('/', shift);
   my $dept = $Tag->data( { table => dept, field => name, key => $deptid 
} );
   $CGI->{deptid} = "$deptid";
   $CGI->{dept} = "$dept";
   $CGI->{mv_coordinate} = 'yes';
   $CGI->{mv_search_file} = 'products';
   $CGI->{mv_searchtype} = 'db';
   $CGI->{mv_todo} ='search';
   $CGI->{mv_return_fields} = 
'sku,manufacturer,prod_group,category,option_type,thumb,image,description,comment,tax_category,nontaxable,price';
   $CGI->{mv_sort_field} = 'category,manufacturer,price,description';
   $CGI->{mv_sort_option} = 'f,f,n,f';
   $CGI->{mv_search_field} = "prod_group";
   $CGI->{mv_column_op} = "rm";
   $CGI->{mv_searchspec} = "$deptid";
   if ($categoryid) {
     my $category = $Tag->data( { table => cat, field => name, key => 
$categoryid, foreign => name } );
     $CGI->{categoryid} = "$categoryid";
     $CGI->{category} = "$category";
     $CGI->{mv_nextpage} = 'category';
     $CGI->{mv_search_field} .= "\0category";
     $CGI->{mv_column_op} .= "\0rm";
     $CGI->{mv_searchspec} .= "\0$category";
     if ($mfrid) {
       my $mfr = $Tag->data( { table => manufacturers, field => name, 
key => $mfrid, foreign => name } );
       $CGI->{mv_search_field} .= "\0manufacturer";
       $CGI->{mv_column_op} .= "\0rm";
       $CGI->{mv_searchspec} .= "\0$mfr";
       $CGI->{mfrid} = "$mfrid";
       $CGI->{mfr} = "$mfr";
       $CGI->{banner_text} = "$mfr $category";
     }
     else {
       $CGI->{mfrid} = '';
       $CGI->{mfr} = '';
       $CGI->{banner_text} = "$category";
     }
   }
   else {
     $CGI->{categoryid} = '';
     $CGI->{category} = '';
     $CGI->{mfrid} = '';
     $CGI->{mfr} = '';
     $CGI->{mv_nextpage} = 'dept';
     $CGI->{banner_text} = "$dept";
   }
   $Tag->update('process');
   return 1;
}
EOR
...

--------------------

This allows URLs like this:

http://www.domain.com/dept/widgets.html ->
   http://www.domain.com/cgi-bin/domain/dept.html?
     deptid=widgets&
     dept=Widgets&
     mv_coordinate=yes&
     mv_search_file=products&
     mv_searchtype=db&
     mv_todo=search&
     mv_return_fields=sku,manufacturer,prod_group,category,option_type,
       thumb,image,description,comment,tax_category,nontaxable,price&
     mv_sort_field=category,manufacturer,price,description&
     mv_sort_option=f,f,n,f&
     mv_search_field=prod_group&
     mv_column_op=rm&
     mv_searchspec=widgets&
     categoryid=&
     category=&
     mv_nextpage=dept&
     mfrid=&
     mfr=&
     banner_text=Widgets

http://www.domain.com/dept/widgets/bigwidgets.html ->
   http://www.domain.com/cgi-bin/domain/category.html?
     deptid=widgets&
     dept=Widgets&
     mv_coordinate=yes&
     mv_search_file=products&
     mv_searchtype=db&
     mv_todo=search&
     mv_return_fields=sku,manufacturer,prod_group,category,option_type,
       thumb,image,description,comment,tax_category,nontaxable,price&
     mv_sort_field=category,manufacturer,price,description&
     mv_sort_option=f,f,n,f&
     mv_search_field=prod_group\0category&
     mv_column_op=rm\0rm&
     mv_searchspec=widgets\0bigwidgets&
     categoryid=bigwidgets&
     category=Big%20Widgets&
     mv_nextpage=category&
     mfrid=&
     mfr=&
     banner_text=Big%20Widgets

http://www.domain.com/dept/widgets/bigwidgets/acme.html ->
   http://www.domain.com/cgi-bin/domain/category.html?
     deptid=widgets&
     dept=Widgets&
     mv_coordinate=yes&
     mv_search_file=products&
     mv_searchtype=db&
     mv_todo=search&
     mv_return_fields=sku,manufacturer,prod_group,category,option_type,
       thumb,image,description,comment,tax_category,nontaxable,price&
     mv_sort_field=category,manufacturer,price,description&
     mv_sort_option=f,f,n,f&
     mv_search_field=prod_group\0category\0manufacturer&
     mv_column_op=rm\0rm\0rm&
     mv_searchspec=widgets\0bigwidgets\0acme&
     categoryid=bigwidgets&
     category=Big%20Widgets&
     mv_nextpage=category&
     mfrid=acme&
     mfr=Acme&
     banner_text=Acme%20Big%20Widgets

Notes:
------

All this is based on the standard foundation demo with an additional 
"manufacturer" field and table.

Eliminating the "dept" is possible (I think) but would require more 
complex rewrite rules with exceptions to avoid clashes with "static" IC 
pages, so maintainance would be tricky.

In order to deal with Title Case and other naming issues, I use an "id" 
for the search which is then looked up in the relevant table using the 
data tag in order to get the proper name e.g. bigwidgets->Big Widgets.

The category page uses the "mfrid" cgi value to determine whether to 
display _all_ products in a category or just a particular 
manufacturer's. I could have done the same with prod_group, but as my 
dept and category pages look quite different I decided against it.

In order to stack mv variables you need to separate them with nulls 
(\0). I'm not sure how this is normally displayed in the actual query 
string so I just put then in as \0 to indicate the point.

-- 
Jamie Neil | <jamie at versado.net> | 0870 7777 454
Versado I.T. Services Ltd. | http://versado.net/ | 0845 450 1254


More information about the interchange-users mailing list