WordPressの起動3 - WP_Queryクラスのカスタマイズ

2016/01/06

WordPressの起動

WP_Queryのメインループは$wp_queryインスタンスからメソッドを実行し該当する投稿データを取得しますが、サブループ(カスタムループ)を作る場合には別途$wp_query2のようなインスタンスを生成する必要があります。

ジャカルタ

インドネシアのITサービス

インターネット技術の急速な発展と普及により、優秀なIT人材を輩出することで知られるジャカルタのビヌス大学(BINUS)やバンドゥンのバンドゥン工科大学、インドネシアコンピューター大学(UNIKOM)の学生の多くがインターネット・WEB業界やソフトウェア業界を志望するようです。

続きを見る

WPクラスとWP_Queryクラス

$wp、$wp_the_query、$wp_queryなどのクラスのオブジェクトは、wp-settings.phpの中で実体化され、スーパーグローバル変数$GLOBALSに格納されています。

WordPressの起動

WordPressの起動2 - WordPress起動時に読み込まれるコアファイルの順番

index.phpはWordPressのエントリーポイントでwp-blog-header.phpを通して環境設定ファイルwp-load.phpを呼びwp-config.phpの中でDB接続情報を読み込み、WordPressメイン関数を実行実行してtemplate-loader.phpの中でテンプレートを選択します。

続きを見る

  1. wp()
  2. $wp->main()
  3. ----$wp->parse_request():①URLをパース(分析)しクエリを特定
  4. ----$wp->query_posts()
  5. --------$wp_query->query()
  6. ------------$wp_query->get_posts():③投稿データを$posts配列に格納
  7. ----------------$wp_query->parse_query():②条件分岐タグで使用されるすべてのis_変数を設定

URLからクエリを特定し、条件分岐タグを使えるための値をセットして、wp_postsテーブルなどから必要な投稿データをグローバル変数$postsに格納する3つの処理は、コンテンツを表示するループの中で使われる処理です。

<?php if( is_single()):  //①③URLから分岐条件にtureかfalseがセットされている?>
<?php 
if(have_posts()):
    while(have_posts()): the_post();  //②必要なデータが格納される
?>
	<h2><?php the_title(); ?></h2>
     <?php the_content(); ?>
<?php 
    endwhile; 
endif;  
?>
<?php endif; //is_single()?>

query_posts関数とget_posts関数

上記のようにquery_posts関数はメインクエリを取得するための関数でありwp-includes/query.php内に以下のように定義されていますが、Codexには「この関数はプラグインまたはテーマの中で使われることを想定されていません。」と書いてあります。

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

つまりquery_posts関数はテンプレートタグ(テンプレートの中で使う関数)ではないわけで、処理の実態はWP_Queryクラス内のメインクエリ取得のための関数です。

一方でget_posts関数はwp-includes/post.phpで以下のように定義されています。

function get_posts( $args = null ) {
	$defaults = array(
		'numberposts' => 5,
		'category' => 0, 'orderby' => 'date',
		'order' => 'DESC', 'include' => array(),
		'exclude' => array(), 'meta_key' => '',
		'meta_value' =>'', 'post_type' => 'post',
		'suppress_filters' => true
	);

	$r = wp_parse_args( $args, $defaults );
	if ( empty( $r['post_status'] ) )
		$r['post_status'] = ( 'attachment' == $r['post_type'] ) ? 'inherit' : 'publish';
	if ( ! empty($r['numberposts']) && empty($r['posts_per_page']) )
		$r['posts_per_page'] = $r['numberposts'];
	if ( ! empty($r['category']) )
		$r['cat'] = $r['category'];
	if ( ! empty($r['include']) ) {
		$incposts = wp_parse_id_list( $r['include'] );
		$r['posts_per_page'] = count($incposts);  // only the number of posts included
		$r['post__in'] = $incposts;
	} elseif ( ! empty($r['exclude']) )
		$r['post__not_in'] = wp_parse_id_list( $r['exclude'] );

	$r['ignore_sticky_posts'] = true;
	$r['no_found_rows'] = true;

	$get_posts = new WP_Query;
	return $get_posts->query($r);

}

ややこしいですがWP_Queryクラス内でグローバル変数$postsに投稿データを格納するメソッドもget_posts()ですが、別モノですから要注意。

このテンプレートタグであるget_posts()のほうが、WP_Queryからメインクエリとは別のクエリを生成していることから、カスタムクエリでのデータ取得にはget_query()テンプレートタグが使われてきましたが、最近は以下のようにWP_Queryクラスからカスタムループ用クエリを使うためのインスタンスを生成して使うのが主流です。

カスタムループ作成はWP_Queryクラスで

WordPressのメインループは、WP_Queryクラスの$wp_queryインスタンスからメソッドを実行し、適切な投稿データを取得しますが、メインループ以外で独自の条件でクエリを実行する場合は、$wp_query2みたいに別途インスタンスを生成する必要があります。

<?php
//WP_Queryクラスの引数を連想配列$argsにセット
$args=array(
    'post_type' => 'post',   //投稿
    'post_per_page'=>3  //取得件数3
    );

//WP_Queryクラスからインスタンス$wp_query2を生成
$wp_query2=new WP_Query($args);
?>

いつものWordPressループを$wp_query2のメソッドとして実行します。

<?php
if ( $wp_query2->have_posts() ) {
    while ( $wp_query2->have_posts() ) {
        $wp_query2->the_post();
    }
}
?>
<?php
    endwhile;
endif;
?>

メインループの変更はpre_get_postsフックで

投稿を取得するクエリのコアであるget_postsメソッドの中で、$this->parse_query()を実行した後に、pre_get_postsというアクションフックが仕込んであり、WP_Queryのパラメータを配列引数array( &$this )でプラグイン側に送りますので、プラグイン関数側で$queryという配列型オブジェクトとして受け取り、パラメータを書き換えることで、メインクエリの動きを調整します。

public function get_posts() {
        global $wpdb;
        $this->parse_query();  //条件分岐タグで使用するis_変数への値をセット
        do_action_ref_array( 'pre_get_posts', array( &$this ) ); //アクションフック
                
        //省略
        return $this->posts;
}

functions.php内で、プラグイン関数とpre_get_postsフックをadd_action関数でマッピングしてあげれば、メインクエリを操作できます。

add_action('pre_get_posts', 'pre_get_posts_map');

function pre_get_posts_map($query){
    $query->set('posts_per_page', 3);
}

プラグイン関数ではWP_Queryのパラメータを配列オブジェクト$queryとして受け取り、setメソッドで値を書き換えます。

  • $query->set('パラメータ名', '値');