web-dev-qa-db-fra.com

get_terms par type de message personnalisé

J'ai deux types de messages personnalisés, "pays" et "ville", ainsi qu'un "drapeau" 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?


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?

19
user1443216

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

De même, sur la page d'administration de la taxonomie, le nombre de publications reflète les types all post. (Je suis à peu près sûr qu'il y a un ticket de train pour ça aussi)http://core.trac.wordpress.org/ticket/14084

Voir aussi, cet article lié .


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 (pour limiter le type d'article).

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 publication.

Mais je ne peux pas garantir que tout fonctionne "comme prévu" (je pense augmenter le compte). Il semble que cela fonctionne 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);           
}

Usage

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

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

Contournement original

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

Usage

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

ou

 $terms = wpse57444_filter_terms_by_cpt('flag','country');
16
Stephen Harris

Deux types de publication personnalisés, 'pays' et 'ville' et un 'drapeau' de taxonomie partagée Vous voulez 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' ) ); ?>
2
Alex

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é. 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 principales pour trouver une solution, afin d’éviter les conflits avec les futures mises à jour WP. Voici ma solution, basée sur un commentaire n ° 7 sur le ticket Trac 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 fonctionne pour un seul type de poste et une seule taxonomie, parce que 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 de Trac que cela peut ne pas bien évoluer, mais je travaille sur une assez petite échelle et n'ai pas eu de problèmes de vitesse.

2
Mark Pruce

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 en déclarant 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 s'il faut que vous fassiez une requête supplémentaire (et la boucle associée) pour préparer les arguments de la fonction wp_get_object_terms.

1
Sgaddo

[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 tels que $flags = wpse57444_get_terms('flags', array('post_types' => array('country','city')));. En effet, $ wpdb-> prepare supprime la chaîne $ post_types_str en 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: https://stackoverflow.com/a/10634225

1
keesiemeijer