No Smoking

At school we learned how to buy train tickets in French, and in the process discovered we needed to make an alien specification: fumeur ou non-fumeur? British Rail—at it may no longer have been by then, but as I still thought of it—had outlawed smoking on its trains years before. Notices on every window reminded one with threats of sanctions.

The maximum fine was £500, while on the buses it was £2000; a curious incongruity. After all, they were both grubby, unpretentious, overworked components of our public transport network. If anything, the train was a grander mode of transport—and this, I thought, should have been reflected in the fines.

Transport was the prism through which I encountered the world—a world on the move. People stared distractedly at their newspapers or out of the window, attempting to transport their minds from their prosaic surroundings just as the train transported their body through drab suburbia, from Twickenham to Clapham Junction and thence into the city. Rusting gas holders, blackened bridges, concrete tower blocks and horrid bungalows all flowed past as we clattered towards Waterloo. Occasionally one would catch a whiff of illicit cigarette smoke—but not often.

Now smoking has departed that other bastion of public life: the pub. The smokers have been kicked out, just as they were from the buses and trains. But unlike the proletarian local rail and bus networks, where there are no First Class carriages and everyone rides together, pubs and bars exhibit the same stratification as society. Barring undesirables is easy—just price them out. If they can’t afford three-fifty a pint, then by definition they’re the wrong sort.

London is too much in my blood to spurn it easily, but some grey days the grime and money and poverty—and the attitudes they bring with them—just grind me down. Between themselves, Londoners do nothing but moan about their city; put them in a room with someone from anywhere else and they’ll defend it to the death as the greatest in the world. Hardly surprising it didn’t make Monocle’s top 20 liveable cities: ambivalence, for those with open eyes, is our defining attitude.

Detect Current Page Template

On the back of my hooks article last week, here’s another potentially useful WordPress trick I’ve picked up: detecting the current page template.

No SQL required

The beauty of the WordPress API is that in most situations, you can pull the values you need from the database without writing lines of SQL code. For example,

global $post;
get_post_meta($post->ID,'_wp_page_template',true);

This returns the template being used by the current page—for example, running it on my archives page would return the value archives.php, while doing it on my about page would return default. The function get_post_meta is documented in the Codex, but basically, it grabs some data from the wp_postmeta table of the database, which is used to store custom fields, including the post template.

A trip through postmeta land

By using the WordPress-generated $post variable, we avoid having to talk to the database directly; $post->ID returns the ID value of the current post, which can then be checked against the records in wp_postmeta. Since we want to return the page’s template, our second argument calls the key _wp_page_template, so the function will only return values with that key.

By default, the function returns an array, but by setting the third argument to true we can make it return a single result (the first one, although it’s pretty unlikely that a page has two _wp_page_template values. Obviously this technique can be extended to return the values for other custom fields, but I’ll leave that as an exercise for the reader.

The why of it

This trick could be useful for any number of things—I’m using it in Tarski to check whether a given page is an archives page, and to include or exclude certain things based on the result.

Obviously if I were just doing the include directly in the archives template, this wouldn’t be a problem, but since I’m actually calling a hook that’s present in a number of other templates, there’s no way I can tell in advance whether a given page is an archives page or not. In effect, I’m putting the coding burden onto my actions and filters, so as to not impose an overly restrictive system on end-users who might want to do something entirely different.

Coda

As a non-programmer myself, I’m always trying to work out how to do fairly simple things in WordPress. If people are interested, I could carry on writing up these code tips, so let me know what you think in the comments.

Amendment, 5th November 2007

If you’re on the WordPress trunk, instead of bothering with all this malarky just use the is_page_template function which was added in revision 6228. It will be in the 2.4 release when that comes out, and it uses essentially the same technique as I’ve described here, albeit with—as you’d expect—much more complete error handling.

Adding Custom WordPress Hooks

All theme authors should have a vague idea of what WordPress hooks are: those things you have to remember to add to your header to stop plugin authors yelling at you. More technically, they’re a way of adding to or altering the content that WordPress outputs.

There are a fair few built into WordPress, and a number need to be correctly implemented by theme authors, but I don’t propose to go into that here. What I’m going to run through in this article is how you can add your own actions and filters to your theme, to make it more flexible and customisable.

Before I get started, a couple of notes on the WordPress development environment. Firstly, updates break things. When WP 2.1 came out we had to rewrite our SQL code to work with the new database structure. 2.2 brought widgets into the core and the link in Tarski’s Options page (which was pointing to the widgets plugin page) no longer worked. For 2.3 we’re going to have to strip out our UTW code and make the theme work with the new tagging system. In other words, themes need to be kept updated, even though this will destroy any alteration of the theme’s files. Themes should come with tools that allow customisation but don’t require the alteration of core files. Users shouldn’t be deterred from upgrading by the prospect of losing their tweaks—which of course is why plugins exist.

Anatomy of a theme hook

There are two kinds of hooks: actions and filters. This article deals mainly with actions, since they’re generally simpler, but all its lessons can be applied to filters without much difficulty.

Theme hooks are just functions; wp_head is a good example of one. It’s defined in wp-includes/general-template.php, and the definition is amazingly simple:

function wp_head() {
do_action('wp_head');
}

The do_action function that does the hard work, tying the wp_head function into WordPress’s hooks system. It’s incredibly simple to add new hooks in the same way.

Adding custom hooks

There are three steps to adding a custom hook to a theme. Firstly, add the hook function. Secondly, add the action to your theme in the spot where you want it to be executed. Thirdly, you can add a function defining the default behaviour—for example, if you were writing a hook for a header image, you’d need to write something to display a header image. Lastly, tie the two together with add_action. Note that the third and fourth steps are optional; your hook doesn’t have to do anything by default.

Since I’ve been working on adding hooks to Tarski, I’ll use an example from there. Unless stated otherwise, this code is being added to the theme’s functions.php file which is automatically included by WordPress. Below is the action definition: it adds an action named th_header to WordPress’s hooks listing.

function th_header() {
do_action('th_header');
}

I then added the function call to the header template, so that whenever that template file is called it will do whatever actions have been added to the th_header hook:

<?php th_header(); ?>

Originally I was just going to use this to add a header image, thinking that if people wanted to make their header image rotate randomly, or display page-specific headers, they could do that with a plugin. But then I realised I could use the same hook to also display the title and the tagline. To do this, I just reused the existing header image, site title and tagline functions, and then added these lines of code to make the hook call them:

add_action('th_header','tarski_headerimage',5);
add_action('th_header','tarski_sitetitle',6);
add_action('th_header','tarski_tagline',7);

Notice that the first argument is the same for all three lines: th_header. This is the hook to which the actions are being added. The second argument is the actions (which, of course, are just functions which we’ve defined elsewhere). The third argument is the priority—the order in which the actions should be performed. This will make the header display first; then the title; then the tagline.

Tweaking with a plugin

Now the theme has its hooks, how does all this customisation work? It’s very simple—just write a plugin. This can be completely independent of the theme, so you can update the theme without fear of losing your tweaks (because they’re all in the plugin). I don’t propose to cover the basics of plugin development here; try this tutorial, or this one.

First things first: what do we want to do? Well, how about writing a little “About this site” blurb and adding it below the tagline? This is very easy: just add the function to output the blurb to your plugin, and then add an action to the requisite hook.

function output_about_text() {
echo '<p>This site is amazing.</p>';
}

That does it for the text; how about the action?

add_action('th_header','output_about_text');

Notice that we didn’t add a priority; this value defaults to 10, so the about text will be displayed after the tagline. If you want to add it before the header image, for example, try this:

add_action('th_header','output_about_text',4);

Let’s now turn to a more complex example: replacing the header image with page-specific headers. Again, just write the function:

function page_specific_headers() {
if(is_home()) {
echo '<img alt="Home" src="home-page-header.gif" />';
} elseif(is_page('about')) {
echo '<img alt="About" src="about-page-header.gif" />';
} else {
echo '<img alt="Header" src="general-header.gif" />';
}
}

Then we need to do two things: add the new action, and remove the default one.

remove_action('th_header','tarski_headerimage',5);
add_action('th_header','page_specific_headers',5);

This should remove the default header image, and replace it with the page-specific one. Note that the priority needs to be specified for both the action being removed (since it’s set in the default action) and for the action being added (since we want the header to be displayed in the same place, before the title and tagline).

Theme hooks in this mould will be a new feature in Tarski 1.5. If you want to try them out in the meantime, just check out the latest build from our Subversion repository.