Este posibil să obții get_terms după taxonomie ȘI post_type?

9 apr. 2011, 03:38:03
Vizualizări: 27.8K
Voturi: 18

Am 2 tipuri de postări personalizate 'bookmarks' și 'snippets' și o taxonomie comună 'tag'. Pot genera o listă cu toți termenii din taxonomie folosind get_terms(), dar nu reușesc să găsesc o modalitate de a limita lista la tipul de postare. În principiu, caut ceva de genul acesta:

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

Există vreo modalitate de a realiza acest lucru? Orice idei sunt apreciate!!

Ah, folosesc WP 3.1.1

0
Toate răspunsurile la întrebare 7
5
14

S-a întâmplat să am nevoie de ceva similar pentru un proiect la care lucrez. Am scris pur și simplu o interogare pentru a selecta toate articolele de un tip personalizat, apoi am verificat ce termeni ai taxonomiei mele sunt folosiți efectiv.

Apoi am obținut toți termenii acelei taxonomii folosind get_terms() și am utilizat doar cei care se aflau în ambele liste, am încapsulat totul într-o funcție și am terminat.

Dar apoi am avut nevoie de mai mult decât doar ID-uri: aveam nevoie de nume, așa că am adăugat un nou argument numit $fields pentru a putea specifica ce să returneze funcția. Apoi mi-am dat seama că get_terms acceptă multe argumente, iar funcția mea era limitată la termenii folosiți de un tip de postare, așa că am adăugat încă o condiție if și iată rezultatul:

Funcția:

/* obține termenii limitați la un tip de postare 
 @ $taxonomies - (string|array) (obligatoriu) Taxonomiile din care se extrag termenii. 
 @ $args  -  (string|array) toate argumentele posibile ale get_terms http://codex.wordpress.org/Function_Reference/get_terms
 @ $post_type - (string|array) tipuri de postare pentru a limita termenii
 @ $fields - (string) Ce să returneze (implicit 'all') acceptă ID, name, all, get_terms. 
 dacă doriți să utilizați argumentele get_terms, atunci $fields trebuie setat la '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){
          //evită duplicatele
            if (!in_array($t,$terms)){
                $terms[] = $c;
            }
        }
    }
    wp_reset_query();
    //returnează array de obiecte termen
    if ($fields == "all")
        return $terms;
    //returnează array de ID-uri de termeni
    if ($fields == "ID"){
        foreach ($terms as $t){
            $re[] = $t->term_id;
        }
        return $re;
    }
    //returnează array de nume de termeni
    if ($fields == "name"){
        foreach ($terms as $t){
            $re[] = $t->name;
        }
        return $re;
    }
    // obține termeni cu argumentele get_terms
    if ($fields == "get_terms"){
        $terms2 = get_terms( $taxonomies, $args );
        foreach ($terms as $t){
            if (in_array($t,$terms2)){
                $re[] = $t;
            }
        }
        return $re;
    }
}

Utilizare:

Dacă aveți nevoie doar de o listă de ID-uri de termeni:

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

Dacă aveți nevoie doar de o listă de nume de termeni:

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

Dacă aveți nevoie doar de o listă de obiecte termen:

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

Și dacă trebuie să utilizați argumente suplimentare ale get_terms precum: orderby, order, hierarchical ...

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

Bucurați-vă!

Actualizare:

Pentru a corecta numărul de termeni pentru un tip specific de postare, schimbați:

foreach ($current_terms as $t){
          //evită duplicatele
            if (!in_array($t,$terms)){
                $terms[] = $t;
            }
        }

cu:

foreach ($current_terms as $t){
    //evită duplicatele
    if (!in_array($t,$terms)){
        $t->count = 1;
        $terms[] = $t;
    }else{
        $key = array_search($t, $terms);
        $terms[$key]->count = $terms[$key]->count + 1;
    }
}
9 apr. 2011 04:21:43
Comentarii

nu ar fi mai bine să folosești (array) $args în loc de o listă de 4 $vars? Asta ar permite să nu te mai gândești la ordinea în care introduci argumentele, deci ceva de genul get_terms_by_post_type( $args = array( 'taxonomies', 'args', 'post_type', 'fields' => 'all') ) și apoi să le apelezi în interiorul funcției cu $args['taxonomies']. Asta te-ar ajuta să eviți adăugarea de valori goale și să nu fii nevoit să-ți amintești ordinea argumentelor. Aș sugera și să folosești ghilimele simple în loc de cele duble. Am văzut că pot fi de până la cinci ori mai rapide.

kaiser kaiser
9 apr. 2011 13:48:50

@kaiser - Șirurile de caractere cu ghilimele duble trebuie parsate, în timp ce valorile cu ghilimele simple sunt întotdeauna tratate ca literale. Când folosești variabile într-un șir de caractere are sens și este perfect în regulă să folosești ghilimele duble, dar pentru valori de șir fără variabile, ghilimele simple sunt mai ideale (pentru că nu vor trebui parsite) și puțin mai rapide (vorbim de milisecunde în majoritatea cazurilor).

t31os t31os
9 apr. 2011 14:35:20

@t31os - Absolut corect. Eu tot prefer 'aceasta este starea mea: '.$value în loc de "aceasta este starea mea: $value", din cauza lizibilității. Când vine vorba de viteză: Nu este puțin - am măsurat până la cinci ori mai rapid. Și când folosești ghilimele duble în întreaga temă peste tot, ele se adună rapid când ai multe solicitări. Oricum, bine că ai clarificat asta.

kaiser kaiser
9 apr. 2011 15:25:26

@t31os După o discuție, am măsurat din nou viteza dintre " și ' și am greșit. Diferența este mult dincolo de orice ce ar putea observa cineva.

kaiser kaiser
24 iul. 2011 18:24:17

+1 funcție frumoasă! 2 greșeli de scriere: $taxonomies este folosit în funcție ca $taxonomy și $terms[] = $c; trebuie să fie $terms[] = $t;

Rob Vermeer Rob Vermeer
5 feb. 2012 19:45:27
3
13

Excelentă întrebare și răspunsuri solide.

Mi-a plăcut foarte mult abordarea lui @jessica folosind filtrul terms_clauses, deoarece extinde funcția get_terms într-un mod foarte rezonabil.

Codul meu este o continuare a ideii ei, cu o parte din sql de la @braydon pentru a reduce duplicatele. De asemenea, permite utilizarea unui array de post_types:

/**
 * my_terms_clauses
 *
 * filtrează clauzele termenilor
 *
 * @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']));

    // permite array-uri
    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);

Deoarece get_terms nu are o clauză pentru GROUP BY, a trebuit să o adaug la sfârșitul clauzei WHERE. Observați că am setat prioritatea filtrului foarte mare, în speranța că va rula întotdeauna ultimul.

4 apr. 2015 06:09:25
Comentarii

Ar trebui să înlocuiești $post_types = $args['post_types']; cu $post_types = implode("','", array_map('esc_sql', (array) $args['post_types'])); și să elimini esc_sql() din clauza IN altfel această clauză va avea \' între tipurile de postări atunci când furnizezi mai multe tipuri de postări în $args['post_types']

ZalemCitizen ZalemCitizen
28 sept. 2020 10:58:33

Singura soluție care mi-a permis să folosesc get_terms și a funcționat pentru mine în 2022

LBF LBF
28 oct. 2022 00:03:13

Argumentul hide_empty va fi în continuare aplicat tuturor postărilor, nu doar tipului de postare selectat?

Adrian B Adrian B
4 oct. 2023 00:43:15
3
12

Iată o altă metodă de a face ceva similar, folosind o singură interogare 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;

}
26 iul. 2011 11:40:10
Comentarii

Da! Asta face exact ce vreau eu.

Gavin Hewitt Gavin Hewitt
7 nov. 2011 03:33:30

print_r(get_terms_by_post_type(array('category') , array('event') )); afișează Warning: Missing argument 2 for wpdb::prepare()

Anshad Vattapoyil Anshad Vattapoyil
20 iun. 2014 05:20:40

S-ar putea să greșesc, dar din capul locului, nu cred că acele instrucțiuni 'join' vor funcționa - adică, ar funcționa doar dacă sunt transmise array-uri cu o singură valoare. Acest lucru se întâmplă pentru că funcția prepare ar escapa toate ghilimelele simple generate și ar considera fiecare instrucțiune 'join' întreagă ca un singur șir de caractere.

Codesmith Codesmith
12 mar. 2019 19:19:43
0
10

Am scris o funcție care permite să transmiți post_type în array-ul $args către funcția get_terms():

HT lui @braydon pentru scrierea SQL-ului.

 /**
 * terms_clauses
 *
 * filtrează clauzele de termeni
 *
 * @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);
8 iun. 2012 08:14:39
1

Nu am reușit să fac argumentele get_terms să funcționeze cu versiunea lui Gavin a codului de mai sus, dar în final am reușit prin schimbarea

$terms2 = get_terms( $taxonomy );

în

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

așa cum era în funcția originală de la Bainternet.

10 apr. 2011 05:16:13
Comentarii

Am rezolvat în versiunea curentă

Gavin Hewitt Gavin Hewitt
10 apr. 2011 14:06:01
5

@Bainternet: Mulțumesc! A trebuit să modific ușor funcția pentru că nu funcționa (avea câteva greșeli de tipar). Singura problemă acum este că numărarea termenilor nu este corectă. Numărarea nu ține cont de tipul de postare, așa că nu cred că poți folosi get_terms() în acest caz.

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){
            //evită duplicatele
            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();

    //returnează array de obiecte termeni
    if ($fields == "all")
        return $terms;
    //returnează array de ID-uri termeni
    if ($fields == "ID"){
        foreach ($terms as $t){
            $re[] = $t->term_id;
        }
        return $re;
    }
    //returnează array de nume termeni
    if ($fields == "name"){
        foreach ($terms as $t){
            $re[] = $t->name;
        }
        return $re;
    }
    // obține termeni cu argumentele get_terms
    if ($fields == "get_terms"){
        $terms2 = get_terms( $taxonomy, $args );

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

EDIT: Am adăugat corecțiile. Dar cumva tot nu funcționează pentru mine. Numărarea încă afișează valoarea incorectă.

9 apr. 2011 14:45:03
Comentarii

Asta e altceva, dar poți număra când eviți duplicatele în bucla while.

Bainternet Bainternet
9 apr. 2011 16:34:55

Am actualizat răspunsul meu cu o corecție pentru numărarea termenilor.

Bainternet Bainternet
9 apr. 2011 17:25:26

Te rog să nu adaugi întrebări suplimentare ca răspunsuri, decât dacă răspunzi în mod specific la propria întrebare. Adăugările ar trebui făcute în întrebarea originală.

t31os t31os
10 apr. 2011 13:06:44

@t31os: Ah da, mă întrebam cum să adaug un adaos. Nu m-am gândit să editez întrebarea mea. Mulțumesc!

Gavin Hewitt Gavin Hewitt
10 apr. 2011 13:58:36

Cum pot apela această funcție? print_r(get_terms_by_post_typea(array('event','category','',array())); aceasta returnează Warning: Invalid argument supplied for foreach() pentru linia foreach ($current_terms as $t){

Anshad Vattapoyil Anshad Vattapoyil
20 iun. 2014 05:32:21
1

Evită duplicatele:

//evită duplicatele
    $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;
        }
26 feb. 2013 19:10:19
Comentarii

Poți explica de ce această soluție rezolvă problema? Vezi [răspuns].

brasofilo brasofilo
26 feb. 2013 19:38:46