間違ったやり方: query_posts()
を使う
要は検索条件にカテゴリ除外の条件を追加すればいいわけなので、じゃあということで検索条件に特定のカテゴリを表示しない設定をしてみました。ループの前にこんな感じ。
<?php query_posts('cat=-582'); ?>
<?php while ( have_posts() ) : the_post(); ?>
一見上手く動いたように見えたのですが、これには致命的な問題があってページネーションが動かなくなります。要は「条件を追加したい」と思って書いたけれど、これだと「条件を置き換える」と言うことになるんですね。おかげで条件が「特定のカテゴリを除く1ページ目」に置き換わってしまい、ページを移動しても移動してもずっと1ページ目が表示されるという状況に。
正しいやり方: pre_get_posts
フックを使う
ドキュメントにこうあります。query_posts() はページ内のメインクエリーを書き換え、新しいクエリーのインスタンスと置き換えるために使う関数としては過度に単純化され、問題が発生しやすい方法です。非効率的で(SQL クエリを再実行します)、一部の状況では適切に実行することもできません(特にページング処理)。モダンな WordPress コードではもっと安定したメソッドを使うべきです。例えばpre_get_posts フックを使った方法などです。ひとことで言うと、query_posts() は決して使うべきではありません。
テンプレートタグ/query posts – WordPress Codex 日本語版
(中略)
paged’ クエリー引数を適切に指定していないと、ページ送りが正しく動作しない可能性があります。
僕がやらかしたことがそのまま書いてありますね。「決して使うべきではありません。」はい。
というわけで正しい実装の方法は、functions.php で
pre_get_posts
フックを使う方法です。ドキュメントの例に従って以下を追加します。function not_show_bookmarks_posts( $query ) {
// トップページの場合のみ
if ( $query->is_home() && $query->is_main_query() ) {
$query->set('category__not_in', array(582));
}
}
add_action( 'pre_get_posts', 'not_show_bookmarks_posts' );
これで当初の目的が果たせました。知らなかったとは言え(多分検索して辿り着いたどこかのサイトから拾ってきたんでしょう)、安易に強い関数を使ってはいけませんね。
その他参考になる記事
調べてみると、query_posts()
でもパラメータをきちんと設定すれば正しく動作することも出来るようです。トップページから一部の記事を除外する | Webエンジニアブログ
確かにこういう処理が必要なこともあるんでしょうし、どちらが直感的か?というと意見が分かれるかも知れませんが、ドキュメントで推奨されていないことは変わらないので、素直に
pre_get_posts
を使っておくのがいいかも知れません。