get_terms by custom post type

时间:2012-07-04 作者:user1443216

我有两种自定义的帖子类型“country”和“city”,还有一个共享的分类法“flag”。

如果我使用:

<?php $flags = get_terms(\'flag\', \'orderby=name&hide_empty=0\');
我得到了分类法中所有术语的列表,但我想将列表限制为post类型“country”。

我该怎么做?

使用新的解决方案

<?php 
$flags = wpse57444_get_terms(\'flags\',array(\'parent\' => 0,\'hide_empty\' => 1,\'post_types\' =>array(\'country\')));
foreach ($flags as $flag) {
    $childTerms = wpse57444_get_terms(\'flags\',array(\'parent\' => $flag->term_id,\'hide_empty\' => 1,\'post_types\' =>array(\'country\')));
    foreach ($childTerms as $childTerm) {
        echo $childTerm->name.\'<br />\';
    }
}
?>
我无法回显$childTerm->name。为什么?

5 个回复
SO网友:Stephen Harris

恐怕这在本地是不可能的查看此跟踪:http://core.trac.wordpress.org/ticket/18106

类似地,在taxonomy admin页面上,帖子数量反映了所有帖子类型。(我很确定也有一张trac罚单)http://core.trac.wordpress.org/ticket/14084

另请参见,this related post.

写了下面的一个解决方案后,我发布了一个更好的方法(尽管在某种意义上你可以做得更多),就是使用get_terms() 呼叫您可以创建一个使用get_terms 并且(有条件地)添加一个过滤器来操作SQL查询(按post类型进行限制)。

该函数的参数与get_terms($taxonomies, $args). $args 采用的附加参数post_types 它接受post类型的数组|字符串。

但我不能保证一切都“按预期”进行(我在考虑增加计数)。它似乎只使用默认的$args 对于get_terms.

function wpse57444_get_terms( $taxonomies, $args=array() ){
    //Parse $args in case its a query string.
    $args = wp_parse_args($args);

    if( !empty($args[\'post_types\']) ){
        $args[\'post_types\'] = (array) $args[\'post_types\'];
        add_filter( \'terms_clauses\',\'wpse_filter_terms_by_cpt\',10,3);

        function wpse_filter_terms_by_cpt( $pieces, $tax, $args){
            global $wpdb;

            // Don\'t use db count
            $pieces[\'fields\'] .=", COUNT(*) " ;

            //Join extra tables to restrict by post type.
            $pieces[\'join\'] .=" INNER JOIN $wpdb->term_relationships AS r ON r.term_taxonomy_id = tt.term_taxonomy_id 
                                INNER JOIN $wpdb->posts AS p ON p.ID = r.object_id ";

            // Restrict by post type and Group by term_id for COUNTing.
            $post_types_str = implode(\',\',$args[\'post_types\']);
            $pieces[\'where\'].= $wpdb->prepare(" AND p.post_type IN(%s) GROUP BY t.term_id", $post_types_str);

            remove_filter( current_filter(), __FUNCTION__ );
            return $pieces;
        }
    } // endif post_types set

    return get_terms($taxonomies, $args);           
}

使用

$args =array(
    \'hide_empty\' => 0,
    \'post_types\' =>array(\'country\',\'city\'),
);

$terms = wpse57444_get_terms(\'flag\',$args);

原创作品,灵感来自上述trac票证,(经过测试,对我很有用)

function wpse57444_filter_terms_by_cpt($taxonomy, $post_types=array() ){
    global $wpdb;

    $post_types=(array) $post_types;
    $key = \'wpse_terms\'.md5($taxonomy.serialize($post_types));
    $results = wp_cache_get($key);

    if ( false === $results ) {
       $where =" WHERE 1=1";
       if( !empty($post_types) ){
            $post_types_str = implode(\',\',$post_types);
            $where.= $wpdb->prepare(" AND p.post_type IN(%s)", $post_types_str);
       }

       $where .= $wpdb->prepare(" AND tt.taxonomy = %s",$taxonomy);

       $query = "
          SELECT t.*, COUNT(*) 
          FROM $wpdb->terms AS t 
          INNER JOIN $wpdb->term_taxonomy AS tt ON t.term_id = tt.term_id 
          INNER JOIN $wpdb->term_relationships AS r ON r.term_taxonomy_id = tt.term_taxonomy_id 
          INNER JOIN $wpdb->posts AS p ON p.ID = r.object_id 
          $where
          GROUP BY t.term_id";

       $results = $wpdb->get_results( $query );
       wp_cache_set( $key, $results );
    }        

    return $results;
}

使用

 $terms = wpse57444_filter_terms_by_cpt(\'flag\',array(\'country\',\'city\'));

 $terms = wpse57444_filter_terms_by_cpt(\'flag\',\'country\');

SO网友:Alex

两种自定义帖子类型“country”和“city”,以及一种共享分类法“flag”。您想将列表限制为帖子类型“country”。

下面是一个更简单的解决方案:

$posts_in_post_type = get_posts( array(
    \'fields\' => \'ids\',
    \'post_type\' => \'country\',
    \'posts_per_page\' => -1,
) );
$terms = wp_get_object_terms( $posts_in_post_type, \'flag\', array( \'ids\' ) ); ?>

SO网友:Mark Pruce

@斯蒂芬·哈里斯(StephenHarris)上面的回答只对我起了部分作用。如果我尝试在页面上使用它两次,它就不会起作用。此外,像这样隐藏mysql查询的想法令我担忧——我认为最好使用核心方法来实现解决方案,以避免与将来的WP更新发生冲突。以下是我的解决方案,基于comment #7 on on the Trac ticket he reference

function get_terms_by_custom_post_type( $post_type, $taxonomy ){
  $args = array( \'post_type\' => $post_type);
  $loop = new WP_Query( $args );
  $postids = array();
  // build an array of post IDs
  while ( $loop->have_posts() ) : $loop->the_post();
    array_push($postids, get_the_ID());
  endwhile;
  // get taxonomy values based on array of IDs
  $regions = wp_get_object_terms( $postids,  $taxonomy );
  return $regions;
}
用法:

$terms = get_terms_by_custom_post_type(\'country\',\'flag\');
这只适用于一种帖子类型和一种分类法,因为这正是我所需要的,但修改它以接受多个值并不难。

在Trac线程中有人提到,这可能无法很好地扩展,但我的工作规模非常小,速度没有问题。

SO网友:keesiemeijer

[编辑]这是对斯蒂芬·哈里斯出色回答的评论。

如果与这样的多个帖子类型一起使用,它不会返回任何术语$flags = wpse57444_get_terms(\'flags\', array(\'post_types\' => array(\'country\',\'city\')));. 这是因为$wpdb->prepare将$post\\u types\\u str字符串清理为p.post_type IN(\'country,city\') 虽然它应该是p.post_type IN(\'country\',\'city\'). 查看此票据:11102. 使用本主题中的解决方案解决此问题:https://stackoverflow.com/a/10634225

SO网友:Sgaddo

我还尝试使用@StephenHarris的答案,但我需要的查询很难作为单个查询编写,也很难使用过滤器。

此外,我还需要在同一页中多次使用该函数,并解决了声明wpse_filter_terms_by_cpt 包装器函数之外的函数。

无论如何,我认为@Mark Pruce的答案更合适,原因与他所说的相同,尽管它需要您再进行一次查询(和相关循环)来为wp_get_object_terms 作用

结束

相关推荐

WP_GET_OBJECT_TERMS()以获取附加到当前查询中所有帖子的所有术语的列表

如何使用wp\\u get\\u object\\u terms()获取当前查询中附加到所有帖子的所有术语的列表?例如,对于当前查询,我想从所有查询的帖子中包含的“Alfa”分类中获取一个术语数组。wp_get_object_terms($wp_query, \'alfa\'); 但似乎只返回数组中的一个项目。。。我这样做是为了构建一个数组来交叉检查导航菜单中的一个分类法和另一个分类法,目前正在使用以下代码进行交叉检查,但我认为一定有更好的方法。请帮忙!谢谢$queried_terms = ar