Using A Canonical URL

Websites that can be accessed from multiple URL’s aren’t very search engine friendly.

Sometimes this structure may have evolved by accident as a site was developed at different times on varying technologies. You don’t want to turn off the old links as that would loose valuable search engine equity, but you don’t want them scattered on multiple URL’s either.

There is a solution, and that is to use a canonical URL.

The easiest is to add a simple link element to the page with it’s correct canonical URL. For example, if we have a page that can be reached at www.example.com/test.html, example.com/test.html or beta.example.com/test.html. we only want this to be index at www.example.com/test.html, so we can use add a link element as follows…

<link rel="canonical" href="http://www.example.com/test.html" />

Notice the use of rel="canonical", this is tells a search engine if it has accessed the page from another URL, it’s actually meant to be indexed from this URL.

Google, Yahoo and Microsoft have all agreed to support this canonical link element.

Another approach is to redirect the user to the page on the correct URL server side. Using Apache, this can be done using a RewriteRule and couple of RewriteCond‘s.

Using the same example, the rewrite rule would be something like this

RewriteEngine on
RewriteCond %{HTTP_HOST} !^www.example.com [NC]
RewriteCond %{HTTP_HOST} !^$
RewriteRule ^/(.*) http://www.example.com/$1 [L,R=301]

Here we make sure we’re not already accessing using the correct domain name. If we aren’t, the we redirect using the L flag to make sure this it’s the last rule run, and R=301 to issue a 301 Moved Permenantly redirect. Anyone visiting the page on an incorrect domain, will now be redirected to the right page.

Alternating Table Rows With JavaScript And jQuery

One of the most popular stories on this website is on Alternating Table Rows With Template Toolkit And CSS. The example I use is how to stripe alternate rows in an HTML table by applying a seperate class to each row.

As I’ve been learning jQuery lately, I thought I’d update this example to show how to do it using this excellent JavaScript framework.

Firstly, we need to setup our styles. We’ll have a lite and a dark class to use that will just set a different background colour.

<style type="text/css">
.lite {background-color: #ddffff;}
.dark {background-color: #aaffff;}
</style>

We’ll also need an example table.

<table class="stripe">
<tbody>
<tr>
<td>1</td><td>One</td>
</tr>
<tr>
<td>2</td><td>Two</td>
</tr>
<tr>
<td>3</td><td>Three</td>
</tr>
<tr>
<td>4</td><td>Four</td>
</tr>
<tr>
<td>5</td><td>Five</td>
</tr>
</tbody>
</table>

Notice how I have given the table a class of stripe. This is important, I’m going to use jQuery to only select table elements that have this class name, else every table on the page would be striped.

The jQuery to achieve the striping is actually very simple.

<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript">
$(document).ready(function() {
$('table.stripe>tbody>tr:even').addClass("lite");
$('table.stripe>tbody>tr:odd').addClass("dark");
});
</script>

Firstly we added the jQuery library to the page. Next we setup our striping code to only run once the DOM is place. This is important as we’re going to be selecting and manipulating over the DOM next. The next two lines apply the lite class to even table rows and the dark class to odd table rows. Let’s look at this in a bit more detail.

The selector $('table.stripe>tbody>tr:even') is easier to explain backwards. We look for even matching tr elements, that have a parent of tbody, that has a parent of table with a class of stripe. The use of the > symbol instead of just a space is to make sure the elements are direct parent and child elements instead of just ancestor and descendant. Why is this important? Well if we used a space any nested tables that happened to have an striped ancestor would also be striped. This isn’t normally what we’d want to happen.

Retargetting Selected Links With JavaScript

At work I have a new site that makes use of iframes to embed external content onto a page. The content is a blog, written by non technical members of staff who needed to be able to include links to external websites. They are happy with using <a href=" tags, but I didn’t want to worry them with target parameters in the HTML. We have to target _blank as we want the readers to keep the old site open and not open the content in the site framework.

The solution to this is to use a bit of JavaScript to manipulate the DOM and insert blank targeting to all blog entries.

As we control the HTML template of the blog, we made sure all the blog entries were wrapped by an enclosing div tag with a class called blogentry.

Here’s some example HTML. We have one link in the blogentry div we need to re target. The other link is not in a blogentry so has to be ignored.

<div class="blogentry">
<a href="http://www.robertprice.co.uk/">This link needs to open in a new window</a>.
</div>
<div>
<a href="http://www.robertprice.co.uk/">This link won't open in a new window</a>.
</div>

The JavaScript first has to get all div tags on the page. It does this by calling getElementsByTagName on the document. Once we have all the div tags, we have to iterate over them to make sure we only get the ones with the classname of blog entry.

var entries = document.getElementsByTagName('div');
for (var i in entries) {
if (entries[i].className == "blogentry") {
// insert target code here.
}
}

Now have our blogentry’s we need to find all the links inside and make sure they all target blank. We do this by calling getElementsByTagName on each node, then setting the target attribute to blank.

var targets = entries[i].getElementsByTagName('a');
for (var j in targets) {
targets[j].target="blank";
}

It’s as simple as that. The full code follows…

<script language="JavaScript" type="text/javascript">
<!--
var entries = document.getElementsByTagName('div');
for (var i in entries) {
if (entries[i].className == "blogentry") {
var targets = entries[i].getElementsByTagName('a');
for (var j in targets) {
targets[j].target="blank";
}
}
}
// -->
</script>