Reserving Slugs for Wordpress

Wordpress Blue LogoAs part of our Apollo WordPress theme, we included a short code for generating a Site Map for a web site. While a useful feature, in the past weeks we decided that we needed a way for all our sites to have a site map page created by default.

The Challenge

Our idea was to add a link to the site map link at the footer of the site, but there was no way we can guarantee that every one of our sites has a site map page already created, let alone that they would have the same URL.

We also wanted the URL to follow the standard WordPress slug format, which meant we couldn’t just add a site-map.php in the directory and call it a day.  Adding a redirect rule in .htaccess wasn’t really appropriate because we only wanted the feature on a specific theme and we have too many sites to have a rewrite rule for each sites.

The Solution

So our solution was to create a template that list all the pages on the site, and then reserve a slug (e.g. http://www.example.com/sitemap) so that all requests hitting that specific URL will be redirected to the template.  This would allow us to add site maps for all our clients without them needing to do any work.

To reserve a slug in WordPress you have to tap in to a couple of the numerous hooks WordPress has in its guts.

    // this hook allows you to check to see if the request url needs
    // to be redirected
    add_action('template_redirect', 'custom_template_redirect');

    // this hook allows you to change the page title if necessary
    add_filter('wp_title', 'custom_title', 10, 3);

This above code registers the hooks so whenever a request comes in, our custom functions (defined below) will execute.

    function template_redirect() {
	global $wp_query;

	if (preg_match('/\/sitemap(|\/)$/i', $_SERVER['REQUEST_URI'])) {

            // make sure the server responds with 200 instead of error code 404
            header('HTTP/1.1 200 OK');
	    $path = locate_template('site-map.php');
	    load_template($path);

            // kill off the request so server doesn't render the 404 message
            die();
	}
    }

We are doing a few things in template_redirect() function here. First, we’re evaluating if the incoming request ends in “sitemap” or “sitemap/” using regular expression. If the request matches, the code will load site-map.php.

Note that we are also explicitly returning a 200 status code. This is because otherwise a 404 status code will be returned to the browser since there actually isn’t http://www.example.com/sitemap page.

Lastly, we kill off the process with die(); because otherwise WordPress will continue to render the 404 error page at the bottom of our sitemap.

    function wp_title($title, $sep, $seplocation) {

	if (preg_match('/\/sitemap(|\/)$/i', $_SERVER['REQUEST_URI']))
		$title = 'Sitemap ' . $sep;

	return $title;
    }

The wp_title function allows you to set page title, otherwise you will get a Page Not Found message in the title.

And that was it.  So far it works, and even though I’m not a big fan of the needing to use die() to terminate the request (it seems kinda hacky), it does work.  And sometimes that’s enough to put one in the win column.