First in a series of articles about tinkering with improving your wordpress installation, today we tackle custom 404 error pages; the page everyone dreads getting when they’ve followed an outdated link.
Four-Oh-Fours are hot again! Just recently came a across the article A Better 404. I remember reading the A List Apart article “A Perfect 404” ages ago, but had never done anything about it. Time to improve.
First some quick vocab: the part after your .com (or .co.uk) is called the URI, so if www.google.com/analytics/provision/ is the address, /analytics/provision/ would be the URI. The URI is the part that’s wrong when someone’s followed an outdated link. This means we can use the URI to create a more helpful 404 page. To create a 404 page for your WordPress theme just create a 404.php file in the directory of your theme (/wp-content/themes/default/ is the default).
The default wordpress 404 page code looks something like this:
<?php get_header(); ?>
<h1>Nothing Found (Error 404)</h1>
<?php get_sidebar(); ?>
<?php get_footer(); ?>
Which I suppose is functional enough, but doesn’t actually help the user much, depending on the content of your sidebar. The first thing to do is to tell programmes visiting (browsers and more importantly search engine spiders!) that the page is a 404 error page.
You do that by adding the following to the top of your 404.php:
<?php ob_start(); ?>
<?php header("HTTP/1.1 404 Not Found"); ?>
This “HTTP/1.1 404 Not Found” message tells spiders exactly what they need to know.
Next up, adding useful things for human users! There are three main things you can do to be helpful. Telling the user exactly what’s wrong, giving them a list of related articles and listing your recent articles. Related articles requires some URI magic which I haven’t figured out yet, but Jonathan Hollin has, so stay tuned for an article from him which I’ll link to when the time comes.
Telling the user exactly what’s wrong goes a little something like this:
<?php // When the visitor is linked through by another site or page
if ($_SERVER['HTTP_REFERER']) { ?>
<p>The link at <em><a href="<?php echo $_SERVER['HTTP_REFERER'];?>">
<?php echo chunk_split($_SERVER['HTTP_REFERER'], 25);?>
</a></em> is incorrect or <em><?php echo $_SERVER['REQUEST_URI'];?></em> has been moved, renamed or deleted.</p>
<?php } // When the visitor isn't linked through (most likely a bookmark)
else {
echo "<p><em>" . $_SERVER['REQUEST_URI'] . "</em>";
?>
has been moved, renamed or deleted.</p>
<?php } ?>
As the comments in the code make clear, there are two situations to tailor for: when people come in from another site and when they don’t. A nice addition is “echo chunk_split($_SERVER[‘HTTP_REFERER’], 25)” which echo’s (outputs) the HTTP_REFERER (the site where the user was linked from) in little blocks of 25 characters. This way long URLs still wrap nicely. I chose 25 characters as that’ll put “http://james.gameover.com” all on one line.
That just leaves a list of some recent posts to add:
<h1>Recent Posts</h1>
<ol>
<?php $postslist = get_posts('numberposts=6');
foreach ($postslist as $post) :
setup_postdata($post); ?>
<li><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></li>
<?php endforeach; ?>
</ol>
This code simply outputs a linked title of the 6 most recent journal entries in a numbered list. Simple!
So, to recap, you’ll end up with something like this as your final code in the 404.php file:
<?php ob_start(); ?>
<?php header("HTTP/1.1 404 Not Found"); ?>
<?php get_header(); ?>
<h1>Nothing Found (Error 404)</h1>
<? if ($_SERVER['HTTP_REFERER']) { ?>
<p>The link at <em><a href="<?php echo $_SERVER['HTTP_REFERER'];?>">
<?php echo chunk_split($_SERVER['HTTP_REFERER'], 25);?>
</a></em> is incorrect or <em><?php echo $_SERVER['REQUEST_URI'];?></em> has been moved, renamed or deleted.</p>
<?php } else {
echo "<p><em>" . $_SERVER['REQUEST_URI'];
?>
</em> has been moved, renamed or deleted.</p>
<?php } ?>
<p>Don't worry, just try again!</p>
<h1>Recent Posts</h1>
<ol>
<?php $postslist = get_posts('numberposts=6');
foreach ($postslist as $post) :
setup_postdata($post); ?>
<li><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></li>
<?php endforeach; ?>
</ol>
<?php get_sidebar(); ?>
<?php get_footer(); ?>
You can visit the final 404 error page here. Many thanks to Jonathan M. Hollin for much of the code and ideas, and to the WordPress Codex and php.net for being such handy recourses.
Update: Added “Possibly related content” to my 404 pages, followup post will come later.
5 replies on “Improve your WordPress: the 404 error page”
Very nice stuff this, definately something I’ll look in to.
The 404 header, though, I honestly thought WordPress sent that automatically. It certainly should.
Not automatically sending the correct http-header was a surprise to me too. The code’s so simple, that I don’t understand why it’s included by default.
However, (probably) due to some Apache htaccess magic, the page sends out a 404 anyway, even without the code.
James I have just published a new article describing the additional functionality I added and offering a breakdown of the code. There’s also a full source-code download available.
See: A Better 404 – Redux
Kindest regards!
How great of you to do all that. You’ve got far more sophisticated “best matches” code than I’ve added, it’s quite impressive!
Glad you like it James. Of course, in an ideal world, nobody will ever see it – but it’s there when it’s needed.
Thanks for your feedback while I put it all together. Your input was much appreciated.