get_terms per tipo di post personalizzato


19

Ho due tipi di post personalizzati "country" e "city" e una "flag" di tassonomia condivisa.

Se uso:

<?php $flags = get_terms('flag', 'orderby=name&hide_empty=0');

Ricevo un elenco di tutti i termini nella tassonomia, ma voglio limitare l'elenco al tipo di post "Paese".

Come posso farlo?


Utilizzando la nuova soluzione

<?php 
$flags = wpse57444_get_terms('flags',array('parent' => 0,'hide_empty' => 1,'post_types' =>array('country')));
foreach ($flags as $flag) {
    $childTerms = wpse57444_get_terms('flags',array('parent' => $flag->term_id,'hide_empty' => 1,'post_types' =>array('country')));
    foreach ($childTerms as $childTerm) {
        echo $childTerm->name.'<br />';
    }
}
?>

Non riesco a ripetere $ childTerm-> name. Perché?


Potresti essere un po 'più chiaro?
TheDeadMedic

Risposte:


16

Temo che questo non sia possibile in modo nativo (ancora?). Vedi questo trac: http://core.trac.wordpress.org/ticket/18106

Allo stesso modo nella pagina di amministrazione della tassonomia il conteggio dei post riflette tutti i tipi di post. ( Sono abbastanza sicuro che ci sia anche un biglietto trac per quello ) http://core.trac.wordpress.org/ticket/14084

Vedi anche questo post correlato .


Nuova soluzione

Dopo aver scritto quello qui sotto, ho rilasciato un modo molto migliore (alteast nel senso che puoi fare di più) è usare i filtri forniti nella get_terms()chiamata. È possibile creare una funzione wrapper che utilizza get_termse (in modo condizionale) un filtro per manipolare la query SQL (per limitare il tipo di posta).

La funzione accetta gli stessi argomenti di get_terms($taxonomies, $args). $argsaccetta l'argomento aggiuntivo di post_typescui accetta una matrice | tipi di post.

Ma non posso garantire che tutto funzioni "come previsto" (sto pensando di riempire il conteggio). Sembra funzionare usando solo il predefinito $argsfor get_terms.

function wpse57444_get_terms( $taxonomies, $args=array() ){
    //Parse $args in case its a query string.
    $args = wp_parse_args($args);

    if( !empty($args['post_types']) ){
        $args['post_types'] = (array) $args['post_types'];
        add_filter( 'terms_clauses','wpse_filter_terms_by_cpt',10,3);

        function wpse_filter_terms_by_cpt( $pieces, $tax, $args){
            global $wpdb;

            // Don't use db count
            $pieces['fields'] .=", COUNT(*) " ;

            //Join extra tables to restrict by post type.
            $pieces['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 ";

            // Restrict by post type and Group by term_id for COUNTing.
            $post_types_str = implode(',',$args['post_types']);
            $pieces['where'].= $wpdb->prepare(" AND p.post_type IN(%s) GROUP BY t.term_id", $post_types_str);

            remove_filter( current_filter(), __FUNCTION__ );
            return $pieces;
        }
    } // endif post_types set

    return get_terms($taxonomies, $args);           
}

uso

$args =array(
    'hide_empty' => 0,
    'post_types' =>array('country','city'),
);

$terms = wpse57444_get_terms('flag',$args);

Soluzione originale

Ispirato al precedente biglietto trac, (testato e funziona per me)

function wpse57444_filter_terms_by_cpt($taxonomy, $post_types=array() ){
    global $wpdb;

    $post_types=(array) $post_types;
    $key = 'wpse_terms'.md5($taxonomy.serialize($post_types));
    $results = wp_cache_get($key);

    if ( false === $results ) {
       $where =" WHERE 1=1";
       if( !empty($post_types) ){
            $post_types_str = implode(',',$post_types);
            $where.= $wpdb->prepare(" AND p.post_type IN(%s)", $post_types_str);
       }

       $where .= $wpdb->prepare(" AND tt.taxonomy = %s",$taxonomy);

       $query = "
          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
          GROUP BY t.term_id";

       $results = $wpdb->get_results( $query );
       wp_cache_set( $key, $results );
    }        

    return $results;
}

uso

 $terms = wpse57444_filter_terms_by_cpt('flag',array('country','city'));

o

 $terms = wpse57444_filter_terms_by_cpt('flag','country');

Funziona, ma cosa posso fare con i miei $ args? Voglio dire ... parent = 0 & orderby = name & hide_empty = 0
user1443216

no - questo deve essere un array: $args = array('parent'=>0,'orderby'=>'name','hide_empty'=>0);. Lo modificherò per consentire le stringhe di query ...
Stephen Harris,

Dove posso mettere i miei $ args in questo esempio: $terms = wpse57444_filter_terms_by_cpt('flag',array('country','city'));?
user1443216

Non puoi in quello, solo nella nuova soluzione:wpse57444_get_terms()
Stephen Harris,

@ user1443216 $argsè il secondo argomento. Ci hai appena messowpse57444_get_terms( 'flag', array( 'country', 'city' ) );
kaiser il

2

La risposta di @ stephen-harris sopra ha funzionato solo parzialmente per me. Se ho provato a usarlo due volte sulla pagina, non ha funzionato. Inoltre, l'idea di seppellire query mysql come questa mi preoccupa: penso che sia la migliore pratica usare metodi di base per ottenere una soluzione, per evitare conflitti con futuri aggiornamenti del WP. Ecco la mia soluzione, basata su alcuni commenti n. 7 sul biglietto Trac a cui fa riferimento

function get_terms_by_custom_post_type( $post_type, $taxonomy ){
  $args = array( 'post_type' => $post_type);
  $loop = new WP_Query( $args );
  $postids = array();
  // build an array of post IDs
  while ( $loop->have_posts() ) : $loop->the_post();
    array_push($postids, get_the_ID());
  endwhile;
  // get taxonomy values based on array of IDs
  $regions = wp_get_object_terms( $postids,  $taxonomy );
  return $regions;
}

Uso:

$terms = get_terms_by_custom_post_type('country','flag');

Funziona solo per un tipo di post e una tassonomia, perché è quello di cui avevo bisogno, ma non sarebbe troppo difficile modificarlo per accettare più valori.

C'è stato qualche cenno su quel thread Trac che questo potrebbe non adattarsi bene, ma sto lavorando su una scala piuttosto piccola e non ho avuto problemi con la velocità.


questa soluzione sembra più "nativa" per me - comunque -> dovresti chiamare "wp_reset_postdata ()" subito dopo la "fine" del ciclo: wordpress.stackexchange.com/questions/144343/…
Thomas Fellinger

2

Due tipi di post personalizzati "paese" e "città" e una "bandiera" di tassonomia condivisa. Desideri limitare l'elenco al tipo di post "Paese".

Ecco una soluzione più semplice:

$posts_in_post_type = get_posts( array(
    'fields' => 'ids',
    'post_type' => 'country',
    'posts_per_page' => -1,
) );
$terms = wp_get_object_terms( $posts_in_post_type, 'flag', array( 'ids' ) ); ?>

1

[modifica] Questo è un commento sull'ottima risposta di Stephen Harris.

Non restituisce alcun termine se utilizzato con più tipi di post come questo $flags = wpse57444_get_terms('flags', array('post_types' => array('country','city')));. Questo perché $ wpdb-> prepar sanifica la stringa $ post_types_str p.post_type IN('country,city')mentre dovrebbe essere p.post_type IN('country','city'). Vedi questo biglietto: 11102 . Utilizzare la soluzione di questo argomento per aggirare il problema: /programming//a/10634225


1

Ho anche provato a usare la risposta di @Stephen Harris, ma la query di cui avevo bisogno era piuttosto difficile da scrivere come una singola query e usando i pezzi del filtro.

Inoltre, avevo anche bisogno di usare quella funzione più volte nella stessa pagina e ho risolto il problema dichiarando il wpse_filter_terms_by_cpt funzione al di fuori della funzione wrapper.

Comunque la risposta di @Mark Pruce secondo me si adatta meglio, per gli stessi motivi che ha detto, anche se ha bisogno che tu faccia un'altra query (e il relativo ciclo) per preparare gli argomenti per la wp_get_object_termsfunzione.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.