get_terms por tipo de publicación personalizada

18

Tengo dos tipos de publicación personalizados 'país' y 'ciudad' y una 'bandera' de taxonomía compartida.

Si uso:

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

Obtengo una lista de todos los términos en la taxonomía, pero quiero limitar la lista al tipo de publicación 'país'.

¿Cómo puedo hacerlo?

Usando la nueva solución

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

No puedo repetir el nombre de $ childTerm- > ¿Por qué?

    
pregunta user1443216 04.07.2012 - 18:29

5 respuestas

15

Me temo que esto no es posible de forma nativa (¿todavía?). Vea este trac: enlace

Del mismo modo, en la página de administración de taxonomía, el recuento de publicaciones refleja todos tipos de publicaciones. ( Estoy bastante seguro de que hay un ticket de trac para eso también ) enlace

Vea también, esta publicación relacionada .

Nueva solución

Habiendo escrito el siguiente, he lanzado una forma mucho mejor (además, en el sentido de que puedes hacer más) es usar los filtros proporcionados en la llamada get_terms() . Puede crear una función de envoltorio que utilice get_terms y (condicionalmente) agrega un filtro para manipular la consulta SQL (para restringir por tipo de publicación).

La función toma los mismos argumentos que get_terms($taxonomies, $args) . $args toma el argumento adicional de post_types que toma una cadena | de tipos de publicación.

Pero no puedo garantizar que todo funcione "como se esperaba" (estoy pensando en completar el conteo). Parece que funciona usando solo el valor predeterminado $args para 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);

Alternativa original

Inspirado en el ticket de trac anterior, (probado y funciona para mí)

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');
    
respondido por el Stephen Harris 04.07.2012 - 19:00
2
La respuesta de

@ stephen-harris de arriba solo funcionó parcialmente para mí. Si intenté usarlo dos veces en la página, no funcionó. Además, la idea de enterrar consultas de mysql así me preocupa. Creo que es mejor utilizar métodos básicos para lograr una solución, para evitar conflictos con futuras actualizaciones de WP. Aquí está mi solución, basada en algunos comentario # 7 en el boleto de Trac al que hace referencia

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');

Esto funciona solo para un tipo de publicación y una taxonomía, porque eso es lo que necesitaba, pero no sería demasiado difícil modificarlo para aceptar múltiples valores.

En el subproceso de Trac se mencionó que esto podría no escalar bien, pero estoy trabajando en una escala bastante pequeña y no he tenido problemas con la velocidad.

    
respondido por el Mark Pruce 07.03.2017 - 17:52
2

Dos tipos de publicación personalizados "país" y "ciudad" y una taxonomía compartida "bandera". Desea limitar la lista al tipo de publicación 'país'.

Aquí hay una solución más 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' ) ); ?>
    
respondido por el Alex 07.11.2017 - 13:44
1

[editar] Este es un comentario sobre la excelente respuesta de Stephen Harris.

No devuelve ningún término si se usa con varios tipos de publicaciones como esta $flags = wpse57444_get_terms('flags', array('post_types' => array('country','city'))); . Esto se debe a que $ wpdb- > prepare desinfecta la cadena $ post_types_str a p.post_type IN('country,city') , mientras que debería ser p.post_type IN('country','city') . Consulte este ticket: 11102 . Utilice la solución de este tema para solucionar esto: enlace

    
respondido por el keesiemeijer 13.02.2013 - 15:42
1

También intenté usar la respuesta de @Stephen Harris, pero la consulta que necesitaba era bastante difícil de escribir como una sola consulta y usando las piezas de filtro.

Además, también necesitaba usar esa función varias veces en la misma página y resolví el problema al declarar la función wpse_filter_terms_by_cpt fuera de la función de envoltura.

De todos modos, en mi opinión, la respuesta de @Mark Pruce encaja mejor, por las mismas razones que dijo, aunque necesita que hagas una consulta más (y el bucle relacionado) para preparar los argumentos para la función wp_get_object_terms .

    
respondido por el Sgaddo 03.08.2017 - 11:31

Lea otras preguntas en las etiquetas