问题描述
我有以下查询,我通过 query_brands_geo('dealers', 'publish', '1', $taxtype, $geo, $brands);
在我的 taxonomy.php 模板中调用
这个功能很完美。但是,在阅读 codex 查询帖子后,它提到了 pre_get_posts 作为更改默认查询的首选方法。 pre_get_posts 会更有效,那么下面我的 wp_query 功能呢?
如果是,我如何构建 pre_get_posts 并在下面传递我的变量和查询?
function my_custom_query($posttype, $poststatus, $paidvalue, $taxtype, $geo, $brands) {
global $wp_query;
$wp_query = new WP_Query();
$args = array(
'post_type' => $posttype,
'post_status' => array($poststatus),
'orderby' => 'rand',
'posts_per_page' => 30,
'meta_query' => array(
array(
'key' => 'wpcf-paid',
'value' => array($paidvalue),
'compare' => 'IN',
)
),
'tax_query' => array(
'relation' => 'AND',
array(
'taxonomy' => $taxtype,
'field' => 'slug',
'terms' => $geo
),
array(
'taxonomy' => 'brands',
'field' => 'slug',
'terms' => $brands
)
)
);
return $wp_query->query($args);
}
最佳解决方案
pre_get_posts
将运行相同的查询,因此两者都需要相同的时间。但是,如果您使用 pre_get_posts
操作,您将保存一个或多个 SQL 查询。现在,WordPress 正在运行默认查询,然后使用此函数运行查询,替换默认查询的结果 (结果,默认查询是没有用的) 。以下是如何将 $args
移动到
function custom_pre_get_posts($query, $posttype='dealers', $poststatus='publish', $paidvalue='1', $taxtype='any_default_value', $geo='any_default_value', $brands='any_default_value') {
// filter your request here.
if($query->is_category) {
$args = array(
'post_type' => $posttype,
'post_status' => array($poststatus),
'orderby' => 'rand',
'posts_per_page' => 30,
'meta_query' => array(
array(
'key' => 'wpcf-paid',
'value' => array($paidvalue),
'compare' => 'IN',
)
),
'tax_query' => array(
'relation' => 'AND',
array(
'taxonomy' => $taxtype,
'field' => 'slug',
'terms' => $geo
),
array(
'taxonomy' => 'brands',
'field' => 'slug',
'terms' => $brands
)
)
);
$query->query_vars = $args;
}
}
add_action('pre_get_posts', 'custom_pre_get_posts');
次佳解决方案
迟到的答案是最受欢迎的答案将会打破您的查询,在某些要点上根本不是真的。
主要的 WP_Query 和它的过滤器
首先,WordPress 内部使用 query_posts()
(WP_Query
周围的薄包装,不应该在主题或插件中使用) 来做 WP_Query
。该 WP_Query
作为主循环/查询。此查询将运行大量的过滤器和操作,直到构建实际的 SQL 查询字符串。其中之一是 pre_get_posts
。其他都是 posts_clauses
,posts_where
等,也允许你拦截查询字符串构建过程。
深入了解核心内部发生的情况
WordPress runs the
wp()
function (inwp-includes/functions.php
), which calls$wp->main()
($wp
is an object of class WP, which is defined inwp-includes/class-wp.php
). This tells WordPress to:
- Parse the URL into a query specification using
WP->parse_request()
— more on that below.- Set all the is_ variables that are used by Conditional Tags using
$wp_query->parse_query()
($wp_query
is an object ofclass WP_Query
, which is defined inwp-includes/query.php
). Note that in spite of this function’s name, in this caseWP_Query->parse_query
doesn’t actually do any parsing for us, since that is done before-hand byWP->parse_request()
.- Convert the query specification into a MySQL database query, and run the database query to get the list of posts, in function WP_Query->get_posts(). Save the posts in the $wp_query object to be used in the WordPress Loop.
Source Codex
Conclusion
如果您真的要修改主查询,那么可以使用各种过滤器。只需使用 $query->set( 'some_key', 'some_value' );
来更改数据,或者使用 $query->get( 'some_key' );
检索数据进行条件检查。这样就可以避免您进行第二次查询,因为您仅更改 SQL 查询。
如果您需要执行其他查询,那么请使用 WP_Query
对象。这将向 DB 添加另一个查询。
例子
因为答案总是以一个例子更好地工作,你在这里得到一个非常好的 (道具到 Brad Touesnard),它只是扩展核心对象,因此是非常可重用的 (使一个插件):
class My_Book_Query extends WP_Query
{
function __construct( $args = array() )
{
// Forced/default args
$args = array_merge( $args, array(
'posts_per_page' => -1
) );
add_filter( 'posts_fields', array( $this, 'posts_fields' ) );
parent::__construct( $args );
}
public function posts_fields( $sql )
{
return "{$sql}, {$GLOBALS['wpdb']->terms}.name AS 'book_category'";
}
}
然后,您可以运行您的第二个/其他查询,如下例所示。不要忘了重置您的查询。
$book_query = new My_Book_Query();
if ( $book_query->have_posts() )
{
while ( $book_query->have_posts() )
{
$book_query->the_post();
# ...do stuff...
} // endwhile;
wp_reset_postdata();
} // endif;
第三种解决方案
请查看 When to use WP_query(), query_posts() and pre_get_posts 的答案。
如果您有任何疑问,这是一个很好的资源。
参考文献
注:本文内容整合自 Google/Baidu/Bing 辅助翻译的英文资料结果。如果您对结果不满意,可以加入我们改善翻译效果:薇晓朵技术论坛。