分類法とpost_typeで用語を取得する


17

2つのカスタム投稿タイプ「ブックマーク」と「スニペット」、および共有分類「タグ」があります。get_terms()を使用して分類法のすべての用語のリストを生成できますが、リストを投稿タイプに制限する方法がわかりません。私が基本的に探しているのは次のようなものです:

get_terms(array('taxonomy' => 'tag', 'post_type' => 'snippet'));

これを達成する方法はありますか?アイデアは大歓迎です!!

ああ、私はWP 3.1.1にいます

回答:


11

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;

}

はい!これはまさに私が望むことをします。
ギャビンヒューイット

print_r(get_terms_by_post_type(array('category') , array('event') ));ショーWarning: Missing argument 2 for wpdb::prepare()
ディーヴォ

私は間違っている可能性がありますが、私の頭上では、これらの「結合」ステートメントが機能するとは思いません。つまり、単一値の配列が渡された場合にのみ機能します。これは、準備関数が生成されたすべての単一引用符をエスケープし、各ストリング全体を「結合」することを考慮するためです。
コードスミス

14

ですから、私が取り組んでいるプロジェクトには、そのようなものが必要になりました。カスタムタイプのすべての投稿を選択するクエリを作成し、それらが使用している分類の実際の用語を確認します。

それから私はその分類法のすべての用語を使って get_terms()使用して、両方のリストにあるのみを使用し、関数でラップして完了しました。

しかし、その後、IDだけが必要になりました。名前が必要なため、新しい引数を追加して、$fields何を返すかを関数に伝えることができました。それから私はそれを考え出したget_terms、多くの引数受け入れ、私の関数は投稿タイプで使用されている単純な用語に制限されていると考えたので、もう1つのifステートメントを追加しました。

関数:

/* 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、hierarchical ...

$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) $args4つの$ varのリストの代わりに使用する方が良いと思いませんか?これは、あなたが、引数でのようなので、何かを投げるために気にしないことを可能にget_terms_by_post_type( $args = array( 'taxonomies', 'args', 'post_type', 'fields' => 'all') )し、その後で関数内でそれらを呼び出します$args['taxonomies']。これにより、空の値を追加したり、引数の順序を覚えたりする必要がなくなります。また、二重ではなく単一引用符を使用することをお勧めします。私はそれらが最大5倍速くなっているのを見ました。
カイザー

1
@kaiser-二重引用符で囲まれた文字列を解析する必要があります。単一引用符で囲まれた値は常にリテラルとして扱われます。文字列で変数を使用している場合、それは理にかなっており、二重引用符を使用することはまったく問題ありませんが、非可変文字列値の場合は、単一引用符がより理想的です(解析する必要がないため)ほとんどの場合、ミリ秒について話してください)。
t31os

@ t31os-絶対に正しい。読みやすさのため、私はまだを好ん'this is my mood: '.$valueでい"this is my mood: $value"ます。スピードに関しては、わずかではありません-最大5回測定しました。また、テーマ全体で二重引用符を使用すると、多くのリクエストを受け取ったときにすぐに要約されます。とにかくあなたはそれを明確にした。
カイザー

@ t31os議論の結果、"vs '。の速度を再測定しましたが、間違っていました。この違いは、誰もが気付く範囲外です。
カイザー

1
+1素敵な機能!2タイプミス:$ taxonomiesは関数$ taxonomyおよび$ terms [] = $ cで使用されます。$ terms [] = $ t;でなければなりません。
ロブフェルメール

8

私はあなたが合格することを可能にする機能を書いたpost_type$argsに配列をget_terms()の機能を:

SQLを記述するためにHTから@braydonへ。

 /**
 * 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);

7

すばらしい質問と確かな答え。

私は、terms_clausesフィルターを使用する@jessicaのアプローチがとても気に入っています。なぜなら、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 = $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 ('". esc_sql( $post_types ). "') GROUP BY t.term_id";
  }
  return $clauses;
}
add_filter('terms_clauses', 'my_terms_clauses', 99999, 3);

get_termsにはGROUPY BYの句がないため、WHERE句の最後に追加する必要がありました。フィルターの優先度が非常に高く設定されていることに注意してください。


3

上記のコードのGavinのバージョンで動作するようにget_terms引数を作成することはできませんでしたが、最終的には変更して

$terms2 = get_terms( $taxonomy );

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

Bainternetの元の機能にあったように。


1
現在のバージョンで修正
Gavin Hewitt

0

@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ループでの重複を避けるときにカウントできます。
Bainternet

期間カウントを修正して回答を更新しました。
Bainternet

1
回答としてフォローアップを追加しないでください。独自の質問に具体的に回答している場合を除き、元の質問に追加する必要があります。
t31os

1
@ t31os:ああ、私は追加を追加する方法を疑問に思っていました。私の質問を編集することを考えていませんでした。ありがとう!
ギャビンヒューイット

どうすればこれを呼び出すことができますか?print_r(get_terms_by_post_typea(array('event','category','',array()));これは与えWarning: Invalid argument supplied for foreach()ラインのためにforeach ($current_terms as $t){
ディーヴォ

0

重複を避ける:

//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;
        }

1
これが問題を解決する理由を説明できますか?回答方法をご覧ください。
ブラソフィロ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.