If you run your Wordpress blog on the wonderful Genesis Framework (as I do did), then you know that the 404 page is pretty nice out of the box. It gives the user a way back to the homepage, and lists of Pages and Posts and all kinds of ways to get people to find the content they wanted.

Wordpress Genesis Theme 404 Page

It lacks customization options though. In most of the sites I work on, there are a few pages that don’t get linked from the menus because they’re specialty pages. It could be a “thank you for purchasing” page, or a landing page for traffic from a specific site or campaign.

I’ve come up with a quick modification that lets you hide pages from the 404 listing by setting a field in the page’s metadata.

Changing the 404

Making any changes to the 404 page is going to require editing the PHP. But most Genesis child themes don’t include a customized 404; they just use the one provided by Genesis. We do not want to modify the file directly in Genesis. Instead we’ll copy the 404.php file into the directory for the child theme.

Copy: wp-content/themes/genesis/404.php
To: wp-content/themes/child_theme/404.php

This will probably have to be done with your FTP program or through your web host’s file manager. Now, you can edit the 404.php file in the child theme directory. For this, you can use any editing method you like, including the one in the Wordpress back end:
Appearance > Editor.

The wp_list_pages() Function

Looking at the code in 404.php, find where the pages are listed:

<h4><?php _e( 'Pages:', 'genesis' ); ?></h4>
<ul>
	<?php wp_list_pages( 'title_li=' ); ?>
</ul>
 

In the documentation for the wp_list_pages() function, you can see that there’s an exclude parameter. You can give it a list of page IDs and it will exclude those from the listing.

I wanted a method that didn’t require me to modify the 404 file for every site I worked on, and every single page I wanted hidden!

Metadata Custom Fields

Each post and page in Wordpress has the ability to add custom fields to its metadata, in the form of key/value pairs. This is perfect for what I wanted: a way to hide individual pages from the 404, and do it from the standard Wordpress back end.

To do that, I made the following modification to code you see above:

<h4><?php _e( 'Pages:', 'genesis' ); ?></h4>
<ul>
	<?php
		$pages = get_pages();
		$exclude = array();
		foreach ( $pages as $page ) {
			$meta = get_post_custom_values( '404' , $page->ID );
			if ( $meta ) {
				foreach ( $meta as $key => $value ) {
					if ( $value == 'hide' ) {
						$exclude[] = $page->ID;
						break;
					}
				}
			}
		}
		wp_list_pages( 'title_li=&exclude=' . implode( ',' , $exclude ) );
	?>
</ul>
 

The outline of what I’m doing here goes like this:

  1. Get an array of all the pages using get_pages().

  2. For each page, get the value of any custom fields with the name 404.

  3. Look for a value of hide and if found, add the page ID to an array.

  4. Finally, call wp_list_pages() with a comma separated list of pages (generated from our exclude array) to exclude.

With these changes in place, the page is generic enough to be included in any Genesis child theme.

Excluding a Page

Now you need only set your metadata custom field with the name 404 and the value hide:

Wordpress Custom Fields Metadata 404 Hide

Any value of other than hide will be ignored, and the page will be shown in the 404 listing.

Other Considerations

If you need to hide posts, you can apply the same logic to the section that shows posts, though I’ve never needed that functionality myself.

Since I’m getting a list of all the pages with the call to get_pages(), I don’t need to call wp_list_pages() again; I could generate the list items and the links myself. But I didn’t want to have to worry about generating the right tags with the right classes and all that. I feel like the 404 page should be such a small part of your site’s traffic that an extra database call in the 404 won’t be such a big deal.

I’ve also included a completed 404.php file which you can download here and use without changes. Just upload it to your child theme directory and you’re good to go (as long as there isn’t already one there).

PHP File Icon 404.php