Sınıflandırmaya göre terimleri alın VE post_type


17

2 özel yazı türü 'yer imleri' ve 'snippet'ler' ve paylaşılan bir sınıflandırma 'etiketi' var. Taksonomide get_terms () ile tüm terimlerin bir listesini oluşturabilir, ancak listeyi yazı türüyle nasıl sınırlandıracağımı anlayamıyorum. Temelde aradığım şey şudur:

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

bunu arşivlemenin bir yolu var mı? Fikirler büyük beğeni topluyor !!

Oh, WP 3.1.1'deyim

Yanıtlar:


11

Bir SQL sorgusu ile benzer bir şey yapmanın başka bir yolu:

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;

}

Evet! Bu tam olarak istediğimi yapıyor.
Gavin Hewitt

print_r(get_terms_by_post_type(array('category') , array('event') ));gösterirWarning: Missing argument 2 for wpdb::prepare()
devo

Yanılıyor olabilirim, ama başımın tepesinde, bu 'birleştirme' ifadelerinin işe yarayacağını sanmıyorum - yani, sadece tek değerli diziler geçerse çalışırlardı. Bunun nedeni, hazırlık işlevinin oluşturulan tüm tek tırnaklardan kaçması ve her bir 'birleştirme' dizesini dikkate almasıdır.
Kod yazarı

14

Yani üzerinde çalıştığım bir proje için böyle bir şeye ihtiyacım var. Sadece özel bir türün tüm mesajlarını seçmek için bir sorgu yazdım, sonra kullandıkları taksonominin gerçek terimlerinin ne olduğunu kontrol ediyorum.

Sonra bu taksonominin tüm terimlerini kullanarak aldım get_terms()ve sonra sadece her iki listede olanları kullandım, bir fonksiyona sardım ve bitti.

Ama sonra daha sadece ID's daha ihtiyacım vardı: isimlere ihtiyacım vardı, bu $fieldsyüzden fonksiyona ne döneceğini söyleyebileceğim yeni bir argüman ekledim . Sonra get_termsbirçok argüman kabul ve fonksiyonum sadece bir yazı türü tarafından kullanılan terimler ile sınırlı olduğunu düşündüm, bu yüzden bir ifade daha ekledi ifve işte gidiyorsun:

İşlev:

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

Kullanımı:

Yalnızca terim kimlikleri listesine ihtiyacınız varsa:

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

Yalnızca bir terim listesine ihtiyacınız varsa:

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

Yalnızca terim nesneleri listesine ihtiyacınız varsa:

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

Ve get_terms gibi ekstra argümanlar kullanmanız gerekiyorsa: orderby, order, hiyerarşik ...

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

Zevk almak!

Güncelleme:

Terim sayısını belirli yazı tipi değişikliğine düzeltmek için:

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

için:

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 $ vars listesi yerine kullanırsanız daha iyi olmaz mıydı ? Bu, argümanlara attığınız düzeni umursamamanıza izin verecektir, bu yüzden bir şey gibi get_terms_by_post_type( $args = array( 'taxonomies', 'args', 'post_type', 'fields' => 'all') )ve sonra bunları fonksiyonun içinde çağırınız $args['taxonomies']. Bu, boş değerler eklemekten ve argümanlarınızın sırasını hatırlamaktan uzak durmanıza yardımcı olur. Ayrıca çift yerine tek tırnak kullanmanızı öneririm. Onları beş kata kadar daha hızlı hareket ettiklerini gördüm.
kaiser

1
@kaiser - Çift tırnaklı dizelerin ayrıştırılması gerekir; burada tek tırnaklı değerler her zaman değişmez olarak kabul edilir. Bir dizede değişkenleri kullanırken mantıklıdır ve çift tırnak kullanmak son derece iyidir, ancak değişken olmayan dize değerleri için tek tırnak daha idealdir (çünkü ayrıştırılmaları gerekmeyecektir) ve biraz daha hızlıdır ( çoğu durumda milisaniyeden bahsediyoruz).
t31os

@ t31os - Kesinlikle doğru. Hala tercih 'this is my mood: '.$valueüzerinde "this is my mood: $value"çünkü okunabilirliği. Hız söz konusu olduğunda: Hafif değil - beş kata kadar ölçüm yaptım. Ve her yerde tüm temanızda çift tırnak kullandığınızda, çok fazla istek aldığınızda hızlı bir şekilde özetlenirler. Her neyse iyi, bunu açıkladın.
kaiser

@ t31os Tartışma dışında "vs hızını tekrar ölçtüm 've yanılmışım. Fark, herkesin fark edeceği her şeyin dışında.
kaiser

1
+1 güzel işlev! 2 yazım hatası: $ taksonomisi ve $ terimleri [$ = $ c; $ terimleri olmalıdır [] = $ t;
Rob Vermeer

8

Geçmene sağlayan bir fonksiyon yazdım post_typeiçinde $argsdizinin get_terms()fonksiyonu:

HT yazmak için @braydon SQL yazmak için.

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

Harika soru ve sağlam cevaplar.

Get_terms işlevini çok makul bir şekilde genişlettiği için terms_clauses filtresini kullanarak @jessica'nın yaklaşımını gerçekten çok sevdim.

Kodum, yinelenenleri azaltmak için @braydon'dan bazı sql ile fikrinin devamıdır. Bir dizi post_types dizisine de izin verir:

/**
 * 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 için bir madde içermediğinden, WHERE deyiminin sonuna eklemek zorunda kaldım. Filtre önceliğinin çok yüksek ayarlandığına dikkat edin, umarım her zaman devam eder.


3

Yukarıdaki kodun Gavin sürümüyle çalışmak için get_terms argümanlarını yapamadım, ancak sonunda değiştirerek yaptım

$terms2 = get_terms( $taxonomy );

için

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

Bainternet'in orijinal işlevinde olduğu gibi.


1
Geçerli sürümde düzeltildi
Gavin Hewitt

0

@Bainternet: Teşekkürler! (Bazı yazım hataları) çalışmadığı için işlevi biraz değiştirmek zorunda kaldı. Şimdi tek sorun sayım terimi kapalı olmasıdır. Bu sayı, get_terms () kullanabileceğinizi sanmıyorum bu yüzden yazı türü dikkate almıyor.

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

DÜZENLE: Düzeltmeleri eklendi. Ama bir şekilde hala benim için çalışmıyor. Sayı yine de yanlış değeri gösteriyor.


Bu farklı bir hikaye, ancak while döngüsünde yinelemelerden kaçınırken sayabilirsiniz.
Bainternet

Cevabımı bir terim sayım düzeltmesi ile güncelledim.
Bainternet

1
Lütfen sorularınızı cevap olarak eklemeyin, özellikle kendi sorunuzu cevaplamadığınız sürece , orijinal soruya eklemeler yapılmalıdır.
t31os

1
@ t31os: Ah evet, nasıl ekleyeceğini merak ediyordum. Sorumu düzenlemeyi düşünmedim. Teşekkürler!
Gavin Hewitt

Bunu nasıl arayabilirim? print_r(get_terms_by_post_typea(array('event','category','',array()));Bu bir Warning: Invalid argument supplied for foreach()satır için verirforeach ($current_terms as $t){
devo

0

Kopyalardan Kaçının:

//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
Bunun sorunu neden çözdüğünü açıklayabilir misiniz? Bkz. Nasıl Cevap Verilir .
brasofilo
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.