get_terms par type de publication personnalisé

19

J'ai deux types de messages personnalisés «pays» et «ville» et une taxonomie partagée «drapeau».

Si j'utilise:

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

Je reçois une liste de tous les termes de la taxonomie, mais je veux limiter la liste au type de message «pays».

Comment puis-je le faire?


Utiliser la nouvelle solution

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

Je ne peux pas faire écho à $ childTerm-> name. Pourquoi?

user1443216
la source
Pourriez-vous être un peu plus clair?
TheDeadMedic

Réponses:

16

J'ai bien peur que ce ne soit pas possible nativement (encore?). Voir ce trac: http://core.trac.wordpress.org/ticket/18106

De même, sur la page d'administration de la taxonomie, le nombre de publications reflète tous les types de publication. ( Je suis quasiment sûr qu'il y a aussi un ticket Trac pour cela ) http://core.trac.wordpress.org/ticket/14084

Voir aussi, ce poste connexe .


Nouvelle solution

Après avoir écrit celui ci-dessous, j'ai publié une bien meilleure façon (tout en ce sens que vous pouvez en faire plus) est d'utiliser les filtres fournis dans l' get_terms()appel. Vous pouvez créer une fonction wrapper qui utilise get_termset (conditionnellement) ajoute un filtre pour manipuler la requête SQL (à restreindre par type de publication).

La fonction prend les mêmes arguments que get_terms($taxonomies, $args). $argsprend l'argument supplémentaire post_typesqui prend un tableau | chaîne de types de messages.

Mais je ne peux pas garantir que tout fonctionne "comme prévu" (je pense rembourrer le décompte). Cela semble fonctionner en utilisant uniquement le par défaut $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);           
}

Usage

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

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

Contournement original

Inspiré du ticket Trac ci-dessus, (testé et cela fonctionne pour moi)

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

Usage

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

ou

 $terms = wpse57444_filter_terms_by_cpt('flag','country');
Stephen Harris
la source
Cela fonctionne, mais que puis-je faire avec mes $ args? Je veux dire ... parent = 0 & orderby = name & hide_empty = 0
user1443216
pas - ce doit être un tableau: $args = array('parent'=>0,'orderby'=>'name','hide_empty'=>0);. Je vais modifier cela pour autoriser les chaînes de requête ...
Stephen Harris
Où puis-je mettre mes $ args dans cet exemple $terms = wpse57444_filter_terms_by_cpt('flag',array('country','city'));:?
user1443216
Vous ne pouvez pas dans celui-ci, seulement dans la nouvelle solution:wpse57444_get_terms()
Stephen Harris
@ user1443216 $argsest le deuxième argument. Là, vous venez de mettrewpse57444_get_terms( 'flag', array( 'country', 'city' ) );
kaiser
2

La réponse de @ stephen-harris ci-dessus n'a fonctionné que partiellement pour moi. Si j'ai essayé de l'utiliser deux fois sur la page, cela n'a pas fonctionné. De plus, l'idée d'enterrer les requêtes mysql comme ça m'inquiète - je pense que sa meilleure pratique consiste à utiliser des méthodes de base pour parvenir à une solution, afin d'éviter les conflits avec les futures mises à jour de WP. Voici ma solution, basée sur un commentaire # 7 sur le ticket Trac qu'il référence

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

Usage:

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

Cela ne fonctionne que pour un seul type de publication et une seule taxonomie, car c'est ce dont j'avais besoin, mais il ne serait pas trop difficile de le modifier pour accepter plusieurs valeurs.

Il y avait une mention sur ce fil Trac que cela peut ne pas bien évoluer, mais je travaille sur une assez petite échelle et je n'ai eu aucun problème de vitesse.

Mark Pruce
la source
cette solution me semble plus "native" - ​​de toute façon -> vous devriez appeler "wp_reset_postdata ()" juste après la "fin" de la boucle: wordpress.stackexchange.com/questions/144343/…
Thomas Fellinger
2

Deux types de messages personnalisés «pays» et «ville» et une taxonomie partagée «drapeau». Vous souhaitez limiter la liste au type de publication «pays».

Voici une solution plus simple:

$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' ) ); ?>
Alex
la source
1

[modifier] Ceci est un commentaire sur l'excellente réponse de Stephen Harris.

Il ne renvoie aucun terme s'il est utilisé avec plusieurs types de publication comme celui-ci $flags = wpse57444_get_terms('flags', array('post_types' => array('country','city')));. En effet, $ wpdb-> prepare assainit la chaîne $ post_types_str p.post_type IN('country,city')pendant qu'elle devrait l'être p.post_type IN('country','city'). Voir ce billet: 11102 . Utilisez la solution de cette rubrique pour contourner ce problème: /programming//a/10634225

keesiemeijer
la source
1

J'ai également essayé d'utiliser la réponse de @Stephen Harris, mais la requête dont j'avais besoin était assez difficile à écrire en tant que requête unique et en utilisant les éléments de filtre.

En outre, j'ai également dû utiliser cette fonction plusieurs fois dans la même page et j'ai résolu le problème de déclaration de la wpse_filter_terms_by_cpt fonction en dehors de la fonction wrapper.

Quoi qu'il en soit, la réponse de @Mark Pruce correspond à mon avis, pour les mêmes raisons, a-t-il dit, même si vous avez besoin de faire une autre requête (et la boucle associée) pour préparer les arguments de la wp_get_object_termsfonction.

Sgaddo
la source