Thursday, June 23, 2005

How-to: Static pages in Blogger

A while ago, I wanted to add a couple of static pages to my blog; a static page being one which falls outside the rigid reverse-chronological blogging timeline. In my case, I wanted to use them as poor man’s category archives, to hold lists of hike writeups and movie reviews.

This isn’t easy to do in Blogger. Blogger isn’t a general-purpose content management service; it’s built around the central blogging concept of sequential dated posts.

So, the trick to static pages is twofold: disguise a dated post as an undated page; and prevent such posts from appearing in Blogger’s generated main and archive page content. Blogger’s templating language does not allow conditional generation at the level of individual posts (the Blogger conditional tags allow conditional behaviour only on the type of page—main, archive, item—being generated) which leaves two other options for tweaking individual posts: styling them with CSS, or massaging them with Javascript. I went with the CSS option.

The key to styling individual posts with CSS is Blogger’s <$BlogItemNumber$> template tag; this expands to an item number unique to each post. Armed with this tag, we can apply a unique class attribute to all posts and links to posts; and then we can use a CSS class selector to hide static posts and links to them.

So, templating. First, edit the template to wrap a <div> around the entire post:

<div class="post-<$BlogItemNumber$>"> date header, blog item, blog comments etc...

This gives us an class we can later select on to suppress display of the entire post on main and archive pages. But we also want to suppress display of the date on static pages; to allow this, wrap a <div> around the post’s date header:

<div class="date">
<BlogDateHeader> heading...

and a <span> around the timestamp in the post’s byline:

<span class="date"><$BlogItemDateTime$> | </span>

And finally, we want to suppress display of links to static pages from any sidebar lists of current or previous posts. To do this, apply a class attribute to the list item for each post. In my sidebar, I list posts on the current page, so:

<li class="post-<$BlogItemNumber$>"><a href="#<$BlogItemNumber$>"><$BlogItemTitle$></a></li>

Note that the class is the same as the one we applied to the post; this will let us hide both post and link with a single CSS selector.

OK: time to add a static page. Add it by creating a new post. And the best date to apply to the posts: 12:00AM on the date of your first weblog post. Two reasons for this:
  1. Dating it early keeps them outside the horizons of your blog’s Atom feed, ensuring that updates to the post won’t be broadcast as updated items in the feed.
  2. Putting it on a day containing a normal post means we don’t need to suppress that day’s date header from the archive page template.
While you’re editing the post, make a note of the post’s item number; you’ll see it in the Edit page’s URL:

Publish it, view the first month of your blog’s archives, and you’ll see the new post. Now to hide it. But before you do, make a note of it’s permanent link; once it’s hidden, the only way to get to it is for you to explicitly link to it.

To hide the post, revisit the template and add the following lines in the <style> section of the header, using the item number you noted above:

.post-YYYYYYYYYYYYYYYYYY <ItemPage>.date</ItemPage> {display:none;}

This rule suppresses display of the entire post, and of links to it, on all but item pages; on item pages, it suppresses display only of the post’s date header and timestamp.

Done: we have created a page which appears to sit entirely outside the chronological flow of the blog, but which still inherits the styling and commenting of a blog entry. The only remaining hint that it is a dated blog entry is its calendar-dated URL.

The <$BlogItemNumber%> tag has plenty of other uses for Blogger hacking. As it’s unique to each post, it lends itself very neatly to forming unique id attributes on tags, for later targeted manipulation by Javascript code using the document.getElementById method. Blogger’s own article on peek-a-boo comments, a variation of which I’m using here, uses just this technique. More Javascripting later.