2026年7月16日

2026年7月16日

WordPressの404ページをカスタマイズする方法

はじめに

WordPressで正しいURLにアクセスしているのに404エラーが表示される・テーマに404.phpを作成したのに反映されない・パーマリンクを変更したら既存の記事がすべて404になった・カスタム投稿タイプのアーカイブページが404になる・リダイレクト設定が意図通りに動かないといった問題は、WordPressのリライトルールとテンプレート階層を正しく理解することで解決できます。

症状・原因

  • パーマリンク設定変更後にリライトルールがフラッシュされていない
  • カスタム投稿タイプのhas_archiverewrite設定が不正確
  • AllowOverride Allが設定されておらず.htaccessのルールが無視されている
  • テーマに404.phpが存在しないためデフォルトの404処理が使われている

解決手順

ステップ1:404の原因を診断する

# リライトルールの状態を確認
wp rewrite list --format=table

# パーマリンク設定を確認
wp option get permalink_structure

# リライトルールをフラッシュ(最初に試すべき操作)
wp rewrite flush --hard

# カスタム投稿タイプのリライト設定を確認
wp eval "
\$types = get_post_types([], 'objects');
foreach (\$types as \$type) {
    if (!\$type->_builtin) {
        echo \$type->name . ': has_archive=' . var_export(\$type->has_archive, true)
            . ', rewrite=' . var_export(\$type->rewrite, true) . PHP_EOL;
    }
}
"

# .htaccess の内容確認
wp eval "echo ABSPATH . '.htaccess';" | xargs cat

ステップ2:カスタム404ページを作成する

// テーマに 404.php を作成(テーマフォルダ直下に配置)
// 404.php の基本構造

get_header(); ?>

<main class="site-main">
    <section class="error-404 not-found">
        <header class="page-header">
            <h1 class="page-title">ページが見つかりません</h1>
        </header>
        <div class="page-content">
            <p>お探しのページは移動または削除された可能性があります。</p>
            <?php get_search_form(); ?>

            <div class="widget">
                <h2>最近の投稿</h2>
                <?php
                $recent = new WP_Query([
                    'posts_per_page' => 5,
                    'no_found_rows'  => true,
                ]);
                if ($recent->have_posts()): ?>
                <ul>
                    <?php while ($recent->have_posts()): $recent->the_post(); ?>
                    <li><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></li>
                    <?php endwhile; wp_reset_postdata(); ?>
                </ul>
                <?php endif; ?>
            </div>
        </div>
    </section>
</main>

<?php get_footer();

ステップ3:パーマリンク変更後の404を修正する

// functions.php: カスタム投稿タイプ登録時のリライト設定
add_action('init', function(): void {
    register_post_type('product', [
        'public'      => true,
        'has_archive' => true,           // アーカイブページを有効化
        'rewrite'     => [
            'slug'       => 'products',  // URLスラッグ
            'with_front' => false,       // フロントページのプレフィックスなし
            'feeds'      => true,        // フィードURLを有効化
            'pages'      => true,        // ページネーションを有効化
        ],
        'supports'    => ['title', 'editor', 'thumbnail'],
    ]);
});

// プラグイン有効化時にリライトルールをフラッシュ
register_activation_hook(__FILE__, function(): void {
    // 投稿タイプ登録後にフラッシュ
    flush_rewrite_rules();
});

// プラグイン無効化時にもフラッシュ
register_deactivation_hook(__FILE__, 'flush_rewrite_rules');

ステップ4:古いURLから新しいURLへリダイレクトする

// 旧URLから新URLへ301リダイレクト
add_action('template_redirect', function(): void {
    if (!is_404()) {
        return;
    }

    $request_uri = $_SERVER['REQUEST_URI'] ?? '';

    // 旧スラッグから新スラッグへのマッピング
    $redirects = [
        '/old-category/old-post/'  => '/new-category/new-post/',
        '/products/'               => '/shop/',
    ];

    foreach ($redirects as $old => $new) {
        if (str_starts_with($request_uri, $old)) {
            wp_redirect(home_url($new), 301);
            exit;
        }
    }
});

// redirect_canonical を無効化(カスタム処理と競合する場合)
// add_filter('redirect_canonical', '__return_false');

// 404ページの HTTP ステータスコードを確認・強制
add_filter('status_header', function(string $status_header, int $code): string {
    if (is_404() && $code !== 404) {
        return 'HTTP/1.1 404 Not Found';
    }
    return $status_header;
}, 10, 2);

ステップ5:404エラーをログに記録して分析する

// 404エラーをログに記録
add_action('template_redirect', function(): void {
    if (!is_404()) {
        return;
    }

    $uri      = $_SERVER['REQUEST_URI'] ?? '';
    $referer  = $_SERVER['HTTP_REFERER'] ?? 'direct';
    $user_agent = $_SERVER['HTTP_USER_AGENT'] ?? '';

    // ボットは除外してログを軽量化
    $bot_patterns = ['Googlebot', 'bingbot', 'Slurp', 'DuckDuckBot'];
    foreach ($bot_patterns as $bot) {
        if (str_contains($user_agent, $bot)) {
            return;
        }
    }

    error_log(sprintf(
        '[404] %s | Referer: %s | UA: %s',
        $uri,
        $referer,
        substr($user_agent, 0, 100)
    ));

    // カスタムデータベースに404を記録する場合
    // update_option('404_log', array_merge(
    //     get_option('404_log', []),
    //     [['uri' => $uri, 'time' => time()]]
    // ));
}, 99);

注意事項

  • flush_rewrite_rules()は毎リクエストで呼び出すと重大なパフォーマンス問題が発生します。必ずregister_activation_hook内か、管理画面のパーマリンク設定保存時(admin_initフック)のみで実行してください
  • redirect_canonicalを完全に無効化するとSEOに悪影響を与える可能性があります

まとめ

WordPress 404問題の解決は①wp rewrite listでルール確認・wp rewrite flush --hardで最初にフラッシュ・カスタム投稿タイプのhas_archive/rewrite設定を確認、②テーマに404.phpを作成・検索フォームと最近の投稿を表示・ユーザーを迷子にしない導線設計、③カスタム投稿タイプにwith_front=falsehas_archive=trueを設定・register_activation_hookでフラッシュ・deactivation_hookでもフラッシュ、④template_redirectフックで旧URLから新URLへ301リダイレクト・スラッグ変更時のマッピングを管理・status_headerフィルターで404ステータスを強制、⑤404エラーをログに記録して頻出URLを分析・ボットを除外してログを軽量化・リダイレクト対象を特定する手順で解決します。

お気軽にご相談ください

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