2026年5月20日

2026年5月20日

WordPressの404ページをカスタマイズする方法:404.phpの作り方とリダイレクト・ログ

存在しない URL を開いたとき、WordPress はテーマの 404 用テンプレートでページを表示し、HTTP ステータスコード 404 を返します。初期のままでも動きますが、検索フォームや記事への道を置いておくと、読者がそのまま目的のページを探せます。

この記事のコードは、2026年11月時点の WordPress 6.9 と PHP 8.3 で構文を確かめています。

どのテンプレートが使われるか

テーマの種類 404 のテンプレート 編集する場所
クラシックテーマ テーマフォルダーの 404.php(無ければ index.php) ファイルを編集する
ブロックテーマ(Twenty Twenty-Five など) templates/404.html 「外観」→「エディター」→「テンプレート」→「404」

ブロックテーマなら、サイトエディターで 404 テンプレートを開き、「検索」ブロックや「最新の投稿」ブロックを置くだけで、コードを書かずに作り直せます。以下はクラシックテーマの例です。

市販のテーマを使っている場合は、テーマを直接編集すると更新で消えるため、子テーマに 404.php を置きます。子テーマの 404.php は親テーマのものより優先されます。テンプレートの選ばれ方は テンプレート階層の記事 で説明しています。

404.php を作る

テーマ(または子テーマ)のフォルダーに 404.php を作ります。.site-main などのクラス名は、使っているテーマの index.php に合わせてください。

<?php
/**
 * 404 ページのテンプレート
 */
get_header();
?>
<main id="main" class="site-main error-404">

    <header class="page-header">
        <h1 class="page-title">ページが見つかりません</h1>
        <p>お探しのページは移動・削除されたか、URL が間違っている可能性があります。</p>
    </header>

    <section class="error-404-search">
        <h2>サイト内を検索する</h2>
        <?php get_search_form(); ?>
    </section>

    <?php
    $recent = new WP_Query(
        array(
            'posts_per_page'      => 5,
            'post_status'         => 'publish',
            'ignore_sticky_posts' => true,
            'no_found_rows'       => true,
        )
    );
    if ( $recent->have_posts() ) :
        ?>
        <section class="error-404-recent">
            <h2>新着記事</h2>
            <ul>
                <?php
                while ( $recent->have_posts() ) :
                    $recent->the_post();
                    ?>
                    <li>
                        <a href="<?php the_permalink(); ?>"><?php the_title(); ?></a>
                        <time datetime="<?php echo esc_attr( get_the_date( 'c' ) ); ?>"><?php echo esc_html( get_the_date() ); ?></time>
                    </li>
                <?php endwhile; ?>
            </ul>
        </section>
        <?php
        wp_reset_postdata();
    endif;
    ?>

    <section class="error-404-categories">
        <h2>カテゴリー</h2>
        <ul>
            <?php
            wp_list_categories(
                array(
                    'orderby'    => 'count',
                    'order'      => 'DESC',
                    'show_count' => true,
                    'title_li'   => '',
                    'number'     => 10,
                )
            );
            ?>
        </ul>
    </section>

    <p class="error-404-home">
        <a href="<?php echo esc_url( home_url( '/' ) ); ?>">トップページへ戻る</a>
    </p>

</main>
<?php
get_footer();

body には error404 というクラスが付くので、404 ページだけのデザインは body.error404 で指定できます。

ステータスコードが 404 になっているか確かめる

WordPress は、該当するページが無いと判断したときに自分でステータスコード 404 を送ります。404.php の中や functions.php で status_header( 404 ) を呼び直す必要はありません。

確かめるには、存在しない URL に curl でアクセスします(example.com は自分のドメインに置き換えます)。

curl -s -o /dev/null -w "%{http_code}\n" https://example.com/no-such-page-12345/

404 と表示されれば正常です。200 と表示される場合は、プラグインやテーマが 404 をトップページなどへ転送していないか確かめてください。ページが無いのに 200 を返したり、すべての 404 をトップページへリダイレクトしたりすると、検索エンジンは「ソフト 404」として扱います。

検索エンジンはステータスコード 404 のページをインデックスしないので、404 ページに noindex のメタタグを追加する必要もありません。

旧 URL を新しい URL へリダイレクトする

WordPress が自動で行うリダイレクト

次の2つは、何も設定しなくても WordPress が行います。

  • スラッグを変えた投稿: 公開済みの投稿のスラッグを変えると、古いスラッグが記録され、古い URL へのアクセスは新しい URL へ 301 でリダイレクトされます。
  • URL の推測: 404 になった URL の末尾のスラッグと似た投稿があれば、その投稿へリダイレクトします。この推測を止めたい場合は、do_redirect_guess_404_permalink フィルターで false を返します。

自分で対応表を持つ

サイトの構成を変えて URL の規則がまとめて変わった場合などは、対応表でリダイレクトします。functions.php か、テーマに依存しないように wp-content/mu-plugins/ に置くファイルに書きます。

<?php
add_action( 'template_redirect', function () {
    if ( ! is_404() ) {
        return;
    }

    // クエリー文字列を除いたパス(例: /old-page/)
    $path = wp_parse_url( $_SERVER['REQUEST_URI'] ?? '', PHP_URL_PATH );
    if ( ! is_string( $path ) ) {
        return;
    }

    // 古いパス => 新しいパス
    $redirects = array(
        '/old-page/'          => '/new-page/',
        '/old-category/post/' => '/new-category/post/',
    );

    if ( isset( $redirects[ $path ] ) ) {
        wp_safe_redirect( home_url( $redirects[ $path ] ), 301 );
        exit;
    }
} );
  • WordPress をサブディレクトリー(/blog/ など)に置いている場合は、$path に /blog が含まれるので、対応表の左側もそれに合わせます。
  • 恒久的な移動は 301、一時的な移動は 302 を使います。
  • 対応表が数十件を超える場合や、管理画面で編集したい場合は、Redirection プラグイン のほうが管理しやすくなります。Redirection には 404 の記録機能もあります。

404 になった URL を記録する

どの URL が 404 になっているかは、まずサーバーのアクセスログで確かめられます。サーバーのログを見られない場合は、PHP で記録します。

記録先は、Web から見えない場所(公開ディレクトリーの外)にします。wp-content の中に置くと、URL を知っている人が誰でもログを読めてしまいます。wp-config.php で記録先を決めておきます(パスは自分のサーバーに合わせます)。

// wp-config.php の「編集が必要なのはここまでです」の行より上に追加
define( 'MYTHEME_404_LOG', '/home/USER/logs/404.log' );
<?php
add_action( 'template_redirect', function () {
    if ( ! is_404() || ! defined( 'MYTHEME_404_LOG' ) ) {
        return;
    }

    // 改行などの制御文字を取り除き、長すぎる値を切る
    $clean = function ( $value ) {
        $value = preg_replace( '/[\x00-\x1F\x7F]/', '', (string) $value );
        return substr( $value, 0, 500 );
    };

    $line = sprintf(
        "%s\t%s\t%s\t%s\n",
        gmdate( 'Y-m-d H:i:s' ),
        $clean( $_SERVER['REQUEST_URI'] ?? '' ),
        $clean( $_SERVER['HTTP_REFERER'] ?? '-' ),
        $clean( $_SERVER['HTTP_USER_AGENT'] ?? '-' )
    );

    error_log( $line, 3, MYTHEME_404_LOG ); // 3 = 指定したファイルに追記する
}, 20 );
  • 優先度を 20 にして、リダイレクトの処理(優先度 10)のあとに記録しています。リダイレクトされた URL は記録されません。
  • ログのフォルダーは事前に作り、PHP から書き込めるようにしておきます。
  • 攻撃のための自動アクセスでも 404 は大量に出るので、ログは定期的に消すか、サーバーの logrotate などで回してください。

まとめ

  • クラシックテーマは 404.php、ブロックテーマはサイトエディターの 404 テンプレートで作り直します。
  • 404 ページには検索フォームや新着記事、カテゴリーへのリンクを置き、トップページへ戻れるようにします。
  • WordPress は自分で 404 のステータスコードを返すので、status_header( 404 ) や noindex を足す必要はありません。curl で 404 が返るかだけ確かめます。
  • 旧 URL のリダイレクトは template_redirect で wp_safe_redirect() を使うか、件数が多ければ Redirection プラグインを使います。

お気軽にご相談ください

お見積りへ お問い合わせへ
▲