Zovirl Industries

Mark Ivey’s weblog

My Conversion to Cool URIs

The Beginning

Out of the box, Blosxom comes with two URL styles for stories and one for categories. URLs for stories can be date-based (http://example.com/2003/12/26#duck.html) or category-based (http://example.com/photography/nature/duck.html). Categories get only category-based URLs (http://example.com/photography/nature/index.html).

After reading several articles on URL design, I decided I wanted something different than what Blosxom gave me. Especially influential were Jakob Nielsen’s URL as UI and Tim Berners-Lee’s Cool URIs don’t change. Tanya Rabourn has also posted a nice list of articles on URI design. After reading those articles, I decided I wanted to have URIs which I could keep forever, without breaking them.

The Plan

The URI format I decided to use is similar to Blosxom’s category-based format, except every URI is extensionless and begins with the creation date of that URI: http://example.com/2003/12/26/photography/nature/duck.

Advantages of this format:

Disadvantages of this format:

The Implementation

While reading all the articles I saw a lot of material on how to design URIs and very little material on how to implement them. Getting Blosxom to use my new URI format ended up being more work than I expected. There were two main problems to solve: Blosxom had to generate the new URLs when it served content, and Blosxom had to recognize the new URLs when a client requested something.

I wrote the cooluri2 plugin to make Blosxom recognize the new URLs. The plugin is more complicated than I would like but it works.

Getting Blosxom to generate the new URLs took several plugins. The main one is permalink, which provides permalinks for stories and can be used by other plugins when they need a URL generated. Some files, like binary files and directories, can’t contain metadates and since the new scheme needs dates for everything, I wrote the metadate plugin. It lets metadates reside in an external file, so I can use metadates for all my categories. Finally, I patched the absolute plugin so I can easily reference other stories/files/categories.

Finally, when it comes time to reorganize my site I can do it freely. If I want to change a document’s URI (by moving it or changing the date on it) the old URI can be replaced with a 301 redirect to the new URI.

The Results

The new URI format requires several plugins but adds very little overhead when I’m just writing articles. The only extra thing I have to remember is to update my external metadate file when I add new directories or non-story files (if I forget then the modification time of the file is used, so nothing terrible happens, but I prefer to use metadates since last-modification times are fragile). By including only the year and not the full date in the URI there is very little cruft added. Overall I’m pleased with the results.

CoolURI2

This plugin makes Blosxom recognize date-based, extensionless URIs (aka Cool URIs) for both stories and categories. If you are using the static_file plugin, Cool URIs will be recognized for static files also. The main motivation for this URI format is that links never have to break…ever. Goodbye 404 errors! You can read Tim Berners-Lee’s essay for more details on why Cool URIs are cool.

The idea for this plugin was based on the cooluri plugin written by Rob Hague, which makes Blosxom recognize extensionless URIs. Along with Blosxom’s built-in ability to recognize date-based URIs for stories, cooluri did almost what I wanted. It didn’t handle date-based URIs for categories however.

I wrote cooluri2 to do both. Now categories, stories, and static-files all can be referenced by cool URIs, like this:
http://example.com/2003/12/03/category
http://example.com/2003/12/14/category/story

Days and months can be left off if you prefer a shorter URI:
http://example.com/2003/12/category
http://example.com/2003/12/category/story
http://example.com/2003/category
http://example.com/2003/category/story

The date part of the URI is the creation date for that document. Note that stories may have different creation dates then the categories they are in, so you may end up with URIs like this:
http://example.com/2003/10/23/category
http://example.com/2003/12/14/category/story

If you use the cooluri2 plugin, you might want to read about how I converted my site to use Cool URIs.

Download cooluri2 0.0.1

Documentation is available here.

Uselib

Occasionally a blosxom plugin needs a perl module that isn’t installed on the server, such as MIME::Types or File::Cat. For users who don’t have administrative access on their server, there has been no official place to install such modules. Additionally, users then needed to modify blosxom.cgi or the plugin to have it search the correct location.

This plugin attempts to help the situation by telling Perl to look for modules in $blosxom::plugin_dir/lib. This gives a standard place to install to (for example, File::Cat comes with one file, Cat.pm, which would go in $blosxom::plugin_dir/lib/File) and also means that users don’t have to modify anything to get perl to find the new module.

Note: uselib needs to be loaded before plugins requiring extra perl modules. You can do this by renaming it to something like 01uselib.

Download uselib 0.0.1

Update:Documentation is now available here.

Pictures

So, I wanted to be able to post pictures. Seemed like a simple enough idea but I ran into a lot of problems. I tried 3 different plugins:

autoimg replaces simple tags in the story with html img tags. It was the easiest of the 3 to use, but didn’t do a good job on the layout. On short stories, images would interfere with the next story. Also, autoimg wanted images to come out of my website’s directory, not the directory where I keep blosxom stories. While this might normally be a Good Thing (separation of content and presentation), in my case the pictures are the content.

binary intercepts URLs passed to blosxom and checks to see if the file exists. If it does, it gets served up. Otherwise, blosxom.cgi gets to deal with the URL normally. This lets me store my images in the blosxom story folder, right next to my text files. It had several bugs, however, and I gave up on it.

static_file is a rewrite of binary. It works much better for me. Combined with interpolate_conditional, it is very close to what I wanted.

Here is an example. In my story, I have this:

<a href="poppies.png">  <img src="poppies.thumb.png" alt=[poppies]"/> </a>

The .png images are sitting in the same directory as the .txt file for this story. interpolate_conditional generates the proper URLs, and static_file catches the requests and serves up the right images:

I would like an easier way to add images than entering raw html source, but for now I am happy. Oh, and in case you are wondering I modified interpolate_conditional so it would pass those $’s through when it sees two in a row. Here is the patch

Update: I also made a patch for static file to make the default MIME type configurable.

Timezone

I want the timestamps on postings to use the PST/PDT timezone, but my server is set to to EST/EDT. I grabbed Raffi Krikorian’s timezone plugin but couldn’t get it to work. Turns out I had to rename it from “timezone.plugin” to “timezone”, after which it works perfectly. I still want the timezone appended on the timestamps (so it would say “posted at: 22:25 PST”, for example).

Update: I’ve updated the timezone plugin so it now exports the timezone for use by flavours.

Hello World

Just got this site up today. This is, surprisingly, the first time I’ve had my own web page. TR from genetikayos.com was the one who finally motivated me to make this page, and he is also kindly providing hosting. I’ve settled on using bloxsom to run the site. It meets my 2 requirements of being free and simple. I was able to get it up and running in about 30 minutes. So far, so good.

Update: I’ve run into a few problems with blosxom. Basically, the further I go with blosxom, the more uncharted the territory feels. It turns out I’m not alone either. Blosxom has a very strong community though, so I haven’t given up hope yet.