Candy, A Journal by a James

Improve your WordPress: the 404 error page

First in a series of art­icles about tinker­ing with improv­ing your word­press install­a­tion, today we tackle cus­tom 404 error pages; the page every­one dreads get­ting when they’ve fol­lowed an out­dated link.

Four-Oh-Fours are hot again! Just recently came a across the art­icle A Better 404. I remem­ber read­ing the A List Apart art­icle “A Perfect 404″ ages ago, but had never done any­thing 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 fol­lowed a out­dated link which means we can use the URI to cre­ate a more help­ful 404 page. To cre­ate a 404 page for your WordPress theme just cre­ate a 404.php file in the dir­ect­ory of your theme (/wp-content/themes/default/ is the default).

The default word­press 404 page code looks some­thing like this:

<?php get_header(); ?>

<h1>Nothing Found (Error 404)</h1>

<?php get_sidebar(); ?>

<?php get_footer(); ?>

Which I sup­pose is func­tional enough, but doesn’t actu­ally help the user much, depend­ing on the con­tent of your side­bar. The first thing to do is to tell pro­grammes vis­it­ing  (browsers and more import­antly search engine spiders!) that the page is a 404 error page.

You do that by adding the fol­low­ing 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” mes­sage tells spiders exactly what they need to know.

Next up, adding use­ful things for human users! There are three main things you can do to be help­ful. Telling the user exactly what’s wrong, giv­ing them a list of related art­icles and list­ing your recent art­icles. Related art­icles requires some URI magic which I haven’t figured out yet, but Jonathan Hollin has, so stay tuned for an art­icle from him which I’ll link to when the time comes.

Telling the user exactly what’s wrong goes a little some­thing like this:

<block­quote>

<?php // When the vis­itor 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 incor­rect or <em><?php echo $_SERVER[’REQUEST_URI’];?></em> has been moved, renamed or deleted.</p>

<?php } // When the vis­itor isn’t linked through (most likely a bookmark)

else { 

echo “<p><em>” . $_SERVER[’REQUEST_URI’] . “</em>”;

?>

has been moved, renamed or deleted.</p>

<?php } ?>

</blockquote>

As the com­ments in the code make clear, there are two situ­ations to tailor for: when people come in from another site and when they don’t. A nice addi­tion is “echo chunk_split($_SERVER[’HTTP_REFERER’], 25)” which echo’s (out­puts) the HTTP_REFERER (the site where the user was linked from) in little blocks of 25 char­ac­ters. This way long URLs still wrap nicely. I chose 25 char­ac­ters 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 $post­slist = get_posts(‘numberposts=6′);

foreach ($post­slist as $post) :

setup_postdata($post); ?>

<li><a href=”<?php the_permalink(); ?>”><?php the_title(); ?></a></li>

<?php end­foreach; ?>

</ol>

This code simply out­puts a linked title of the 6 most recent journal entries in a numbered list. Simple!

So, to recap, you’ll end up with some­thing 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>

 

<block­quote>

<? 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 incor­rect 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 } ?>

</blockquote>

 

<p>Don’t worry, just try again!</p>

 

<h1>Recent Posts</h1>

<ol>

<?php $post­slist = get_posts(‘numberposts=6′);

foreach ($post­slist as $post) :

setup_postdata($post); ?>

<li><a href=”<?php the_permalink(); ?>”><?php the_title(); ?></a></li>

<?php end­foreach; ?>

</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 con­tent” to my 404 pages, fol­lowup post will come later.

5 Responses to “Improve your WordPress: the 404 error page”

  1. Joen says:

    Very nice stuff this, definately some­thing I’ll look in to.

    The 404 header, though, I hon­estly thought WordPress sent that auto­mat­ic­ally. It cer­tainly should.

    • Not auto­mat­ic­ally send­ing the cor­rect http-header was a sur­prise to me too. The code’s so simple, that I don’t under­stand why it’s included by default.

      However, (prob­ably) due to some Apache htac­cess magic, the page sends out a 404 any­way, even without the code.

  2. James I have just pub­lished a new art­icle describ­ing the addi­tional func­tion­al­ity I added and offer­ing a break­down of the code. There’s also a full source-code down­load available.

    See: A Better 404 — Redux

    Kindest regards!

  3. 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 feed­back while I put it all together. Your input was much appreciated.