【WordPress】pre_get_postsを使ってハマりました。

近頃、ちまたで噂になっております「pre_get_posts」。
基本私は子テーマで開発することが多いので、出来る限り親のテンプレートは触りたくないです。出来れば、子テーマの中にはstyle.cssとfunctions.phpだけにしたいな〜って思ったり。
※現実には難しいですが・・・

pre_get_postsを使えばfunctions.phpに記載するのでテンプレートファイルへの記載が減るなぁ〜と。

でもって、ちまたで噂の「pre_get_posts」とは簡単に言うとメインクエリーの抽出条件を初回のデータを取得時に変更できるものです。
ちまたで噂では、「query_posts」を使わずに「pre_get_posts」を使おう!って言うのを良く見聞きします。

利点を簡単に書くと、「pre_get_posts」を使うと記事データを取得してブラウザーに表示するまでの間で記事取得の為のデータベースへのアクセエスが1回に抑えれます。
「query_posts」を使ってしまうとデータ取得の為のデータベースへのアクセスが2回になります。

データベースへのアクセスってのはサイトの表示の速度に関わってきますので、2回よりは1回の方がサイトの表示が当然早くなるってことです。

良く「pre_get_posts」と「query_posts」を比較されることが多いのですが、この2つ実は全然違う性質?のものになります。
「query_posts」は皆さん良くご存知だと思いますが、テンプレートファイルに書きます。

記載する位置は「<?php if(have_posts()): while(have_posts()): the_post(); ?> 」と記載されている直前に記載することが多いと思います。こんな感じですね。(記事の表示件数をデフォルトの10件から5件に変更しています。)

[php] <?php query_posts(‘posts_per_page=5’); ?>
<?php if(have_posts()): while(have_posts()): the_post(); ?>
[/php]

上記に書いたように「query_posts」を使うとデフォルトの記事10件を取得した後に5件の記事を再度取得をしに行くことになります。2回データベースにアクセスします。

で、「query_posts」は「query_posts(‘記事取得の条件’)」の様に書きますが、「pre_get_posts」は「pre_get_posts()」というように書きません。またテンプレートファイルにも記載しません。

「query_posts」はWordPress関数なのですが、「pre_get_posts」はWordPress関数ではないからです。関数の場合は関数名の後に丸括弧をつけて上げれば実行できます。
では、「pre_get_posts」は何なのかというと「アクションフック」というものになります。

フックとは、簡単に言うとWordPressの処理の合間合間に横ヤリを入れれる感じです。
例えば、サザエさんの朝食の食卓の準備風景を想像してください。
サザエさんの一家は、波平、舟、さざえ、カツオ、ワカメ、タラ、マスオの7人で住んでます。

サザエがカツオにお茶碗を取ってこいとお願いするとカツオはデフォルトの人数である7人分のお茶碗をとってきます。でもって、カツオがテーブルにお茶碗をマトメて置いた時に、サザエさんが、「イヤイヤ、マスオさんは今日は朝帰りだからお茶碗は6人分でいいんだよ?」と再度いうのが「query_posts」です。

「pre_get_posts」の場合は、カツオが7人分のお茶碗を取りに行ってる時、リビングから台所に向かってる最中に、「今日はマスオさんは朝帰りだからお茶碗は6人分ね!」と伝える感じです。そうするとカツオは1回の移動で6人分のお茶碗を食卓のテーブルに置いておくことが出来ます。

こんな感じで横ヤリを入れれるのが「アクションフック」になります。

前置きが長くなってしまいまたが、何にハマってしまったかと言うとですね。
「pre_get_posts」フックをfunctions.phpに2つ記載をしました。こんな感じです。

以下、検索処理が動いた時に、横ヤリを入れる処理。
※searchform.phpには「<input type=”hidden” name=”post_type” value=”camp” />」と記載し、カスタム投稿タイプがcampのものだけ検索対象にしていた・・・・

[php] function search_camp_info($query) {
if ( is_admin() || ! $query->is_main_query() )
return;

if ( $query->is_search() ) {
………むふふな処理が続く

add_action( ‘pre_get_posts’, ‘search_camp_info’ );
[/php]

以下、campの投稿一覧を表示する時に、横ヤリを入れる処理

[php] function archive_camp_list_rule($query) {
if ( is_admin() || ! $query->is_main_query() )
return;

if ( $query->is_post_type_archive(‘camp’) ) {
………むふふな処理が続く

add_action( ‘pre_get_posts’, ‘archive_camp_list_rule’ );
[/php]

上記の2つの関数をfunctions.phpに定義しました。で、このプログラムだとバグになります。
検索フォームからいくら検索しても検索条件を無視して、全件データを取得してしまうのです・・・
原因は検索処理が動いた時に、「検索処理が動いた時に、横ヤリを入れる処理」と「campの投稿一覧を表示する時に、横ヤリを入れる処理」の2つ処理が動いてしまってました・・・
同じ処理に対して横ヤリが2つ発生してしまったのです・・・
※仕事でも良くありますよね・・・あの人はこういう指示したけど、違う人が後でまた違う指示をしてきた・・・みたいな・・・指示系統が統一されてない。

私としては、「if ( $query->is_post_type_archive(‘camp’) ) {」とif分で制御してるので、大丈夫だと思っていたのですが、たぶんsearchform.phpに「<input type=”hidden” name=”post_type” value=”camp” />」と記載してることにより、「if ( $query->is_post_type_archive(‘camp’) ) {」の処理が通ってしまったのかな?という思っています。

なので、以下のように修正し無事に解決しました。
「if ( $query->is_post_type_archive(‘camp’) ) {」の部分に「&& !is_search()」を追記して、検索処理の時は横ヤリを入れるな!とif分の条件を追加しました。

[php] function archive_camp_list_rule($query) {
if ( is_admin() || ! $query->is_main_query() )
return;

if ( $query->is_post_type_archive(‘camp’) && !is_search() ) {
………むふふな処理が続く

add_action( ‘pre_get_posts’, ‘archive_camp_list_rule’ );
[/php]

ってことで、今日はWordBench神戸の勉強会です。
今日の勉強会の1つのテーマがpre_get_postsのネタです^^ しっかり勉強しようと思います!
でもって実は今日登壇される(まさに今日pre_get_postsの話しをされる) @HissyNC さんに今回の不具合を一緒に調べて頂きました。感謝です>< ありがとうございましたm(__)m

よかったらシェアしてね!
URLをコピーする
URLをコピーしました!

「エンジニアのためのWordPress開発入門」を執筆しました!

WordPressを使った開発案件は依然多く、それに携わるWebエンジニアも多数存在します。ただし、モダンな開発手法に慣れたWebエンジニアがWordPressに初めて触れたとき、その独特のアーキテクチャやシステムの構成に戸惑いを感じることがあるかもしれません。だが、WordPressは、それらを補ったうえにさらに強力なメリットを持ち合わせています。本書は、PHPプログラマがWordPressで開発する際に必要な基礎知識から、現場で役立つ具体的なカスタマイズ手法や開発のポイントについて詳しく解説しています。

この記事を書いた人

NPO法人のHP制作(WordPress)やkintoneを使った業務システムの構築をしています。サイボウズ株式会社公認kintoneエバンジェリスト/CoderDojo西宮と梅田のチャンピオン/認定NPO法人宝塚NPOセンター理事/NPO法人SEIN理事/

コメント

コメント一覧 (4件)

コメントする

目次
閉じる