WordPress是一个非常流行的CMS以及博客平台,它有非常强大、贴心的功能。例如它会根据你当前访问的页面自动为你查询数据,访问分类页面时,会显示该分类下的最新文章;访问文章页面时,则会将文章的内容显示出来,这样固然很好很方便,但是却牺牲了灵活度。
那么问题来了,WordPress 里如何进行自定义查询?
在说自定义查询前,先要知道 WordPress 的主查询,即 Main Query
。WordPress 的机制是:当检测到特定页面的访问时,会创建一个全局变量 ($query)
,并将该页面的信息当作参数传入 $query
,然后执行 $query
的查询方法,并将查询到的数据保存到 $query
中,这样,当你在模板文件里使用的 have_posts()
、the_post()
等方法,访问的都是 $query
里的数据。
WordPress里进行自定义查询的方法大致有3种:
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 同时会对后台的查询生效。
query_posts 方法是另一种修改主查询的方法,但是更为直接,因为它会直接覆盖 $query
变量。WordPress 官方建议不要轻易使用该方法,而是使用 pre_get_posts
Action 来代替,因为两者实现的功能类似,但是前者会增加页面的加载时间(需要重新查询),带来代码上的混淆等诸多弊端,所以咱们还是别自找麻烦了。
前面所讲的主查询,使用的便是 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
则一般不用。