問題描述
我有以下查詢,我通過 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()($wpis 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_queryis 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_querydoesn’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 輔助翻譯的英文資料結果。如果您對結果不滿意,可以加入我們改善翻譯效果:薇曉朵技術論壇。