SlideShare une entreprise Scribd logo
1  sur  35
WordPressの表示件数
WP_Queryを巡る冒険
田島 優也
プライム・ストラテジー
WordPressの表示件数
WordPressには管理画面から、
各アーカイブページの表示件数を変えられる
機能がデフォルトでついています。
たとえば、表示したい投稿数が60件だとして
1ページの表示件数を10件とすれば、
10件ずつページ送りされて、
6つのページに分割することができます。
管理画面>設定>表示設定
でも
場合によっては、
それぞれのアーカイブページによって表示件数を変えたい
時もある。
たとえばカテゴリーページでは5件表示にしたり、
トップページでは10件にしたいなどなど。。。
さて、どうしよう。
すると、ヒントが!
http://www.warna.info/archives/1964/
pre_get_posts
• 大曲さんのブログによると、pre_get_postsとい
うフックを利用して、色々やると実現したいこ
とができるらしい。
• そこで、WordPressのファイルの中身を探検し
てみることにします。
• なお、以下参照していくコアファイルは
WordPress3.5.1のものです。
./wp-includes/query.php 1919行
該当のフックは/wp-includes/query.php 1919
行
function get_posts() {
…略…
do_action_ref_array('pre_get_posts', array(&$this));
にありました。
get_posts()
なお、ここでのget_posts()は
Wp_Queryクラスのメソッドであるget_posts()で
あり、テーマのテンプレートでよく使うget_posts()とは別
物です。
あの便利なget_posts()は
/wp-includes/post.phpの1699行目付近に書いて
あります。
do_action_ref_array
http://codex.wordpress.org/Function_Reference/do_action_ref_array
Codexによると
This function is identical to do_action,
but the arguments passed to the functions hooked to
$tag are supplied using an array.
[意訳]
この関数はdo_actionと同一、
しかしこのタグにフックされた関数に渡される引数は一つの配列です。
そもそも
ページの表示件数はどこで決めているのかといえば、
WP_Queryクラスのquery_varsプロパティ(配列)。
の中の
posts_per_pageをキーとする値が
1ページの表示件数を決めています。
WP_Queryクラスのquery_varsプロパティ
$this->query_vars;
コード中ではこのように表記されています
だけど、この時点では。。。
つまり、アクションフック、
do_action_ref_array('pre_get_posts',array(&$this));の処理の
時点では。
query_varsの中身に
'posts_per_page'というキー自体がそもそも存在しない。
処理を上から追っていってみま
しょう。
•./wp-includes/query.php 1922行
$this->parse_query();によって$this->query_varsにいくつかキーが追加
されているもののまだ‘posts_per_page‘は未設定。
$q = &$this->query_vars;
query_varsプロパティを参照変数$qに代入している。
ん、参照変数?
参照とは何?
通常、変数に値を代入する時。
$a = 10;
$b = $a;
$b = 20;
echo '$aの結果は' . $a . '<br/>';
echo '$bの結果は' . $b;
$aの結果は10
$bの結果は20
とブラウザ上に表示されます。
参照とは何?
しかし。
$a = 10;
$b =& $a;
$b = 20;
echo '$aの結果は' . $a . '<br/>';
echo '$bの結果は' . $b;
$aの結果は20
$bの結果は20
と表示されます。
参照とは何?
実は=&(参照代入演算子)を用いて
右辺を左辺に代入すると、左辺は右辺のデータを格納する
領域を表示する変数を表します。
つまり$bは$aは同じ場所を向いているので、$aの変更は
$bに、また$bの変更は$aに反映されます。
二人の別々の人間が、同じ方向を向いているようなことで
すね。
(参照の内部的な挙動はプログラミング言語によって違うの
で調べてみると面白いかもしれません)
戻ります
ということで、
$q = &$this->query_vars;
これ以降は
$this->query_varsと$qは同じものとみなし
てよさそうです。
更に下に進んでいくと、
•./wp-includes/query.php 1922行
if ( !isset($q['posts_per_page']) || $q['posts_per_page'] == 0 )
$q['posts_per_page'] = get_option('posts_per_page');
という表記が見つかりました。
これはつまり$q[‘posts_per_page’]に値がセットされていて、その値がNULLで
ないまたは0と同値であるような値である場合は
wp_optionsテーブル(プレフィックスをwp_に設定してあれば)のoption_nameカ
ラムがposts_per_pageであるoption_valueの値をセットする。
どういうことかというと。
管理画面の設定 > 表示設定 > 1ページに表示する最大投稿
数がそこにセットされるということです。
つまり、すでに $q['posts_per_page']が設定されていたなら
ば、そこの値ではなく
前もって$q['posts_per_page']に設定されている値が1ペー
ジに表示する最大投稿数に設定される仕組みになっている
らしい。
だったら前もってここに値を設定しておけば、表示件数を
自由にかえられそうです。
pre_get_posts
add_action( 'pre_get_posts', 'コールバック関数');
コールバック関数の箇所に$q['posts_per_page']を
設定する処理をかけばよさそうです。
pre_get_posts
コールバックに渡される引数はarray(&$this)
つまりこのオブジェクト自身なので。
たとえば、アーカイブページの表示を変えたい場合は
function archive_change_posts_per_page($query) {
if ( !is_admin() && $query->is_main_query()){
if ( $query->is_archive()) {
$query->set( 'posts_per_page', '5' ) );
}
}
}
この関数をコールバックとして渡してやります。
この関数について少し詳しくみていきましょう。
引数に渡す$queryの部分は通常、グローバル変数$wp_queryが渡されています。
if ( !is_admin() && $query->is_main_query())
この部分で管理画面ではない、かつ$query->is_main_queryが真であれば。
アクションフック、pre_get_postsは管理画面にも影響を与えます。
具体的にいうと、
投稿一覧、固定ページ一覧、メディアライブラリ、各カスタム投稿タイプの記
事一覧の表示件数などに影響を与えます。
(Wp_Queryのインスタンスを利用したプラグインなどを使用していると他にも
影響があるかもしれません)
各一覧ページの表示させる件数は表示オプションから変更できますが、この
フックが有効になっていると表示件数を変えることができないということにな
るので!is_admin()を条件に加えておきましょう。
$query->is_main_query
大曲さんのブログによると、
WordPress3.3から使えるようになったようです。
is_main_queryメソッドでは何をしているかというと。
function is_main_query() {
global $wp_the_query;
return $wp_the_query === $this;
}
}
現在処理の対象となっているオブジェクト($wp_query)が$wp_the_queryと等
値であるかを判別しているようです。
オブジェクトの比較
http://www.php.net/manual/ja/language.oop5.object-comparison.php
PHPにおけるオブジェクトの比較については
比較演算子(==)を使用する際、オブジェクト変数は、単純に比較され
ます。つまり、 二つのオブジェクトのインスタンスは、同じ属性と値
を有し、同じクラスのインスタンスである場合に、等しいとされます。
一方、一致演算子(===)を使用する場合、オブジェクト変数は、同じク
ラスの同じインスタンスを参照する場合のみ、等しいとされます。
つまり、$wp_queryが$wp_the_queryと同じ格納領域を参照しているか
どうかの判定結果を返しているようです。
$wp_the_queryとか、$wp_queryとか
$wp_the_queryとか、$wp_queryとか話がややこしくなっ
てきました。。
./wp-includes/query.phpを一度離れて、WordPressの最初
の方の処理からたどってみましょう。
するとwp-settings.phpに以下のような記述がありました。
./wp-settings.php
224行目
$wp_the_query = new WP_Query();
232行目
$wp_query = $wp_the_query;
実はこれもまた参照変数に代入されているのです。
=&がないのに参照?
PHP5からはオブジェクトの代入は
=&でなくとも=で参照変数への代入になります。
よって、
$wp_queryは$wp_the_queryの参照変数となる。
以降、WordPressは$wp_queryを中心に処理を行なっ
ていきます。
再び$query->is_main_query
何故、$query->is_main_query()が真である必要があるのか。
たとえばquery_posts関数を使っていた場合。
./wp-includes/query.php 89行目
function query_posts($query) {
$GLOBALS['wp_query'] = new WP_Query();
return $GLOBALS['wp_query']->query($query);
}
参照変数$wp_queryを新たなWP_Queryのインスタンスで上書きしてい
ます。
その新たなインスタンスのメソッドを使って引数で与えられたqueryメ
ソッドを実行する。
再び$query->is_main_query
参照変数に再度別の変数の参照を代入した場合は、新しい参照変数と
なってしまうので、
$wp_queryと$wp_the_queryが別のオブジェクトを参照していることに
なり
$wp_the_query === $thisの判定は偽となります。
再び$query->is_main_query
./wp-includes/query.php 3550 行
function is_main_query() {
global $wp_the_query;
return $wp_the_query === $this;
}
$wp_the_queryと等値(同じオブジェクトの同じインスタンスを参照し
ているということなのでメインクエリであることが保証される。基本
的に$wp_queryはquery_postsなどによって書き換えられるが、
$wp_the_queryは書き換えられない)
つまり本来そのページに適用されるべき記事の表示件数だけをかえた
い場合は、$query->is_main_queryが真である必要があります。
余談 wp_reset_query()
./wp-includes/query.php 104行目
function wp_reset_query() {
$GLOBALS['wp_query'] = $GLOBALS['wp_the_query'];
wp_reset_postdata();
}
wp_reset_queryは別のインスタンスを参照してしまった$wp_queryを
再びグローバル変数wp_the_queryの参照変数とする処理を行なってい
ます。
query_posts()の後にwp_reset_query()が必要なのはそういう理由です。
再びコールバック関数
function archive_change_posts_per_page($query) {
if ( !is_admin() && $query->is_main_query()){
if ( $query->is_archive()) {
$query->set( 'posts_per_page', '5' ) );
}
}
}
$query->is_archive()メソッドによって、アーカイブページであるかど
うかを判定して、
$query->set( 'posts_per_page', '5' ) );
を実行します。
$query->set( 'posts_per_page', '5' ) );
./wp-includes/query.php 1903行
function set($query_var, $value) {
$this->query_vars[$query_var] = $value;
}
よって、
$this->query_vars['posts_per_page'] = 5;
となります。
まとめ
$this->query_vars[‘posts_per_page’]が設定されていることによって
アーカイブページの時だけ、
$q['posts_per_page'] = get_option('posts_per_page');
の設定が適用されず
archive_change_posts_per_page関数での処理で設定した
$this->query_vars['posts_per_page'] = 5
が適用されることになるので
アーカイブページの表示件数だけ5件とすることができます。
おまけ
でもいちいち、この処理をfunctions.phpに書くのは手間か
もしれない・・・
そこで簡易的ではありますが、プラグインを作りました。
現在は一般的なアーカイブ設定と検索結果、各カテゴリの
表示件数しか変えられませんが、のちのち改良していきた
いと思います。
コードの間違いや改良点などのフィードバックも頂ければ
幸いです。

Contenu connexe

En vedette

PHP7で目指す 継続的インテグレーション開発
PHP7で目指す 継続的インテグレーション開発PHP7で目指す 継続的インテグレーション開発
PHP7で目指す 継続的インテグレーション開発優也 田島
 
var dumpを使わないWordPress開発フロー
var dumpを使わないWordPress開発フローvar dumpを使わないWordPress開発フロー
var dumpを使わないWordPress開発フロー優也 田島
 
初心者向けWordPress DB & Performance
初心者向けWordPress DB & Performance初心者向けWordPress DB & Performance
初心者向けWordPress DB & PerformanceTakayuki Miyauchi
 
これから始める人のためのjQuery入門 先生:大竹 孔明
これから始める人のためのjQuery入門 先生:大竹 孔明これから始める人のためのjQuery入門 先生:大竹 孔明
これから始める人のためのjQuery入門 先生:大竹 孔明schoowebcampus
 
Yahoo! JAPAN MeetUp #8 (インフラ技術カンファレンス)セッション①
Yahoo! JAPAN MeetUp #8 (インフラ技術カンファレンス)セッション①Yahoo! JAPAN MeetUp #8 (インフラ技術カンファレンス)セッション①
Yahoo! JAPAN MeetUp #8 (インフラ技術カンファレンス)セッション①Yahoo!デベロッパーネットワーク
 
Yahoo! JAPAN MeetUp #8 (インフラ技術カンファレンス)セッション②
Yahoo! JAPAN MeetUp #8 (インフラ技術カンファレンス)セッション②Yahoo! JAPAN MeetUp #8 (インフラ技術カンファレンス)セッション②
Yahoo! JAPAN MeetUp #8 (インフラ技術カンファレンス)セッション②Yahoo!デベロッパーネットワーク
 
Yahoo! JAPAN MeetUp #8 (インフラ技術カンファレンス)セッション④
Yahoo! JAPAN MeetUp #8 (インフラ技術カンファレンス)セッション④Yahoo! JAPAN MeetUp #8 (インフラ技術カンファレンス)セッション④
Yahoo! JAPAN MeetUp #8 (インフラ技術カンファレンス)セッション④Yahoo!デベロッパーネットワーク
 

En vedette (12)

PHP7で目指す 継続的インテグレーション開発
PHP7で目指す 継続的インテグレーション開発PHP7で目指す 継続的インテグレーション開発
PHP7で目指す 継続的インテグレーション開発
 
var dumpを使わないWordPress開発フロー
var dumpを使わないWordPress開発フローvar dumpを使わないWordPress開発フロー
var dumpを使わないWordPress開発フロー
 
初心者向けWordPress DB & Performance
初心者向けWordPress DB & Performance初心者向けWordPress DB & Performance
初心者向けWordPress DB & Performance
 
これから始める人のためのjQuery入門 先生:大竹 孔明
これから始める人のためのjQuery入門 先生:大竹 孔明これから始める人のためのjQuery入門 先生:大竹 孔明
これから始める人のためのjQuery入門 先生:大竹 孔明
 
Yahoo! JAPAN MeetUp #8 (インフラ技術カンファレンス)セッション①
Yahoo! JAPAN MeetUp #8 (インフラ技術カンファレンス)セッション①Yahoo! JAPAN MeetUp #8 (インフラ技術カンファレンス)セッション①
Yahoo! JAPAN MeetUp #8 (インフラ技術カンファレンス)セッション①
 
Yahoo! JAPAN MeetUp #8 (インフラ技術カンファレンス)LT①
Yahoo! JAPAN MeetUp #8 (インフラ技術カンファレンス)LT①Yahoo! JAPAN MeetUp #8 (インフラ技術カンファレンス)LT①
Yahoo! JAPAN MeetUp #8 (インフラ技術カンファレンス)LT①
 
Yahoo! JAPAN MeetUp #8 (インフラ技術カンファレンス)LT②
Yahoo! JAPAN MeetUp #8 (インフラ技術カンファレンス)LT②Yahoo! JAPAN MeetUp #8 (インフラ技術カンファレンス)LT②
Yahoo! JAPAN MeetUp #8 (インフラ技術カンファレンス)LT②
 
Yahoo! JAPAN MeetUp #8 (インフラ技術カンファレンス)LT⑧
Yahoo! JAPAN MeetUp #8 (インフラ技術カンファレンス)LT⑧Yahoo! JAPAN MeetUp #8 (インフラ技術カンファレンス)LT⑧
Yahoo! JAPAN MeetUp #8 (インフラ技術カンファレンス)LT⑧
 
Yahoo! JAPAN MeetUp #8 (インフラ技術カンファレンス)セッション②
Yahoo! JAPAN MeetUp #8 (インフラ技術カンファレンス)セッション②Yahoo! JAPAN MeetUp #8 (インフラ技術カンファレンス)セッション②
Yahoo! JAPAN MeetUp #8 (インフラ技術カンファレンス)セッション②
 
Yahoo! JAPAN MeetUp #8 (インフラ技術カンファレンス)LT③
Yahoo! JAPAN MeetUp #8 (インフラ技術カンファレンス)LT③Yahoo! JAPAN MeetUp #8 (インフラ技術カンファレンス)LT③
Yahoo! JAPAN MeetUp #8 (インフラ技術カンファレンス)LT③
 
Yahoo! JAPAN MeetUp #8 (インフラ技術カンファレンス)セッション④
Yahoo! JAPAN MeetUp #8 (インフラ技術カンファレンス)セッション④Yahoo! JAPAN MeetUp #8 (インフラ技術カンファレンス)セッション④
Yahoo! JAPAN MeetUp #8 (インフラ技術カンファレンス)セッション④
 
Yahoo! JAPAN MeetUp #8 (インフラ技術カンファレンス)LT⑦
Yahoo! JAPAN MeetUp #8 (インフラ技術カンファレンス)LT⑦Yahoo! JAPAN MeetUp #8 (インフラ技術カンファレンス)LT⑦
Yahoo! JAPAN MeetUp #8 (インフラ技術カンファレンス)LT⑦
 

WordPressの表示件数