我有2种自定义帖子类型“书签”和“代码段”,以及共享的分类法“标签”。我可以使用get_terms()生成分类法中所有术语的列表,但是我不知道如何将列表限制为发布类型。我基本上正在寻找的是这样的东西:非常感谢您的想法!

哦,我正在使用WP 3.1.1

#1 楼

这是使用一个SQL查询执行类似操作的另一种方法:

static public function get_terms_by_post_type( $taxonomies, $post_types ) {

    global $wpdb;

    $query = $wpdb->prepare(
        "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 p.post_type IN('%s') AND tt.taxonomy IN('%s')
        GROUP BY t.term_id",
        join( "', '", $post_types ),
        join( "', '", $taxonomies )
    );

    $results = $wpdb->get_results( $query );

    return $results;

}


评论


是!这正是我想要的。

–加文·休伊特(Gavin Hewitt)
11年7月7日在1:33

print_r(get_terms_by_post_type(array('category'),array('event'))));显示警告:wpdb :: prepare()缺少参数2

–devo
2014年6月20日在2:20

我可能是错的,但我想不通,那些“ join”语句不会起作用-即,仅当传递单值数组时它们才起作用。这是因为prepare函数将转义所有生成的单引号,并考虑将每个整体“ join”成一个字符串。

– Codesmith
19 Mar 12 '19 at 17:19

#2 楼

因此,碰巧的是,我正在从事的项目需要这样的东西。我只写了一个查询以选择一个自定义类型的所有帖子,然后检查它们使用的分类法的实际术语是什么。只使用了两个列表中的那些,将其包装在一个函数中,然后就完成了。名为get_terms(),所以我可以告诉函数返回什么。然后我发现$fields接受许多参数,并且我的功能仅限于帖子类型使用的术语,因此我又添加了一个get_terms语句,然后您就可以了:

函数:

/* get terms limited to post type 
 @ $taxonomies - (string|array) (required) The taxonomies to retrieve terms from. 
 @ $args  -  (string|array) all Possible Arguments of get_terms http://codex.wordpress.org/Function_Reference/get_terms
 @ $post_type - (string|array) of post types to limit the terms to
 @ $fields - (string) What to return (default all) accepts ID,name,all,get_terms. 
 if you want to use get_terms arguments then $fields must be set to 'get_terms'
*/
function get_terms_by_post_type($taxonomies,$args,$post_type,$fields = 'all'){
    $args = array(
        'post_type' => (array)$post_type,
        'posts_per_page' => -1
    );
    $the_query = new WP_Query( $args );
    $terms = array();
    while ($the_query->have_posts()){
        $the_query->the_post();
        $curent_terms = wp_get_object_terms( $post->ID, $taxonomy);
        foreach ($curent_terms as $t){
          //avoid duplicates
            if (!in_array($t,$terms)){
                $terms[] = $c;
            }
        }
    }
    wp_reset_query();
    //return array of term objects
    if ($fields == "all")
        return $terms;
    //return array of term ID's
    if ($fields == "ID"){
        foreach ($terms as $t){
            $re[] = $t->term_id;
        }
        return $re;
    }
    //return array of term names
    if ($fields == "name"){
        foreach ($terms as $t){
            $re[] = $t->name;
        }
        return $re;
    }
    // get terms with get_terms arguments
    if ($fields == "get_terms"){
        $terms2 = get_terms( $taxonomies, $args );
        foreach ($terms as $t){
            if (in_array($t,$terms2)){
                $re[] = $t;
            }
        }
        return $re;
    }
}


用法:

如果只需要术语ID的列表,则:

$terms = get_terms_by_post_type('tag','','snippet','ID');


如果仅需要术语名称列表,则:

$terms = get_terms_by_post_type('tag','','snippet','name');


如果仅需要术语对象列表,则:

$terms = get_terms_by_post_type('tag','','snippet');


如果需要使用get_terms的额外参数,例如:orderby,order,hierarchy ...

$args = array('orderby' => 'count', 'order' => 'DESC',  'hide_empty' => 1);
$terms = get_terms_by_post_type('tag',$args,'snippet','get_terms');


享受吧!

更新:

将术语计数固定为特定的文章类型更改:

foreach ($current_terms as $t){
          //avoid duplicates
            if (!in_array($t,$terms)){
                $terms[] = $t;
            }
        }


至:

foreach ($current_terms as $t){
    //avoid duplicates
    if (!in_array($t,$terms)){
        $t->count = 1;
        $terms[] = $t;
    }else{
        $key = array_search($t, $terms);
        $terms[$key]->count = $terms[$key]->count + 1;
    }
}


评论


如果使用(array)$ args而不是4个$ vars的列表会更好吗?这将使您不必在意参数的顺序,因此类似get_terms_by_post_type($ args = array('taxonomies','args','post_type','fields'=>'all')))然后调用它们在$ args ['taxonomies']函数中。这将帮助您避免添加空值,而不必记住参数的顺序。我还建议使用单引号而不是双引号。我看到他们的速度快了五倍。

– kaiser
2011年4月9日在10:48



@kaiser-必须分析双引号字符串,因为单引号值始终被视为文字。当您在字符串中使用变量时,这很有意义,并且使用双引号也很好,但是对于非可变字符串值,单引号更理想(因为不需要解析),并且速度稍快(我们在大多数情况下都在谈论毫秒)。

– t31os
2011年4月9日在11:35



@ t31os-绝对正确。由于可读性,我仍然更喜欢'这是我的心情:'。$ value比“这是我的心情:$ value”。关于速度:不会太慢-我最多测量了五次。而且,当您在整个主题中的所有地方都使用双引号时,当您收到大量请求时,它们会迅速总结。无论如何,你说得很清楚。

– kaiser
2011年4月9日,12:25

@ t31os在讨论之后,我重新确定了“ vs.”的速度,但我错了。区别远没有任何人会注意到。

– kaiser
2011年7月24日在15:24

+1不错的功能! 2种错别字:$ taxonomies用于函数$ taxonomy和$ terms [] = $ c;必须是$ terms [] = $ t;

– Rob Vermeer
2012年2月5日在17:45

#3 楼

很好的问题和可靠的答案。
我真的很喜欢@jessica使用terms_clauses过滤器的方法,因为它以一种非常合理的方式扩展了get_terms函数。
我的代码是她的想法的延续,有些@braydon中的sql以减少重复。它还允许使用post_types数组:
/**
 * my_terms_clauses
 *
 * filter the terms clauses
 *
 * @param $clauses array
 * @param $taxonomy string
 * @param $args array
 * @return array
 **/
function my_terms_clauses($clauses, $taxonomy, $args)
{
  global $wpdb;

  if ($args['post_types'])
  {
    $post_types = implode("','", array_map('esc_sql', (array) $args['post_types']));

    // allow for arrays
    if ( is_array($args['post_types']) ) {
      $post_types = implode( "','", $args['post_types'] );
    }
    $clauses['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";
    $clauses['where'] .= " AND p.post_type IN ('". $post_types. "') GROUP BY t.term_id";
  }
  return $clauses;
}
add_filter('terms_clauses', 'my_terms_clauses', 99999, 3);

因为get_terms没有GROUPY BY的子句,所以我必须将其添加到WHERE子句的末尾。请注意,我已将过滤器优先级设置为很高,希望它会一直排在最后。

评论


您应该替换$ post_types = $ args ['post_types'];通过$ post_types = implode(“','”,array_map('esc_sql',(array)$ args ['post_types'])));并从IN子句中删除esc_sql(),或在$ args ['post_types']中提供多个帖子类型时,此子句在post_types之间以\'结尾

–ZalemCitizen
20-09-28在7:58

#4 楼

我编写了一个函数,允许您将post_type数组中的$args传递给get_terms()函数:

HT到@braydon以编写SQL。

 /**
 * terms_clauses
 *
 * filter the terms clauses
 *
 * @param $clauses array
 * @param $taxonomy string
 * @param $args array
 * @return array
**/
function terms_clauses($clauses, $taxonomy, $args)
{
    global $wpdb;

    if ($args['post_type'])
    {
        $clauses['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";
        $clauses['where'] .= " AND p.post_type='{$args['post_type']}'"; 
    }
    return $clauses;
}
add_filter('terms_clauses', 'terms_clauses', 10, 3);


#5 楼

我无法使get_terms参数与上面的Gavin版本的代码一起使用,但最终通过将

$terms2 = get_terms( $taxonomy );


更改为

$terms2 = get_terms( $taxonomy, $args );


,就像Bainternet最初的功能一样。

评论


修复了当前版本

–加文·休伊特(Gavin Hewitt)
2011年4月10日上午11:06

#6 楼

@Bainternet:谢谢!我不得不稍微修改一下功能,因为它不起作用(有些错字)。现在唯一的问题是术语计数已关闭。计数未考虑发布类型,因此我认为您不能在此使用get_terms()。

function get_terms_by_post_type($post_type,$taxonomy,$fields='all',$args){
    $q_args = array(
        'post_type' => (array)$post_type,
        'posts_per_page' => -1
    );
    $the_query = new WP_Query( $q_args );

    $terms = array();

    while ($the_query->have_posts()) { $the_query->the_post();

        global $post;

        $current_terms = get_the_terms( $post->ID, $taxonomy);

        foreach ($current_terms as $t){
            //avoid duplicates
            if (!in_array($t,$terms)){
                $t->count = 1;
                $terms[] = $t;
            }else{
                $key = array_search($t, $terms);
                $terms[$key]->count = $terms[$key]->count + 1;
            }
        }
    }
    wp_reset_query();

    //return array of term objects
    if ($fields == "all")
        return $terms;
    //return array of term ID's
    if ($fields == "ID"){
        foreach ($terms as $t){
            $re[] = $t->term_id;
        }
        return $re;
    }
    //return array of term names
    if ($fields == "name"){
        foreach ($terms as $t){
            $re[] = $t->name;
        }
        return $re;
    }
    // get terms with get_terms arguments
    if ($fields == "get_terms"){
        $terms2 = get_terms( $taxonomy, $args );

        foreach ($terms as $t){
            if (in_array($t,$terms2)){
                $re[] = $t;
            }
        }
        return $re;
    }
}


编辑:添加了修复)。但是以某种方式,它仍然对我不起作用。计数仍显示不正确的值。

评论


那是另一回事,但是您可以在避免while循环中出现重复时进行计数。

–互联网
2011年4月9日在13:34

我用术语计数修复程序更新了我的答案。

–互联网
2011年4月9日14:25

请不要添加后续问题作为答案,除非您专门回答自己的问题,否则应在原始问题上添加补充内容。

– t31os
2011年4月10日上午10:06

@ t31os:是的,我想知道如何添加一个附加项。没想到要编辑我的问题。谢谢!

–加文·休伊特(Gavin Hewitt)
2011年4月10日上午10:58

我怎么称呼它? print_r(get_terms_by_post_typea(array('event','category','',array()));这给出警告:为foreach()为foreach行提供了无效参数($ current_terms为$ t){

–devo
2014年6月20日在2:32

#7 楼

避免重复:

//avoid duplicates
    $mivalor=$t->term_id;
    $arr=array_filter($terms, function ($item) use ($mivalor) {return isset($item->term_id) && $item->term_id == $mivalor;});

    if (empty($arr)){
    $t->count=1;
            $terms[] = $t;
        }else{
            $key = array_search($t, $terms);
            $terms[$key]->count = $terms[$key]->count + 1;
        }


评论


您能解释为什么这可以解决问题吗?请参阅如何回答。

–brasofilo
13年2月26日在17:38