pre_get_posts でメインクエリを操作して投稿の表示条件を変更する【WordPress】

メインページやアーカイブページのように投稿が一覧表示されるページにおいて、特定のカテゴリーを非表示にしたり表示件数を変えたりしたい場合があります。

これは「メインクエリ」というものを操作することで実現できます。

PR

メインクエリとは?

データベースに保存されている投稿データを取得するための要求

WordPressではメインページ・アーカイブページ・固定ページ・個別投稿ページ等、アクセスしたURLに応じた投稿データをデータベースに要求し、該当する投稿を自動的に表示してくれます。
この「データベースへのURLに応じた投稿データの要求」をメインクエリと言います。

このメインクエリを操作することでメインページから特定のカテゴリーの投稿を除外したり、任意のページのみ表示件数を変更したりすることができます。

メインクエリの変更

メインクエリの操作で可能なこと

メインページやアーカイブページ等の投稿を一覧表示するページで次のような使われ方をすることが多いです。

  • 特定のカテゴリーや特定の投稿、投稿タイプを指定して除外
  • 指定したカテゴリーや投稿タイプのみを表示
  • 管理パネルで設定されている表示件数の変更

これらを活用したテンプレートを追加すると特定のカテゴリーや投稿を異なるデザインで見せることもできます。

メインクエリ操作を行う方法

アクションフックpre_get_postsを使ってメインクエリが実行される前にデータベースへの要求内容を変更します。その後、変更されたメインクエリが実行され、投稿データを取得します。

参考リンク
WordPress Codex – pre_get_posts

問題のある方法は使わないようにする

古い情報ではquery_posts()を使った方法が紹介されていることがありますがこれについては次の通りです。

query_posts() はページ内のメインクエリーを書き換え、新しいクエリーのインスタンスと置き換えるために使う関数としては過度に単純化され、問題が発生しやすい方法です。非効率的で(SQL クエリを再実行します)、一部の状況では適切に実行することもできません(特にページング処理)。モダンな WordPress コードではもっと安定したメソッドを使うべきです。例えばpre_get_posts フックを使った方法などです。ひとことで言うと、query_posts() は決して使うべきではありません。

テンプレートタグ/query posts – WordPress Codex 日本語版

pre_get_postsの基本的な使い方

条件分岐タグ等を利用して指定したページに処理を行います。
2行目で管理画面とメインクエリ以外に影響を与えないようにしています。

function my_pre_get_posts( $query ) {
	if ( is_admin() || ! $query->is_main_query() ) { // 何もしない条件.
		return;
	} elseif ( $query->is_home() ) { // 適用ページの条件.
		// 処理を記述.
		return;
	}
}
add_action( 'pre_get_posts', 'my_pre_get_posts' );

elseifのブロックを追加して異なるページの処理を追加できます。
様々なページのクエリ操作が1か所にまとまるため、メンテナンス性の向上も期待できます。

pre_get_posts の使用例

特定のカテゴリーを除外する

メインページが表示されている場合、投稿一覧からIDが3のカテゴリーを除外します。
IDに負の値を指定すると除外になります。

function my_pre_get_posts( $query ) {
	if ( is_admin() || ! $query->is_main_query() ) {
		return;
	} elseif ( $query->is_home() ) {
		$query->set( 'cat', -3 );
		return;
	}
}
add_action( 'pre_get_posts', 'my_pre_get_posts' );

カテゴリーを除外する場合はID(数値)を指定する必要がありますが、スラッグを指定してIDを導き出す方法もあります。

記事の表示件数を指定する

example-foods というカテゴリーアーカイブが表示されている場合、1ページに10件表示します。
この数値は管理画面での表示件数設定に影響されません。

function my_pre_get_posts( $query ) {
	if ( is_admin() || ! $query->is_main_query() ) {
		return;
	} elseif ( $query->is_category( 'example-foods' ) ) {
		$query->set( 'posts_per_page', 10 );
		return;
	}
}
add_action( 'pre_get_posts', 'my_pre_get_posts' );

該当する投稿を全て表示する

次の例では example-goods というタクソノミーアーカイブが表示されている際、管理パネルによる表示件数の設定に関わらず、example-goods に属する投稿を全て表示します。

前述の表示件数の指定と書式は同じですが、-1を指定すると「全ての投稿」となります。

function my_pre_get_posts( $query ) {
	if ( is_admin() || ! $query->is_main_query() ) {
		return;
	} elseif ( $query->is_tax( 'example-goods' ) ) {
		$query->set( 'posts_per_page', -1 );
		return;
	}
}
add_action( 'pre_get_posts', 'my_pre_get_posts' );

PR

タイトルとURLをコピーしました