Dapatkan persyaratan dengan taksonomi DAN post_type

17

Saya memiliki 2 jenis 'bookmark' dan 'cuplikan' pos kustom dan 'taksonomi' tag bersama. Saya dapat membuat daftar semua istilah dalam taksonomi dengan get_terms (), tapi saya tidak tahu cara membatasi daftar ke jenis posting. Yang saya cari pada dasarnya adalah sesuatu seperti ini:

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

Apakah ada cara untuk mencapai ini? Ide sangat dihargai !!

Oh, saya di WP 3.1.1

Gavin Hewitt
sumber

Jawaban:

11

Berikut ini cara lain untuk melakukan sesuatu yang serupa, dengan satu query 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;

}
Braydon
sumber
Iya! Ini tepat seperti yang saya inginkan.
Gavin Hewitt
print_r(get_terms_by_post_type(array('category') , array('event') ));showsWarning: Missing argument 2 for wpdb::prepare()
devo
Saya bisa saja salah, tetapi dari atas kepala saya, saya tidak berpikir bahwa pernyataan 'bergabung' akan bekerja - yaitu, mereka hanya akan bekerja jika melewati array bernilai tunggal. Ini karena fungsi persiapan akan lolos dari semua tanda kutip tunggal yang dihasilkan, dan menganggap setiap keseluruhan 'bergabung' satu string.
Codesmith
14

Jadi kebetulan saya membutuhkan sesuatu seperti itu untuk proyek yang sedang saya kerjakan. Saya hanya menulis kueri untuk memilih semua posting dari jenis khusus, lalu saya memeriksa apa saja persyaratan taksonomi saya yang sebenarnya mereka gunakan.

Lalu saya mendapatkan semua istilah yang menggunakan taksonomi itu get_terms()dan kemudian saya hanya menggunakan yang ada di kedua daftar, membungkusnya dalam suatu fungsi dan saya selesai.

Tetapi kemudian saya membutuhkan lebih dari sekedar ID: Saya membutuhkan nama-nama sehingga saya menambahkan argumen baru bernama $fieldssehingga saya bisa memberi tahu fungsi apa yang harus dikembalikan. Lalu saya pikir bahwa get_termsmenerima banyak argumen dan fungsi saya terbatas hanya istilah yang sedang digunakan oleh jenis posting jadi saya menambahkan satu ifpernyataan lagi dan begini :

Fungsi:

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

Pemakaian:

Jika Anda hanya memerlukan daftar istilah id maka:

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

Jika Anda hanya perlu daftar nama istilah maka:

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

Jika Anda hanya perlu daftar objek jangka maka:

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

Dan jika Anda perlu menggunakan argumen tambahan get_terms seperti: orderby, order, hierarchical ...

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

Nikmati!

Memperbarui:

Untuk memperbaiki jumlah istilah untuk perubahan jenis posting tertentu:

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

untuk:

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;
    }
}
Bainternet
sumber
bukankah akan lebih baik jika Anda menggunakan (array) $argsdaftar 4 $ vars? Ini akan memungkinkan Anda untuk tidak peduli dengan urutan Anda melemparkan argumen, jadi sesuatu seperti get_terms_by_post_type( $args = array( 'taxonomies', 'args', 'post_type', 'fields' => 'all') )dan kemudian memanggil mereka di dalam fungsi $args['taxonomies']. Ini akan membantu Anda menjauh dari menambahkan nilai kosong dan harus mengingat urutan argumen Anda. Saya juga menyarankan untuk menggunakan tanda kutip tunggal, bukan ganda. Saya melihat mereka naik hingga lima kali lebih cepat.
kaiser
1
@kaiser - String yang dikutip ganda harus diuraikan, di mana nilai-nilai yang dikutip selalu diperlakukan sebagai literal. Ketika Anda menggunakan variabel dalam string, masuk akal dan itu baik-baik saja untuk menggunakan tanda kutip ganda, tetapi untuk nilai string non-variabel tanda kutip tunggal lebih ideal (karena mereka tidak perlu diuraikan) dan sedikit lebih cepat (kami ' sedang berbicara tentang milidetik dalam banyak kasus).
t31os
@ t31os - Benar sekali. Aku masih lebih suka 'this is my mood: '.$valuelebih "this is my mood: $value", karena mudah dibaca. Ketika datang ke kecepatan: Tidak sedikit - saya mengukur hingga lima kali. Dan ketika Anda menggunakan tanda kutip ganda di seluruh tema Anda di mana-mana, mereka akan dengan cepat meringkas ketika Anda mendapat banyak permintaan. Ngomong-ngomong, kau sudah membuatnya jelas.
kaiser
@ t31os Keluar dari diskusi saya mengukur kembali kecepatan "vs 'dan saya salah. Perbedaannya jauh di luar apa pun yang orang akan perhatikan.
kaiser
1
+1 fungsi yang bagus! 2 kesalahan ketik: $ taksonomi digunakan dalam fungsi $ taksonomi dan $ syarat [] = $ c; harus menjadi $ terms [] = $ t;
Rob Vermeer
8

Saya menulis sebuah fungsi yang memungkinkan Anda untuk lulus post_typedalam $argsarray ke get_terms()fungsi:

HT ke @braydon untuk menulis 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);
jessica
sumber
7

Pertanyaan bagus dan jawaban yang solid.

Saya sangat menyukai pendekatan oleh @ jessica menggunakan filter terms_clauses, karena ia memperluas fungsi get_terms dengan cara yang sangat masuk akal.

Kode saya merupakan kelanjutan dari idenya, dengan beberapa sql dari @braydon untuk mengurangi duplikat. Itu juga memungkinkan untuk array 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);

Karena get_terms tidak memiliki klausa untuk GROUPY BY, saya harus menambahkannya ke akhir klausa WHERE. Perhatikan bahwa saya menetapkan prioritas filter sangat tinggi, dengan harapan ini akan selalu menjadi yang terakhir.

belati
sumber
3

Saya tidak dapat membuat argumen get_terms untuk bekerja dengan versi Gavin dari kode di atas, tetapi akhirnya melakukannya dengan mengubah

$terms2 = get_terms( $taxonomy );

untuk

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

seperti pada fungsi asli dari Bainternet.

tzeldin88
sumber
1
Memperbaikinya dalam versi saat ini
Gavin Hewitt
0

@ Netternet: Terima kasih! Saya harus mengubah fungsi sedikit karena tidak berfungsi (beberapa kesalahan ketik). Satu-satunya masalah sekarang adalah bahwa hitungan istilah tidak aktif. Hitungannya tidak mempertimbangkan jenis posting jadi saya tidak berpikir Anda bisa menggunakan get_terms () dalam hal ini.

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

EDIT: Menambahkan perbaikan. Tetapi entah bagaimana itu masih tidak berhasil untuk saya. Hitungan masih menunjukkan nilai yang salah.

Gavin Hewitt
sumber
Itu cerita yang berbeda, tetapi Anda bisa menghitung ketika menghindari duplikat dalam loop sementara.
Bainternet
Saya memperbarui jawaban saya dengan fix count term.
Bainternet
1
Tolong jangan tambahkan tindak lanjut sebagai jawaban, kecuali jika Anda secara khusus menjawab pertanyaan Anda sendiri , penambahan harus dilakukan untuk pertanyaan awal.
t31os
1
@ t31os: Ah ya, saya ingin tahu bagaimana cara menambahkan tambahan. Tidak terpikir untuk mengedit pertanyaan saya. Terima kasih!
Gavin Hewitt
Bagaimana saya bisa menyebutnya? print_r(get_terms_by_post_typea(array('event','category','',array()));yang satu ini memberikan Warning: Invalid argument supplied for foreach()garisforeach ($current_terms as $t){
devo
0

Hindari Duplikat:

//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;
        }
Kaotiko
sumber
1
Bisakah Anda menjelaskan mengapa ini menyelesaikan masalahnya? Lihat Cara Menjawab .
brasofilo