get_terms por tipo de publicación personalizada

19

Tengo dos tipos de publicaciones personalizadas 'país' y 'ciudad' y una taxonomía compartida 'bandera'.

Si yo 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 hacer eco de $ childTerm-> name. ¿Por qué?

usuario1443216
fuente
¿Podrías ser un poco más claro?
TheDeadMedic

Respuestas:

16

Me temo que esto no es posible de forma nativa (¿todavía?). Vea este seguimiento: http://core.trac.wordpress.org/ticket/18106

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

Vea también esta publicación relacionada .


Nueva solución

Habiendo escrito el siguiente, he lanzado una forma mucho mejor (en el sentido de que puedes hacer más) es usar los filtros provistos en la get_terms()llamada. Puede crear una función de contenedor que use get_termsy (condicionalmente) agregue 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). $argstoma el argumento adicional del post_typescual toma una matriz | cadena de tipos de publicación.

Pero no puedo garantizar que todo funcione 'como se esperaba' (estoy pensando en completar el recuento). Parece funcionar usando solo el predeterminado $argspara 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);

Solución original

Inspirado en el boleto 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');
Stephen Harris
fuente
Funciona, pero ¿qué puedo hacer con mis $ args? Quiero decir ... parent = 0 & orderby = name & hide_empty = 0
user1443216
no - esto tiene que ser un array: $args = array('parent'=>0,'orderby'=>'name','hide_empty'=>0);. Editaré esto para permitir cadenas de consulta ...
Stephen Harris
¿Dónde puedo poner mis $ args en este ejemplo $terms = wpse57444_filter_terms_by_cpt('flag',array('country','city'));:?
user1443216
No puedes en esa, solo en la nueva solución:wpse57444_get_terms()
Stephen Harris
@ user1443216 $argses el segundo argumento. Ahí acabas de ponerwpse57444_get_terms( 'flag', array( 'country', 'city' ) );
kaiser
2

La respuesta anterior de @ stephen-harris solo funcionó para mí parcialmente. Si intenté usarlo dos veces en la página, no funcionó. Además, la idea de enterrar consultas mysql como esa me preocupa: creo que es una mejor práctica usar métodos básicos para lograr una solución, para evitar conflictos con futuras actualizaciones de WP. Aquí está mi solución, basada en algún comentario # 7 sobre 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 modificar esto para aceptar múltiples valores.

Hubo alguna mención en ese hilo de Trac de que esto puede no escalar bien, pero estoy trabajando en una escala bastante pequeña y no he tenido problemas con la velocidad.

Mark Pruce
fuente
esta solución parece más "nativa" para mí - de todos modos -> debe llamar a "wp_reset_postdata ()" justo después del "fin" del bucle: wordpress.stackexchange.com/questions/144343/…
Thomas Fellinger
2

Dos tipos de publicaciones personalizadas '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' ) ); ?>
Alex
fuente
1

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

No devuelve ningún término si se usa con múltiples 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 p.post_type IN('country,city')mientras debería estar p.post_type IN('country','city'). Ver este boleto: 11102 . Use la solución de este tema para solucionar esto: /programming//a/10634225

keesiemeijer
fuente
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 declarando el wpse_filter_terms_by_cpt función fuera de la función de contenedor.

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

Sgaddo
fuente