Blog

Finally got my custom WordPress permalinks working

March 23, 2006 at 6:15 pm | In tech |

Note: This post is continued and ammended in my next post. Please be sure to read that as well to get the full picture and correct code.

Boy do I feel guilty. I’ve reverted to my comfort zone, writing code, at the expense of marketing activities. I did make a few phone calls, mind you, but I need to put my salesman hat back on, and really tighten up the chin strap so it doesn’t fall off so easily next time. It’s a weakness of mine: give me a good, worthwhile challenge, and I can’t stop until it’s done. Well, at least I take comfort in that it seems I did solve a nagging problem that plagues some WordPress users.

WordPress allows you to define custom permalink structures for your posts, and this seems to work fine for most people. For example, instead of the URL for a post being in the form: /blog/?p=22, the URL can be /blog/name-of-the-post.php. The second URL is favored by search engines, since it supports the content of the page. However, this functionality relies on the web server using the “mod_rewrite” module to read the “.htaccess” file for instructions on how to perform the necessary redirections, and if you are not running your own web server, you are at the mercy of your web host to provide this functionality. Alas, my host does not, so it seemed I was stuck with ugly URLs.

My research into this problem only revealed there are some very frustrated users out there, and that even with a working mod-rewrite module, getting custom permalinks to work in WP was a hit-or-miss affair. Most of the suggested solutions were of the “reinstall everything” variety. I even ran across several threads where someone discovered they did not have the mod_rewrite module installed, so they switched hosts. Well, I didn’t want to do that, so I came up with my own workaround instead.

The way WP implements permalinks is pretty slick (when it works). Instead of actually creating a complex folder structure for all the categories, archives, and posts, all pages are really served by the same file from the same location, /blog directory/index.php, with a query appended to the URL so it knows what to serve up: a category, an archive, or an individual post. Then, when blog pages are generated, all the category, archive, and post links are written according to the custom permalink structure. So, even if the link to an archive is /blog/2006/03/, there really is no such directory, but the link works anyway because the server itself redirects the request back to /index.php, according to the instructions in the .htaccess file. One of the big advantages to this scheme is that the permalink structure can be changed at any time, and there is no need to go and re-name or re-shuffle a bunch of directories and files when you do so. The only things that change are the links on the pages, and the .htaccess file.

Ok, I could not use an .htaccess file, so I was pretty much forced to do the redirections myself. This meant actually creating the nested category and archive folders, and placing a single index.php file in each of them, that redirected the request back to the base folder, to a new file I created, that did the final redirect to index.php. Also, since the custom permalink structure I wanted was: /%postname%.php, I also had to create a file for each post, each one named name-of-post.php that also redirected requests to my new redirect.php file, so it could do the final redirect to index.php.

This sounds complicated, but it’s not that bad, and once it is set up, there is little maintenance involved. Obviously the biggest drawback is that I have to remember to create a new name-of-post.php file every time I make a new post. Also, I need to know the cleaned-up post name that WP will use for the permalink. This could probably be handled with a plug-in, but I’ll leave that as an exercise for the interested reader. For now, I’ll make theses file manually. All I have to do is copy and rename an existing one, so it’s not that bad. The same goes for any new categories I create in the future.

Another drawback to this implementation is that the final URL the user sees is the ugly one, without my custom permalink. I guess I’ll have to live with that, and since this was mostly done to appease the Google God, it should be ok. I did read that the preferred redirection external linkfor search engines is a “301 – permanent move”, but according to the RFC 2616 - Hypertext Transfer Protocol — HTTP/1.1 external link documentation, this will cause the requester to update the URL that was used to the new, redirected one, which would negate any benefit from the custom URL. Instead, I opted to use the default “302 – found” header that PHP sends with the redirect, that signals to the requester that this is a temporary move that might change, so please continue using the original URL. I hope this works.

Do you suppose the Googleites went to the trouble of seeing how long a “temporary” redirect is in effect, and penalize those who use it too long? Should I cower in fear, afraid that gGod might see my impudence, and banish me from his holy index? Whatever. – Hey, if that happens, I’ll put out a press release and get all sorts of attention, right?

Will this be my last tech post? Hardly – there is plenty to do on the site still – at least 4 of the remaining to-do items are tech, and that’s even before I get into expanding AustinMania! But, I think I will be unhappy with myself I don’t get out there and sell more ads. Pixels, anyone?

This is the index.php code that went in every category folder - /blog/categories/austin/index.php, for example:<?php
$path = dirname($_SERVER['PHP_SELF']);
$position = strrpos($path,'/') + 1;
$thisDir = substr($path,$position);
header("Location: ../../redirect.php?cat=$thisDir"); exit;
?>

This is the index.php code that went in every archive folder - /blog/2006/03/index.php, for example:<?php
$path = dirname($_SERVER['PHP_SELF']);
$position = strrpos($path,'/') + 1;
$thisDir = substr($path,$position);
header("Location: ../../redirect.php?m=2006$thisDir"); exit;
?>

Every year, I’ll have to copy the previous year’s folder set, and edit this file to change the year on the last line.

This is the contents of every “name-of-post.php” file:<?php
$path = $_SERVER['PHP_SELF'];
$position = strrpos($path,'/') + 1;
$thisPost = substr($path,$position,-4);
header("Location: redirect.php?p=$thisPost"); exit;
?>

This is the redirect.php file code that receives all the redirects above:<?php
require_once('wp-config.php');

$URLquery = "";

if (array_key_exists("cat",$_GET)) {
$catName = $_GET['cat'];
$catID = get_object_vars($wpdb->get_row("SELECT cat_ID FROM $wpdb->categories WHERE cat_name = '$catName' LIMIT 1"));
$catID = $catID['cat_ID'];
$URLquery = "?cat=$catID";
}

if (array_key_exists("m",$_GET)) {
$month = $_GET['m'];
$URLquery = "?m=$month";
}

if (array_key_exists("p",$_GET)) {
$postName = $_GET['p'];
$postID = get_object_vars($wpdb->get_row("SELECT ID FROM $wpdb->posts WHERE post_name = '$postName' LIMIT 1"));
$postID = $postID['ID'];
$URLquery = "?p=$postID";
}

header("Location: index.php$URLquery");
?>

No Comments yet »

RSS feed for comments on this post.
Trackback URI for this post:
http://austinmash.com/blog/finally-got-my-custom-wordpress-permalinks-working/trackback/

Leave a comment

XHTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <code> <em> <i> <strike> <strong>