AD5 WordPress Lab

WP_Queryクラスとpre_get_postsフィルター

WP_Queryクラスとpre_get_postsフィルター

WordPress内部では、あらゆる投稿の検索に、WP_Queryオブジェクトを使用しています。

WordPressによる投稿の検索をカスタマイズする、最も最良の方法は、pre_get_postsフィルターを使用することです。

この手法を使いこなすためには、WP_Queryクラスの仕様を理解することが重要です。

WP_Queryクラス

WP_Queryクラスは、検索するための各種パラメータ(投稿タイプ、投稿名、カテゴリやターム、投稿者、取得件数など、あらゆる条件)と、その検索結果をプロパティとして持っています。
(その他多くのプロパティがあります。)

URLへのアクセス時には、URLを解析してWP_Queryオブジェクトが自動的に生成され、検索条件パラメータ($query_varsプロパティ)がセットされます。

そして、query() メソッドによって、投稿データが取得され、検索結果(postsプロパティ)にセットされます。

この時自動的に作成される WP_Query オブジェクトは、グローバル変数 $wp_query に格納されています。

テンプレートファイル内で、ループ処理内に必ず記述される、the_post() メソッドが実行されると、postsプロパティに格納された検索結果の配列がポップされ、グローバル変数である $post に格納されます(厳密にはpopではなくindexを進めてコピー)。

テンプレートタグである the_title() や the_content() は、このグローバル変数 $post から値を取得します。

テンプレートによるWP_Queryオブジェクトの操作

pre_get_posts の挙動を説明する前に、WordPressコーディングで、よくpre_get_postsフィルターと対比される、各手法について解説しておきます。

今や事実上の非推奨となったquery_posts() 関数は、グローバル変数 $wp_query を直接書き換えます。
(query_varsプロパティを書き換えてquery() メソッドを実行。)

これにより、自動生成されたWP_Queryオブジェクトの内容が失われるため、それに依存する処理が不具合を起こしたりするなどの難点があります。

それに変わって普及したのが、テンプレートタグ内で、新たにWP_Queryオブジェクトを作成する方法。

WP_Queryクラスのコンストラクタは、引数でquery_varsプロパティに任意の値をセットできるため、query_posts() と同様のことが実現できます。

デフォルトのWP_Queryオブジェクト(グローバル変数 $wp_query)は上書きされません。
グローバル変数 $post は上書きされていますが、再利用が必要な際は、wp_reset_postdata() 関数をコールすれば、元々の $post を復元できます。

しかし、query_posts() 同様、テンプレートに記述する以上、デフォルトの検索が既に終わっているため、無駄に2回DBにクエリを投げることになる、テンプレートの決定などの後続処理が既に終わっているなどの、根本的な問題は解消されません。

例えば、20投稿ある投稿タイプに対して、デフォルトでは1ページ10件のところ、テンプレートで1ページ5件に変更したWP_Queryオブジェクトを生成してループ処理したとします。

このとき、アーカイブの3ページ目のURLにアクセスすると、デフォルトの検索処理では21件目からを探しに行くためNOT FOUNDとなり、404テンプレートなどが選択されてしまいます。

そのため、ページのメインループの変更には、やはり適しません。

そもそもメインループにはあまり使用しませんが、get_posts() という関数もあります。

これは、検索結果を直接配列で返すため、デフォルトのWP_Queryオブジェクトはもちろん、グローバル変数 $post にも影響しないという点で、ページ内での副次的な投稿取得には非常に手軽です。

内部的には、もちろんWP_Queryクラスを使用していますが、WP_Queryオブジェクトが隠蔽されるため、ループ処理や出力処理は、全て自前で書く必要があります。

pre_get_postsフィルター

さて、本題のpre_get_postsフィルターですが、WP_Queryクラスが生成された際、DBにクエリを投げる前に、通過するフィルターです。

コールバック関数の引数にはWP_Queryオブジェクトそのものが渡されます。
コールバック関数内では、is_archive() 等のメソッドによって、query_varsプロパティの中身を評価し、set() メソッド等によって、query_varsプロパティの値を書き換えることができます。

注意すべき点は、このフィルターは、当然のことながら、デフォルトのWP_Queryオブジェクト生成時のみならず、テンプレート内で新たにWP_Queryオブジェクトを作成した時はもちろん、get_posts() 内部でWP_Queryオブジェクトが生成された時や、管理画面の表示時などにも通過するということです。

そのため、is_admin() メソッドや、is_main_query() メソッドの戻り値を評価することによって、意図したケースのみにquery_varsプロパティが書き換えられるようにする必要があります。

余談:WordPressの優しさ〜WP_Queryクラスのメソッドとテンプレートタグ

テンプレートのループ処理内で使用されるhave_posts() や、the_posts() は、元々、WP_Queryクラスのメソッドです。

そのため、$wp_query->have_posts() などと記述すべきなのですが、WordPressは、関数として、同名の have_posts() や the_post() を用意してくれています。

これはもちろん、内部的には、グローバル変数 $wp_query に格納されている、WP_Query オブジェクトのメソッドをコールしています。

なんと冗長な・・・と思わなくもありませんが、クラスやオブジェクトのことがよくわからないPHP初心者でも扱えるようにという、WordPressの優しさでしょう。

Plugin Outbound Posts – 記事リスト内に外部リンクを挿入

Outbound Posts – 記事リスト内に外部リンクを挿入

投稿のリストの中に、見た目は他の投稿のリンクと同じように、外部リンクを差し込みたい、なんてことはありませんか? こんな風に・・・ Outbound Posts は、このような記事風の外部リンクを簡単に投稿できるプラグインです。 このプラグインを有効化すると、各記事の投稿画面に、「外部リンク」という欄が現
Column WordPressが重い・遅いときは、まず「プラグインのスリム化」をしよう 〜調査篇〜

WordPressが重い・遅いときは、まず「プラグインのスリム化」をしよう 〜調査篇〜

WordPressが重い、遅い!? WordPressのサイトが重い、読み込みが遅いので高速化したい、という相談をよく受けます。 本シリーズでは、実際の高速化の実例を元に、事前調査から対応までの手順をご紹介します。 WordPressが遅い原因 経験上、WordPressが遅い原因の80%以上はプラグインの過剰使用です。 プラグイン
Column WordPressにXMLサイトマップを独自実装するカスタマイズ

WordPressにXMLサイトマップを独自実装するカスタマイズ

WordPressに限らず、SEO対策に不可欠なXMLサイトマップ。 カスタマイズせずとも「Google XML Sitemaps」などのプラグインで瞬殺なわけですが、 多くのXMLサイトマッププラグインは、柔軟に設定できるように作られている分、 「このサイトでは要らない機能」がたくさん含まれることになるので、多少なりともリソー
Plugin AD5 LOYALTY – WordPressで会員制サイト作成

AD5 LOYALTY – WordPressで会員制サイト作成

当サイトで使用しているプラグインです。 WordPressのサイトを簡単に会員制サイトにすることができます。 ショートコードで簡単に会員登録フォーム、ログインフォームが設置可能で、全ての投稿に対して、会員用コンテンツと非会員用コンテンツを設定することができます。 ショートコートで簡単に会員登録フォーム
Column WordPressテーマ・プラグイン開発時のセキュリティ対策

WordPressテーマ・プラグイン開発時のセキュリティ対策

WordPressのテーマやプラグインを開発、カスタマイズする際には、脆弱性を生まないよう、セキュリティ対策を十分に考慮する必要があります。 CSRF対策 管理画面内外を問わず、WordPressにリクエストを送信するフォームや、データを更新するAJAXを実装する場合には、CSRF対策を施しましょう。 リクエストを送信する
Plugin Mobile Sticky Footer – スマホ用固定フッター

Mobile Sticky Footer – スマホ用固定フッター

Mobile Sticky Footerは、スマートフォンサイトに簡単に固定フッターを設置できるWordPressプラグインです。 選べる3タイプのレイアウト 複数ボタンタイプは2ボタンから5ボタンまで設定可能。 お問合せフォームやSNSへのリンクのほか、電話ボタンの設置も可能です。 リアルタイムプレビューつきの直感的な設定画
Column WordPressにメールフォームを自力で実装する

WordPressにメールフォームを自力で実装する

WordPressにメールフォームを実装する優秀なプラグインは沢山ありますが、 ほとんどのプラグインは非開発者向けに導入しやすさを重視して作られているため、 例えば入力項目を動的にするなど、少し複雑なことをしようと思うと、 詰んでしまいます。 WordPressにはメール送信処理やデータの保存などを簡単に実装できる
Plugin WP LOYALTY Checkout add-on – クレジットカード決済

WP LOYALTY Checkout add-on – クレジットカード決済

当サイトで使用しているプラグインです。 AD5 LOYATYのアドオンとして、決済機能を提供します。 決済サービスとして、カード決済手数料が3.0%〜と安く、個人事業主でも利用可能なPAY.JPと連携できます。 (別途PAY.JPのアカウントが必要です。)
Column WordPressのテーマファイル構成を本気出して考えてみた

WordPressのテーマファイル構成を本気出して考えてみた

エンジニアの端くれとして、たかがWordPressテーマであっても、綺麗なモジュール設計がしたいわけです。 そこで、以前作ったサイトのテーマをモチーフに、テーマファイルを再設計してみました。 対象にしたサイトは、ユーザーが会員登録し、PDFコンテンツを投稿でき、ダウンロード結果を集計できるなど、そこそこ高機
Column WordPressサイトにパンくずリストをプラグインなしで実装する

WordPressサイトにパンくずリストをプラグインなしで実装する

意外と大変なパンくずリスト WordPressサイトに限らず、SEOの面でも重要視されるパンくずリスト(breadcramb nav)。 WordPressでガチで実装すると意外と面倒ですよね。 個別投稿ページだけでも、 A. 標準投稿 HOME > 親カテゴリ > 子カテゴリ > 投稿名 B. 固定ページ HOME > 親ページ >
 
ログイン
メールアドレス
パスワード
会員登録
お名前
メールアドレス
パスワード
購入手続き
カード番号
有効期限 (MM/YY)
/
セキュリティコード (CVC)