get_terms par type de message personnalisé

18

J'ai deux types de messages personnalisés, "pays" et "ville", ainsi qu'un "indicateur" de taxonomie partagée.

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 souhaite limiter la liste au type de message "pays".

Comment puis-je le faire?

Utilisation de 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?

    
posée user1443216 04.07.2012 - 18:29

5 réponses

15

J'ai bien peur que ce ne soit pas possible (encore?). Voir cette balise: enlace

De même, sur la page d'administration de taxonomie, le nombre de publications reflète tous les types de publications. ( Je suis presque sûr qu'il existe un ticket de traçabilité pour cela aussi ) enlace

Voir aussi cet article associé .

Nouvelle solution

Après avoir écrit celui ci-dessous, j'ai publié une méthode bien meilleure (en tout cas, vous pouvez en faire plus): utiliser les filtres fournis dans l'appel get_terms() . Vous pouvez créer une fonction wrapper qui utilise get_terms et ajoute (de manière conditionnelle) 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) . $args prend l'argument supplémentaire de post_types qui prend un tableau | chaîne de types de publications.

Mais je ne peux pas garantir que tout fonctionne "comme prévu" (je pense augmenter le nombre). Cela semble fonctionner en utilisant simplement la valeur par défaut $args pour 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);           
}

Utilisation

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

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

Solution de contournement d'origine

Inspiré du ticket de 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;
}

Utilisation

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

ou

 $terms = wpse57444_filter_terms_by_cpt('flag','country');
    
réponse donnée Stephen Harris 04.07.2012 - 19:00
2

La réponse ci-dessus de @ stephen-harris n'a fonctionné que partiellement pour moi. Si j'ai essayé de l'utiliser deux fois sur la page, cela n'a pas fonctionné. Aussi, l’idée d’enterrer de telles requêtes mysql me préoccupe - je pense que sa meilleure pratique consiste à utiliser les méthodes de base pour trouver une solution, afin d’éviter les conflits avec les futures mises à jour de WP. Voici ma solution, basée sur un commentaire n ° 7 sur le billet Trac 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;
}

Utilisation:

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

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

Il a été mentionné sur le fil de discussion Trac que cela n’était peut-être pas très performant, mais je travaille à une assez petite échelle et n’ai aucun problème de vitesse.

    
réponse donnée Mark Pruce 07.03.2017 - 17:52
2

Deux types de publication personnalisés, "pays" et "ville", ainsi qu'un "indicateur" de taxonomie partagée. Vous souhaitez limiter la liste au type de message "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' ) ); ?>
    
réponse donnée Alex 07.11.2017 - 13:44
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 d'article, comme ceci: $flags = wpse57444_get_terms('flags', array('post_types' => array('country','city'))); . En effet, $ wpdb- > prepare supprime la chaîne $ post_types_str à p.post_type IN('country,city') alors qu'elle devrait être p.post_type IN('country','city') . Voir ce billet: 11102 . Utilisez la solution de cette rubrique pour contourner ce problème: enlace

    
réponse donnée keesiemeijer 13.02.2013 - 15:42
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.

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

Quoi qu'il en soit, la réponse de @Mark Pruce, à mon avis, convient mieux, pour les mêmes raisons, a-t-il dit, même si vous devez faire une requête supplémentaire (et la boucle associée) pour préparer les arguments de la fonction wp_get_object_terms .

    
réponse donnée Sgaddo 03.08.2017 - 11:31

Lire d'autres questions sur les étiquettes