pre_get_posts なるものがあったなんて。。

 

カテゴリ一覧等のアーカイブのページでは、ほとんどquery_posts()を使ってソート順や記事の取得をおこなっていました。

wordpressの日本語サポートフォーラムでもそれで返事をしていました。
記事一覧の時のソートができません

そんななか、サポートフォーラムをちょくちょく見ていると、query_postsよりpre_get_postsのほうがいいよ。
という記載があったり。

そんな関数があるの?pre_get_posts()という関数の存在が分かりませんでした。

そこでちょっと調べてみました。

http://codex.wordpress.org/Plugin_API/Action_Reference/pre_get_posts

英語だらけ。難しい。。

http://wpdocs.sourceforge.jp/テンプレートタグ/query_posts

ここはquery_postsの説明(日本語)です。

functions.phpでpre_get_postsを使って同じことをするなら、このように書けます。
function five_posts_on_homepage( $query ) {
if ( $query->is_home() && $query->is_main_query() ) {
$query->set( ‘posts_per_page’, ‘5’ );
}
}
add_action( ‘pre_get_posts’, ‘five_posts_on_homepage’ );

いつからでしょうか、こんな表記が。前からこんな表記あったっけな。。

と、ここで日本語のドキュメントを発見。

http://wpdocs.sourceforge.jp/プラグイン_API/アクションフック一覧/pre_get_posts

使い方は、条件分岐等をおこなって、

$query->set();

で取得したい記事の種類や順序、数を決める感じかな。
->set()はcakephpみたいでこっちのほうが感覚的にやりやすそう。

念の為、コアファイルのset()に当たる部分を確認してみることに。

おそらく、wp-include/query.phpの1900行目辺りの、

function set($query_var, $value) {
  $this->query_vars[$query_var] = $value;
}

が$query->set()の部分だと思います。

$query->set( ‘posts_per_page’, ‘5’ );
こういう指定だと、
$this->query_vars[“posts_per_page”] = 5;
こういう風になるって事かな。

query_posts() は

function query_posts($query) {
 $GLOBALS['wp_query'] = new WP_Query();
 return $GLOBALS['wp_query']->query($query);
}

うーん、クラス WP_Query のfunction query()を実行して突っ込んだ値を返す。かな。

http://wpdocs.sourceforge.jp/関数リファレンス/WP_Query
を読んだほうがいいかな。

うん、読んでもよく分からない :mrgreen:

私の場合は実行して確かめたほうが早いかな。

あの時のフォーラムの質問者の方と同じ環境にする為にまずは

  1. 記事を5個ぐらい追加。
  2. 記事への評価とアクセス数を取得する為に、WP-PostRatingsとWP-PostViews をインストール。

と、こんな感じ。

記事一覧
記事一覧

あ、評価やアクセス数でソートしなきゃいけないから、評価も適当につけないといけないか。
カテゴリも適当に1つ作らないと。公開日も適当にばらばらにしないと。

なので、こうなるかな。

記事一覧2
記事一覧2

この状態で「未分類」のカテゴリ一覧の$wp_queryを確認してみます。

WP_Query Object
(
    [query] => Array
        (
            [cat] => 1
        )

    [query_vars] => Array
        (
            [cat] => 1
            [category_name] => %e6%9c%aa%e5%88%86%e9%a1%9e
            [category__in] => Array
                (
                    [0] => 1
                )

            [posts_per_page] => 10
            [nopaging] => 
            [order] => DESC
        )
...

デフォルトのクエリですね。

ここで、query_posts()にて、記事のソートを評価の高い順でソートしてみます。

WP_Query Object
(
    [query] => Array
        (
            [cat] => 1
            [nopaging] => 1
            [orderby] => meta_value_num
            [meta_key] => ratings_average
        )

    [query_vars] => Array
        (
            [cat] => 1
            [nopaging] => 1
            [orderby] => meta_value_num
            [meta_key] => ratings_average
            [category_name] => %e6%9c%aa%e5%88%86%e9%a1%9e
            [category__in] => Array
                (
                    [0] => 1
                )
            [posts_per_page] => 10
            [order] => DESC
        )

WP_Query Object->query部分に指定したクエリが入りましたが、結局query_varsにも入るようになっているんですね。

次は、pre_get_posts。コードはこれ。

function add_fil_pre_get_posts( $query ) {
 if ( $query->is_category && $query->is_main_query() ) {
 $query->set( 'nopaging', 1 );
 $query->set( 'orderby', 'meta_value_num' );
 $query->set( 'meta_key', 'ratings_average' );
 }
}
add_action( 'pre_get_posts', 'add_fil_pre_get_posts' );

結果は、

WP_Query Object
(
    [query] => Array
        (
            [cat] => 1
        )

    [query_vars] => Array
        (
            [cat] => 1
            [error] => 
            [category_name] => %e6%9c%aa%e5%88%86%e9%a1%9e
            [meta_key] => ratings_average
            [category__in] => Array
                (
                    [0] => 1
                )
            [nopaging] => 1
            [orderby] => meta_value_num
            [posts_per_page] => 10
            [order] => DESC
        )

WP_Query Object->queryには一切値は入りません。query_varsだけに値がセットされました。
query_posts、pre_get_postsともに、見た目は同じように評価順の記事のソートになりました。

 

queryって意味ないの?なんなの?
ということで、queryに関するところを調べていたら、get_posts()関数にquery_varsに関することがありました。

function get_posts() {
 global $wpdb, $user_ID, $_wp_using_ext_object_cache;

$this->parse_query();
do_action_ref_array('pre_get_posts', array(&$this));

// Shorthand.
$q = &$this->query_vars;

// Fill again in case pre_get_posts unset some vars.
$q = $this->fill_query_vars($q);

// Parse meta query
$this->meta_query = new WP_Meta_Query();
$this->meta_query->parse_query_vars( $q );

$qは最終的にsql文に追加される配列部分。これって、query_varsをもとにデータを取得していますよね。(違うかな?)

そうだとすると、pre_get_posts()フックで記事のソートが出来る事が理解は出来ますが。

余計にqueryの意味が分からなくなってきた 😕
何の為にあるの?もうちょっと探ってみましたが。

さっぱり分からず。

$this->queryを使って何か処理をしているところを探してみましたが、さっぱり。

これ以上はよく分かりません。今日はこの辺で終わりにしよう。

 

でも、とりあえずpre_get_posts()で目的の記事一覧が取得できる事は理解できました。
今後はこれを使っていこうかな。

そういえば、これは注意。

http://wpdocs.sourceforge.jp/プラグイン_API/アクションフック一覧/pre_get_posts

このページの、メモ、の3番目。

このフィルターは管理画面のクエリーにも影響を与えます。

えー。対処法はis_admin()とかでなんとかなると思うけど、もっと大きく書いて欲しい。

 

——————————–

よく考えたら、アーカイブの記事一覧の順序を自由に変更するプラグインってないのかな?

無ければ作ろうかな。

コメントを残す