获取与当前类别中的产品关联的术语

时间:2020-09-16 作者:Kristián Filo

我需要列出与当前正在查看的类别中的产品相关的所有自定义术语(品牌)。E、 g.我创建了以下品牌:

衬衫品牌A,衬衫品牌B,衬衫品牌C,牛仔裤品牌A,牛仔裤品牌B,仅衬衫品牌A, BC 将显示。

我就是这样做的:

$args = array(
    \'taxonomy\' => \'brand\',
    \'orderby\' => \'count\',
    \'order\' => \'DESC\',
    \'hide_empty\' => false
);
$brands = get_terms($args);

foreach($brands as $brand) {
    if(is_product_category()) {
        $cat_id = get_queried_object_id();
        $count_args = array(
            \'post_type\'             => \'product\',
            \'post_status\'           => \'publish\',
            \'tax_query\'             => array(
                array(
                    \'taxonomy\'      => \'product_cat\',
                    \'field\'         => \'term_id\',
                    \'terms\'         => $cat_id,
                    \'operator\'      => \'IN\'
                ),
                array(
                    \'taxonomy\'      => \'brand\',
                    \'field\'         => \'slug\',
                    \'terms\'         => $brand->slug,
                    \'operator\'      => \'IN\'
                )
            )
        );
        $count_products = new WP_Query($count_args);
        if($count_products->post_count <= 0) continue; // Skip if this query contains zero products

        // Display brand that has at least 1 product in this category
        display_brand();
    }
}
当然,这是可行的,但是对于创建的300多个品牌,有时需要0,5-1,5秒来处理这个循环,这是不必要的。AFAIK术语和产品类别之间没有直接的数据库关系(只有每个术语的帖子数),但有没有更好的方法来实现这一点,并提供更好的性能?

2 个回复
最合适的回答,由SO网友:Antti Koskinen 整理而成

要进一步微调DevelJoe的答案,您可以从全局$wp_query 而不是做额外的WP_Query.

// make the current query available from global variable
global $wp_query;
// helper variable
$brands = array();
// loop queried posts
foreach ( $wp_query->posts as $queried_post ) {
    // check if they have terms from custom taxonomy
    $current_post_brands = get_the_terms( $queried_post, \'brands\' ); // post object accepted here also, not just ID
    if ( ! is_wp_error( $current_post_brands ) && $current_post_brands ) {
        // push found brands to helper variable
        foreach ( $current_post_brands as $current_post_brand ) {
            // avoid having same brands multiple time in the helper variable
            if ( ! isset( $brands[$current_post_brand->term_id] ) ) {
                $brands[$current_post_brand->term_id] = $current_post_brand;
            }
        }
    }
}

// do something with the brand terms (WP_Term)
foreach ( $brands as $brand_id => $brand_term ) {
    // yay?
}
这可能是一种更快的方法,因为WP会自动缓存被查询帖子的条款——我不了解。这里将讨论这种缓存,例如,Explanation of update_post_(meta/term)_cache

<小时/>

EDIT 23.9.2020

让我再试一次。。。

一种方法是首先查询当前类别中的所有帖子。然后loop找到帖子来检查他们的品牌条款。最后说出一系列独特的品牌术语。您还可以选择将结果保存到瞬态中,以便查询和循环不会在每次页面加载时运行,从而节省一些服务器资源。

function helper_get_brands_in_category( int $cat_id ) {
    $transient = get_transient( \'brands_in_category_\' . $cat_id );
    if ( $transient ) {
        return $transient;
    }
    
    $args = array(
        \'post_type\' => \'product\',
        \'posts_per_page\' => 1000, // is this enough?
        \'post_status\' => \'publish\',
        \'no_found_rows\' => true,
        \'update_post_meta_cache\' => false, // not needed in this case
        \'fields\' => \'ids\', // not all post data needed here
        \'tax_query\' => array(
            array(
                \'taxonomy\' => \'product_cat\',
                \'field\' => \'term_id\',
                \'terms\' => $cat_id,
            )
        ),
    );
    $query = new WP_Query( $args );
    $brands = array();
    
    foreach ($query->posts as $post_id) {
        $post_brands = get_the_terms( $post_id, \'brands\' );
        if ( ! is_wp_error( $post_brands ) && $post_brands ) {
            foreach ( $post_brands as $post_brand ) {
                if ( ! isset( $brands[$post_brand->term_id] ) ) {
                    $brands[$post_brand->term_id] = $post_brand;
                }
            }
        }
    }

    set_transient( \'brands_in_category_\' . $cat_id, $brands, WEEK_IN_SECONDS ); // change expiration date as needed

    return $brands;
}
// Usage
$brands_in_category = helper_get_brands_in_category( get_queried_object_id() );
如果您将品牌保存到瞬态中,那么您可能还希望在添加新品牌时使瞬态无效。沿着这些路线,

function clear_brands_in_category_transients( $term_id, $tt_id ) {
    $product_cats = get_terms( array(
        \'taxonomy\' => \'product_cat\',
        \'hide_empty\' => false,
        \'fields\' => \'ids\',
    ) );
    if ( ! is_wp_error( $product_cats ) && $product_cats ) {
        foreach ($product_cats as $cat_id) {
            delete_transient( \'brands_in_category_\' . $cat_id );
        }
    }
}
add_action( \'create_brands\', \'clear_brands_in_category_transients\', 10, 2 );
我用了create_{$taxonomy} 上钩。

SO网友:DevelJoe

将您的术语定义为hierarchical 自定义分类法,作为要从中继承的相应父分类法的子分类法。。。?这样,您只需查询父税务,如果需要,只需回显相应的子分类。

**更新**

您要做的是查询给定分类法的所有术语,并使用它们来查询拥有它们的帖子,因此您要为每个品牌税创建一个WP\\u查询对象,这是不必要的昂贵。你应该反过来做;只需查询一次与品牌分类法相关的帖子(以及您可能希望用于查询的其他功能),在检索这些帖子时(在您的wp\\U查询循环中),访问循环中当前查询帖子的id,然后检索brand 与之相关的条款。像这样的事情:

$product_query_args = array(
  \'post_type\' => \'your_post_type\',
  \'tax_query\' => array(
    array(
      \'taxonomy\' => \'brand\'
    )
  )
);

$products_request = new WP_Query( $product_query_args );

if ( $products_request->have_posts() ) {
  
  while ( $products_request->have_posts() ) {

    $products_request->the_post();

    // Get ID of currently iterated post
    $id_of_iterated_product = get_the_ID();

    // Retrieve associated brand terms
    $brands = get_the_terms( $id_of_iterated_product, \'brand\' );

    // Check if there are brand terms associated to iterated post
    if ( ! empty( $brands ) ) {

      // If so, iterate through them and get the name of each
      foreach( $brands as $brand_key => $brand_object ) {

        $brand_name = $brand_object->name;

        // Do whatever you want with it

      }

    }

  }

}
这样,您实际上只进行了一次完整查询,而不是无数次,因此性能应该会更好。让我知道这个解决方案如何适合您。

向你进一步解释我为什么想到层次分类法;您写道:

"E;我需要列出与当前正在查看的类别中的产品相关的所有自定义术语(品牌)"E;

据我所知,你的网站上有一个类别过滤器,你想显示该类别的所有帖子,然后呼出每个帖子的品牌。为此,您实际上可以做的只是在所选类别的功能中查询帖子(使您的查询更容易),然后针对每个帖子检索并吐出关联的品牌(如果您定义它们是这样的,那么它们都是所查询类别的子税)。但是,您可以在给定类别的功能中查询产品,然后检索与每个检索到的帖子相关联的所有品牌标签,就像我在代码中所做的那样;也许在性能方面会更好。但从逻辑的角度来看,使用分类层次结构和单个类别查询似乎是实现这一点的最简单和最符合逻辑的方法

相关推荐

如何使用Get_the_Terms()显示多个术语?

我使用以下代码在单个帖子的元数据中显示自定义分类法,但现在我需要显示多个用逗号分隔的术语,而不是只显示一个术语。只是不知道怎么做。有没有一种方法可以使用wp_sprintf_l 结合get_the_terms() 要做到这一点?或者其他方式?以下是我当前的功能:$sources = get_the_terms( $post->ID, \'source\' ); if ( ! empty( $sources ) && ! is_wp_error( $sources ) ){&#