问题描述
我需要交叉参考两个分类,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 辅助翻译的英文资料结果。如果您对结果不满意,可以加入我们改善翻译效果:薇晓朵技术论坛。