WordPress でステータスコード 404(Not Found)を返却するエラーページを作る

WordPress でステータスコード 404(Not Found)を返却するエラーページを作る

Posted at May 21,2007 2:25 AM
Tag:[404, HTTP, WordPress]

WordPress のサイトで、「指定された URL が存在しない場合、テーマ(テンプレート)で用意した 404 エラーページ(404.php)の内容を返却します」というようなことが関連書籍等に記されていますが、サーバの設定によっては 404 エラーページを表示したにもかかわらず、HTTP レスポンスにステータスコード 200(OK)を付与してしまうケースがあります。

また、「指定された URL が存在しない場合」についてもバリエーションがあり、例えば、WordPress が解釈できるクエリー文字列が付与され、かつ存在しない URL であれば、適正なサーバの設定を行っても 404 エラーページが表示されない可能性が高いです。

このエントリーでは、指定された URL が存在しない場合、可能な限り 404 エラーページを返却させると同時に、スクリーンショットのように HTTP レスポンスのステータスコードに 404( Not Found)を返却する方法を紹介します。

ステータスコード 404(Not Found)返却

この内容は 2.1.x から、先日リリースされた WordPress 2.2 まで確認しています。また内容について認識不足・認識誤り等ありましたらご指摘ください。適宜修正したいと思います。

1.ステータスコード 200 と 404 について

基礎知識として、HTTP レスポンスのステータスコード 200(OK)は「リクエストは成功」を意味しますので、404 エラーページを返却する場合は「リクエストURIと一致するリソースが見つけられなかった」ことを意味する 404(Not Found)を付与する必要があります。

ちなみに 404 は 4xx レスポンス(クライアントエラー)に含まれます。

2.ステータスコード 404 を返却する・対処その1(.htaccess の作成)

下記の内容を .htaccess の先頭に記述します。

ErrorDocument 404 /index.php?error=404

ドキュメントルート以外の場所に WordPress をインストールしている場合は、 "/" の前にドキュメントルートからのディレクトリを記述します。

下記のようにした場合は、エラーページの URL によって若干動作が異なります。

ErrorDocument 404 /404.php

WordPress標準ガイドブック―導入&基本操作からフルチューンまで」では、クエリーによる設定(前者)が推奨されています。

WordPress標準ガイドブック―導入&基本操作からフルチューンまでWordPress標準ガイドブック―導入&基本操作からフルチューンまで
マクラケン 直子 WordPress Japan

毎日コミュニケーションズ 2006-09
売り上げランキング : 14469

Amazonで詳しく見る
by G-Tools

3.ステータスコード 404 を返却する・対処その2(テーマ修正)

.htaccess をアップロードしてエラーの動作を確認したところ、存在しない URL を指定すると 404.php がハンドリングされるようになりました。しかしながら、例えばデフォルト設定の個別ページやカテゴリーページの URL の末尾の数字に、存在しない ID を指定した場合は、そのテンプレートに記述したエラー処理の内容が表示されます。

例えば、個別記事の URL(デフォルト)は、末尾に "?p=記事番号" というクエリーが付与されますが、

http://user-domain/?p=10000

と、記事が存在しない URL を指定した場合は、404.php が起動されるのではなく、正しいクエリー文字が URL に含まれていると判断してシングルポスト(single.php)がハンドリングされます。

次に、起動されたシングルポストのテンプレートが下記の構造になっていると仮定します。

<?php get_header(); ?>
 
<?php if (have_posts()) :  while (have_posts()) : the_post(); ?>
             :
 (記事がある場合はここに記述されたテンプレートが展開)
             :
<?php endwhile; else: ?>
             :
 (記事がない場合はここに記述されたテンプレートが展開)
             :
<?php endif; ?>
 
<?php get_footer(); ?>

つまり、記事が存在しない ID が付与された正しいクエリーの URL で、上記の構造になっているテンプレートでは、「記事がない場合」の部分(赤色)が実際に処理されることになります。

ここには2つの問題があります。

  • テンプレートを正常に処理しているので、ステータスコード 200(OK)を返却する
  • 404 エラーであるにもかかわらず 404 エラー用テンプレートがハンドリングされない

この事象は、アーカイブ(archive.php)やページ(page.php)も同様です。アーカイブとして認識されるクエリーが URL に付与されると、アーカイブテンプレート内のエラー処理が起動します。

ステータスコード 404 を返却したいのはもちろんですが、できればエラーページについてはエラーとなる URL に関わらず、一意のページ、つまり 404.php に処理を委ねた方が良い場合もあるのではないでしょうか(例えば 404 エラーページをカスタマイズしたい場合)。

この認識が間違っていないという前提で、下記にそれぞれの対処案を示します。

3.1 ステータスコード 404 を付与する

テーマファイルに含まれる、

  • シングルポスト(single.php
  • アーカイブ(archive.php
  • ページ(page.php

の先頭に、下記の青色の内容を追加します。

<?php if (!have_posts()) { 
header("HTTP/1.1 404 Not Found"); } ?>
<?php get_header(); ?>
     :

この設定は、処理すべき記事が存在しない場合、ステータスコード 404 を付与し、その後テンプレート後方に出現するエラー処理(前出リストの赤色部分)が実施されます。

3.2 404 エラー用テンプレートをハンドリングする

ここでは2つの方法を提示していますが、基本的に3.2.1を実施してください。

3.2.1 テンプレートを修正する(推奨)

3.1 項の修正内容と一部重複しますが、テーマファイルに含まれる

  • シングルポスト(single.php
  • アーカイブ(archive.php
  • ページ(page.php

の先頭に、下記の青色の内容を追加します。

<?php if (!have_posts()) { 
header("HTTP/1.1 404 Not Found");
include (TEMPLATEPATH . '/404.php');
return; } ?>
<?php get_header(); ?>
     :

この行を加えることで、処理すべき記事が存在しない場合は、テンプレートの通常処理を実行する前にレスポンスヘッダに 404 を付与し、404.php に処理を移します。

3.2.2 ソースコードを修正する(非推奨)

今回のカスタマイズは、WordPress のソースコードを解析していて、先にこの方法に辿りつき、それからテンプレートに記述する案が思いつきました。
この方法を用いればテンプレートの修正をせずに、404.php の内容を表示することができます。が、これは覚え書きレベルですので、実際には3.2.1項の修正を推奨します。

/wp-includes/classes.php を任意のエディタで開き、下記の青色部分を追加します。

function handle_404() {
    global $wp_query;
    // Issue a 404 if a permalink request doesn't match any posts.  Don't
    // issue a 404 if one was already issued, if the request was a search,
    // or if the request was a regular query string request rather than a
    // permalink request.
    if ( (0 == count($wp_query->posts)) && !is_404() && !is_search() && ( $this->did_permalink || (!empty($_SERVER['QUERY_STRING']) && (false === strpos($_SERVER['REQUEST_URI'], '?'))) ) ) {
        $wp_query->set_404();
        status_header( 404 );
        nocache_headers();
    }    elseif( !have_posts() ) {
        $wp_query->set_404();
        status_header( 404 );
    }    elseif( is_404() != true ) {
        status_header( 200 );
    }
}

4.まとめ

WordPress でエラーとなる URL でリクエストされた場合に、正しいレスポンスを返却するためには、.htaccess の設定と、テンプレートの修正が必要です。どの部分の修正がどこに適用されるかについては下記の表を参考にしてください。

 存在しない URLあり得るクエリーの URL
.htaccess
なし
テンプレート修正
なし
サーバ依存200 OK
テンプレート修正
あり
サーバ依存404 Not Found
.htaccess
あり
テンプレート修正
なし
404 Not Found200 OK
テンプレート修正
あり
404 Not Found404 Not Found

「サーバ依存」の部分は、自宅サーバとレンタルサーバで結果が異なったため、このような表記にしています。

5.その他

エラーページの表示に、常に 404.php を利用するのであれば、各テンプレートの構造は(おおざっぱですが)、

<?php if (!have_posts()) { 
header("HTTP/1.1 404 Not Found");
include (TEMPLATEPATH . '/404.php');
return; } ?>
<?php get_header(); ?>
 
<?php if (have_posts()) :  while (have_posts()) : the_post(); ?>
             :
 (記事がある場合はここに記述されたテンプレートが展開)
             :
<?php endwhile; endif; ?>
<?php get_footer(); ?>

と、エラー処理を省略したフォーマットで統一できそうな気がします。

また上記までの修正で、ステータスコード 404 が付与されるようになりますが、レスポンスヘッダ全体を眺めた場合、X-PingBack ヘッダが付与されることついては懸念が残ってます。

関連記事
zenback
人気エントリー
トラックバックURL


トラックバック

美しき404エラーページ集  from JJLW
404エラー、NotFoundは、HTTPステータスコードのひとつです。 さて、Notfound画面にもデザインあり!ということで、お洒落... [続きを読む]

Tracked on August 20, 2007 11:36 PM

トリアエズで from prag -pranktone life archives-
急ぎ、404エラーページ作成。 いや、まったく忘れてた。 ってか、個別記事の URLって、末尾に "?p=記事番号" というクエリーがつくけど、 あ... [続きを読む]

Tracked on June 5, 2008 1:31 AM

WordPressの404エラーをカスタマイズしてみたよ from Hinemosu
毎日10件ほど発生しているリクエストエラー(ページが見つかりません)を救うため、404エラーページをカスタマイズして... [続きを読む]

Tracked on August 29, 2008 11:20 AM
コメントする
greeting

*必須

*必須(非表示)


ご質問のコメントの回答については、内容あるいは多忙の場合、1週間以上かかる場合があります。また、すべてのご質問にはお答えできない可能性があります。予めご了承ください。

太字イタリックアンダーラインハイパーリンク引用
[サインインしない場合はここにCAPTCHAを表示します]

コメント投稿後にScript Errorや500エラーが表示された場合は、すぐに再送信せず、ブラウザの「戻る」ボタンで一旦エントリーのページに戻り(プレビュー画面で投稿した場合は、投稿内容をマウスコピーしてからエントリーのページに戻り)、ブラウザをリロードして投稿コメントが反映されていることを確認してください。

コメント欄に(X)HTMLタグやMTタグを記述される場合、「<」は「&lt;」、「>」は「&gt;」と入力してください。例えば「<$MTBlogURL$>」は「&lt;$MTBlogURL$&gt;」となります(全て半角文字)