問題描述
我需要交叉參考兩個分類,product_categories 和 brands 。我可以想到的唯一辦法就是把所有的帖子都放在一個分類中,然後得到另一個分類中存在的所有帖子:
<?php
$category = /* Taxonomy object selected from list */;
// Get all the posts in this query
$args = array(
'post_type' => 'product',
'tax_query' => array(
array(
'taxonomy' => $category->taxonomy,
'field' => 'slug',
'terms' => $category->slug
)
)
);
$product_items = get_posts( $args );
// create a blank array ready for the IDs
$product_items_ids = [];
// For every post found, populate the array
foreach ($product_items as $product_item) {
// Create array from all post IDs in category
$product_items_ids[] = $product_item->ID;
}
// Get all terms in Brand taxonomy that are in the array above
$brand_items = wp_get_object_terms( $product_items_ids, 'brand' );
// Output the information needed
foreach ($brand_items as $brand_item) { ?>
<li><a href="<?php%20echo%20get_term_link(%20$brand_item->slug,%20%20$brand_item->taxonomy%20);%20?>"> <?php echo $brand_item->name; ?></a></li>
<?php } ?>
我調用 5-10 次,如果產品列表變得很大,這意味着我正在網站上的每個帖子 10 次加載菜單等。
有沒有更有效的方式來做這種類型的查詢?
添加註意事項:
第一個查詢引用了分配了 $category->taxonomy 分類的帖子。
$category 是由高級自定義字段在管理員中選擇的分類對象。對於這個例子,説配件是一個術語,product_cat 是分類法 @PieterGoosen
我需要返回所有與附件條款相關的品牌的條款。
最佳解決思路
我們可以做很多改進代碼的性能。讓我們先設定一些基準
BENCH MARKS
-
我正在用這個測試
-
category分類學術語有 9 個職位 -
具有 61 個匹配標籤的
post_tag分類法。
-
使用您當前的代碼,我得到以下結果
-
69 查詢在= / – 0.4s
對於這樣一個小數據庫和測試對象,這是相當昂貴的和大量的查詢
OPTIMIZATIONS
我們要做的第一件事就是要查詢帖子中的帖子 ID,原因如下
-
我們不需要任何帖子數據
-
我們不需要後緩存和後期元緩存更新,我們不需要
-
顯然,只查詢帖子 ID 會大大提高性能
只查詢 ID 的缺點在於我們也放寬了緩存期限。因為我們不更新術語緩存,這將導致數據庫查詢的巨大增長。為瞭解決這個問題,我們將使用 update_object_term_cache 手動更新術語緩存。
到這個時候,只要查詢一下,你就獲得了 1db 的調用和 0.02s,這並不是那麼大,但是在一個巨大的數據庫上卻有很大的不同。真正的收穫將在下一節中介紹
真正的大收穫是將術語對象傳遞給 get_term_link(),而不是術語 ID 。如果術語緩存中沒有術語,並將術語 ID 傳遞給 get_term_link(),而不是從緩存中獲取術語對象,get_term_link()將查詢數據庫以獲取術語對象。剛剛測試,這相當於額外的 61 個 db 調用,每個標籤一個。想想幾百個標籤。
我們已經有了術語對象,所以我們可以簡單地傳遞完整的術語對象。你應該永遠這樣做即使術語對象在緩存中,傳遞術語 ID 仍然非常緩慢,因為我們仍然必須從緩存中獲取術語對象
我已經清理了你的代碼。注意,我使用了需要 PHP 5.4+的短數組語法。以下是您的代碼的外觀
$category = get_category( 13 ); // JUST FOR TESTING< ADJUST TO YOUR NEEDS
$args = [
'post_type' => 'product',
'fields' => 'ids', // Only query the post ID's, not complete post objects
'tax_query' => [
[
'taxonomy' => $category->taxonomy,
'field' => 'slug',
'terms' => $category->slug
]
]
];
$ids = get_posts( $args );
$links = [];
// Make sure we have ID'saves
if ( $ids ) {
/**
* Because we only query post ID's, the post caches are not updated which is
* good and bad
*
* GOOD -> It saves on resources because we do not need post data or post meta data
* BAD -> We loose the vital term cache, which will result in even more db calls
*
* To solve that, we manually update the term cache with update_object_term_cache
*/
update_object_term_cache( $ids, 'product' );
$term_names = [];
foreach ( $ids as $id ) {
$terms = get_object_term_cache( $id, 'post_tag' );
foreach ( $terms as $term ) {
if ( in_array( $term->name, $term_names ) )
continue;
$term_names[] = $term->name;
$links[$term->name] = '<li><a href="'%20.%20get_term_link(%20$term%20)%20.%20'">' . $term->name . '</a></li>';
}
}
}
if ( $links ) {
ksort( $links );
$link_string = implode( "nt" , $links );
} else {
$link_string = '';
}
echo $link_string;
現在,我們已經將數量減少到了 0.04 分,這是一個很大的改進。
我們甚至可以進一步,並將結果存儲在一瞬間
$category = get_category( 13 ); // JUST FOR TESTING< ADJUST TO YOUR NEEDS
$link_string = '';
$transient_name = 'query_' . md5( $category->slug . $category->taxonomy );
if ( false === ( $link_string = get_transient( $transient_name ) ) ) {
$args = [
'post_type' => 'product',
'fields' => 'ids', // Only query the post ID's, not complete post objects
'tax_query' => [
[
'taxonomy' => $category->taxonomy,
'field' => 'slug',
'terms' => $category->slug
]
]
];
$ids = get_posts( $args );
$links = [];
// Make sure we have ID'saves
if ( $ids ) {
/**
* Because we only query post ID's, the post caches are not updated which is
* good and bad
*
* GOOD -> It saves on resources because we do not need post data or post meta data
* BAD -> We loose the vital term cache, which will result in even more db calls
*
* To solve that, we manually update the term cache with update_object_term_cache
*/
update_object_term_cache( $ids, 'product' );
$term_names = [];
foreach ( $ids as $id ) {
$terms = get_object_term_cache( $id, 'post_tag' );
foreach ( $terms as $term ) {
if ( in_array( $term->name, $term_names ) )
continue;
$term_names[] = $term->name;
$links[$term->name] = '<li><a href="'%20.%20get_term_link(%20$term%20)%20.%20'">' . $term->name . '</a></li>';
}
}
}
if ( $links ) {
ksort( $links );
$link_string = implode( "nt" , $links );
} else {
$link_string = '';
}
set_transient( $transient_name, $link_string, 7 * DAY_IN_SECONDS );
}
echo $link_string;
這將減少所有內容到 0.002s 中的 2 個查詢。隨着瞬間的到來,我們只會在發佈,更新,刪除或取消刪除帖子時刷新瞬態。我們將在這裏使用 transition_post_status 鈎
add_action( 'transition_post_status', function ()
{
global $wpdb;
$wpdb->query( "DELETE FROM $wpdb->options WHERE `option_name` LIKE ('_transient%_query_%')" );
$wpdb->query( "DELETE FROM $wpdb->options WHERE `option_name` LIKE ('_transient_timeout%_query_%')" );
});
參考文獻
注:本文內容整合自 Google/Baidu/Bing 輔助翻譯的英文資料結果。如果您對結果不滿意,可以加入我們改善翻譯效果:薇曉朵技術論壇。