投稿一覧を出したいだけなのに、2ページ目で404になる。
「あれ、ちゃんとループ書いてるのに…?」
その原因、もしかしてquery_posts()
を使っていませんか?
今回は、実際に筆者がハマった「ページネーションが効かないWordPress地獄」からの脱出劇を、経験ベースでわかりやすく解説します。
🔥 事の発端:「固定ページテンプレートで一覧を出したいだけだった」
あるとき、こんなコードを書きました。
/*
Template Name: お知らせ
*/
<?php
$paged = get_query_var('paged') ?: 1;
query_posts(array(
'post_type' => 'post',
'posts_per_page' => 5,
'paged' => $paged
));
?>
WordPressの固定ページで「お知らせ一覧」を表示したくて、何も考えずに query_posts()
を使ったのです。
😱 表示されるけど…2ページ目に行くと 404 Not Found
URLは /news/page/2/
。
存在するはずなのに、なぜか404ページが出る。
- トップページでは投稿が表示される
the_posts_pagination()
も書いてある- でも2ページ目が出ない。どこにも書いてない不具合。
🧠 原因:query_posts()
がメインクエリを壊していた
WordPressには、URLに応じて自動的に生成される「メインクエリ」があります。
query_posts()
はこれを強制的に上書きしてしまう関数です。
問題 | 内容 |
---|---|
query_posts() を使うと | WordPress が作った元のクエリが破棄される |
結果 | ページ数・カテゴリ・投稿タイプなどの判定ができなくなる |
最終的に | ページネーションが壊れて404になる |
⚠ 注意すべき点
🔄 query_posts() 非推奨の明確な理由とバージョン情報
query_posts()
が非推奨とされているのは、WordPress 3.x 以降(2011年頃)から既知のベストプラクティスです。現在(WordPress 6.x時点)でも公式では「使用しないことを強く推奨」と明記されています。
理由としては:
- メインクエリを書き換えてしまう → 条件分岐(
is_category()
など)が壊れる - グローバル変数を直接変更 → テンプレートタグやページネーションで不具合
- 実装ミスの温床 → ページネーション失敗・404になる・表示件数が効かない等
将来的に互換性がなくなる可能性もあるため、新規開発では絶対に使わない方向が安心です。
➡ 代替案:WP_Query
や pre_get_posts
を使用
🧭 get_query_var('paged')
の補足
ページネーション用の $paged
変数を取得するために get_query_var('paged')
を使いますが、これはアクセスしているページの種類によって動作が異なるため注意が必要です。
📌 ページ種類ごとの違い
ページ種別 | 必要な変数 | 解説 |
---|---|---|
投稿一覧(ブログTOPなど) | paged | 通常通り機能します |
カテゴリー・タグ一覧 | paged | 通常通り機能します |
固定ページ + カスタムテンプレート | page | なぜか paged ではなく page に格納されることがある |
✅ 対策(安全な取得方法)
$paged = get_query_var('paged') ? absint(get_query_var('paged')) : absint(get_query_var('page'));
$paged = $paged ? $paged : 1;
これで どのページタイプでも正しく現在のページ番号を取得できるようになります。
🔧 パーマリンク設定にも注意
カスタム投稿タイプや独自テンプレートでページネーションを行う場合は、パーマリンク設定を「保存し直す」必要があることがあります。
設定場所:
- WordPress管理画面 > [設定] > [パーマリンク] > 「変更を保存」
変更しなくてもOKですが、「保存ボタンを押す」ことで内部のリライトルールが再生成され、404エラーの原因を解消できることがあります。
😰 さらにミスを重ねた:category.php
や archive.php
が使われない?
その後、category-news.php
を作成しても表示されないという問題にも直面しました。
原因は以下:
- 固定ページテンプレートに
Template Name: お知らせ
と書いたことで、WordPressはそのテンプレートを優先してしまっていた。 category.php
やarchive.php
が無視される。- URL構造とテンプレート階層がバラバラになり、思った通りに表示されない。
✅ 解決方法まとめ(実体験)
誤り | 正しい方法 |
---|---|
query_posts() でクエリを再定義 | WP_Query で新しく取得する |
Template Name を使って一覧を表示 | category.php や archive.php を利用し、WordPressに任せる |
固定ページ+クエリ再定義でページ送り | 投稿タイプごとに pre_get_posts を使って件数を変更する |
パーマリンク設定を初期のまま | 「パーマリンク設定」で一度保存して再構築 |
💡 よくある思い込み vs 正しい理解
思い込み | 実はこうだった! |
---|---|
query_posts() は便利だから使ってOK | 使うとメインクエリを壊す。使ってはいけない |
固定ページに Template Name: が必要 | 一覧ページには不要。WordPressのテンプレート階層に任せる |
ページネーションは the_posts_pagination() を入れればOK | その前に正しいクエリが必要。WP_Query + max_num_pages を忘れずに |
表示されてるからOKだと思った | 2ページ目で気づく地獄のトラップ |
✅ 正しいコード例(WP_Query
+ ページネーション)
<?php
$paged = get_query_var('paged') ?: 1;
$args = array(
'post_type' => 'blog', // カスタム投稿タイプ名
'posts_per_page' => 5,
'paged' => $paged
);
$blog_query = new WP_Query($args);
?>
<ul class="blog-list">
<?php if ($blog_query->have_posts()) : while ($blog_query->have_posts()) : $blog_query->the_post(); ?>
<li><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></li>
<?php endwhile; endif; ?>
</ul>
<?php
the_posts_pagination([
'total' => $blog_query->max_num_pages
]);
wp_reset_postdata();
?>
💡 カスタム投稿で一覧表示+ページ送りするには
archive-{post_type}.php
を作成する(例:archive-blog.php
)- テンプレート内で
WP_Query
を使わず、WordPressに任せる - 件数変更したいなら
functions.php
に以下を追記:
function blog_posts_per_page($query) {
if (is_admin() || !$query->is_main_query()) return;
if (is_post_type_archive('blog')) {
$query->set('posts_per_page', 5);
}
}
add_action('pre_get_posts', 'blog_posts_per_page');
☠️ query_posts()
が絶対にダメな理由まとめ
理由 | 詳細 |
---|---|
メインクエリを壊す | ページネーション、URLマッチング、条件分岐が狂う |
条件分岐が効かない | is_category() や is_archive() が false になる |
パフォーマンスも悪化 | 無駄にクエリを再生成して非効率 |
WordPress公式も非推奨 | 公式ドキュメントにも記載あり |
✅ まとめ:これからはこう使おう!
やりたいこと | 方法 |
---|---|
一覧を表示したい | category.php や archive.php を使う |
固定ページに表示したい | WP_Query で別インスタンスとして取得 |
表示件数を変えたい | pre_get_posts を functions.php に記述 |
ページネーションを正しく表示 | the_posts_pagination() + max_num_pages |
🎯 最後に:この経験から学んだこと
query_posts()
を安易に使うと、後で地獄を見る。- テンプレート階層を理解すれば WordPress はもっと快適になる。
- ページネーションが壊れたら、まず疑うのは「クエリの書き方」。
「動く」コードは書けても、「壊れない」コードを書くには理解が必要。
自分のミスを糧に、誰かのトラブルも防げたら嬉しいです。