WordPress 里的自定义查询

WordPress是一个非常流行的CMS以及博客平台,它有非常强大、贴心的功能。例如它会根据你当前访问的页面自动为你查询数据,访问分类页面时,会显示该分类下的最新文章;访问文章页面时,则会将文章的内容显示出来,这样固然很好很方便,但是却牺牲了灵活度。

那么问题来了,WordPress 里如何进行自定义查询?

在说自定义查询前,先要知道 WordPress 的主查询,即 Main Query。WordPress 的机制是:当检测到特定页面的访问时,会创建一个全局变量 ($query),并将该页面的信息当作参数传入 $query,然后执行 $query 的查询方法,并将查询到的数据保存到 $query 中,这样,当你在模板文件里使用的 have_posts()the_post() 等方法,访问的都是 $query 里的数据。

WordPress里进行自定义查询的方法大致有3种:

1、pre_get_posts Action

pre_get_posts Action 的执行是在 $query 变量创建后,但在查询执行前调用的,因此你可以通过修改 $query 变量的参数,来改变查询的结果。该 Action 会将 $query 对象的引用作为参数传入该方法,因此对该对象的任何操作都会生效。该 Action 修该的是主查询,因此你可以使用该 Action 来改变主查询的内容。

例如在首页的文章列表中排除某些分类的文章:

function exclude_category( $query ) {
    if ( $query->is_home() && $query->is_main_query() ) {
        $query->set( 'cat', '-1,-2' );
    }
}
add_action( 'pre_get_posts', 'exclude_category' );

或者设置每页显示的文章数:

function home_pagesize( $query ) {
    if ( is_admin() )
        return;

    if ( is_home() ) {
        $query-->set( 'posts_per_page', 5 );
        return;
    }
}
add_action( 'pre_get_posts', 'home_pagesize', 1 );

这里注意到在上一个例子中我们用 is_admin() 来排除掉了后台的页面,原因就是该 Action 同时会对后台的查询生效。

2、query_posts Function

query_posts 方法是另一种修改主查询的方法,但是更为直接,因为它会直接覆盖 $query 变量。WordPress 官方建议不要轻易使用该方法,而是使用 pre_get_posts Action 来代替,因为两者实现的功能类似,但是前者会增加页面的加载时间(需要重新查询),带来代码上的混淆等诸多弊端,所以咱们还是别自找麻烦了。

3、WP_Query Class

前面所讲的主查询,使用的便是 WP_Query 类,使用该类,可以实现完全的自定义查询。该类封装了一些方法,用来处理文章的查询请求。

例如,你需要在文章页面的末尾显示该文章的相关文章,相关文章是和该文章同一分类下的随机的 6 篇文章。你可能需要这样写:

// The Main Loop
$post_id = get_the_ID();
$post_category = get_the_category($post_id);
$cat_id = $post_category->term_id;

$args = array(
	'post_status' => 'publish',
	'orderby'       => 'rand',
	'cat'  => $cat_id,
	'post__not_in' => array($post_id),
	'paged'         => 1,
	'posts_per_page' => 6
);

$my_query = new WP_Query($args);

if ( $my_query->have_posts() ) {
	$list = '<ul>';
	while ( $my_query->have_posts() ) {
		$my_query->the_post();
		$list .= sprintf('<li><a href="%s">%s</a></li>', the_permalink(), the_title());
	}
	$list .= '</ul>';
	echo $list;
}
wp_reset_postdata();
// The Main Loop

这里我们先获取文章 ID,再根据 ID 获取分类,然后构造参数并创建 WP_Query 对象,然后调用 have_posts() 来遍历查询到的文章。

WP_Query 的构造参数非常之多,这里不一一举例,通过这些参数的组合,我们几乎能实现任何的自定义的查询。

总的来说,如果要修改主查询,例如修改分类页面的排序方式,每页的文章数,排除某些文章等,则使用 pre_get_posts Action,而要进行完全的自定义查询,如侧边栏的最新文章,或者自己创建的新页面,则需要使用 WP_Query 类,query_posts 则一般不用。