get_terms por tipo de postagem customizado

18

Eu tenho dois tipos de postagem personalizados 'país' e 'cidade' e uma 'bandeira' de taxonomia compartilhada.

Se eu usar:

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

Eu recebo uma lista de todos os termos da taxonomia, mas quero limitar a lista ao tipo de postagem "país".

Como posso fazer isso?

Usando a nova solução

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

Não consigo ecoar o nome $ childTerm- > Por quê?

    
por user1443216 04.07.2012 / 18:29

5 respostas

15

Eu tenho medo que isso não seja possível nativamente (ainda?). Veja este trac: enlace

Da mesma forma, na página de administração de taxonomia, a contabilização reflete todos tipos de postagem. ( eu tenho certeza que existe um ticket do trac para isso também ) enlace

Veja também este post relacionado .

Nova solução

Após ter escrito o seguinte, eu lancei uma maneira muito melhor (alteast no sentido de que você pode fazer mais) é usar os filtros fornecidos na chamada get_terms() . Você pode criar uma função de invólucro que use get_terms e (condicionalmente) adiciona um filtro para manipular a consulta SQL (para restringir por tipo de postagem).

A função usa os mesmos argumentos que get_terms($taxonomies, $args) . $args recebe o argumento adicional de post_types , que recebe uma cadeia | de tipos de postagem.

Mas não posso garantir que tudo funcione "como esperado" (estou pensando em preencher a contagem). Parece funcionar usando apenas o padrão $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);

Trabalho original

Inspirado no bilhete trac acima, (testado e funciona para mim)

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

ou

 $terms = wpse57444_filter_terms_by_cpt('flag','country');
    
por Stephen Harris 04.07.2012 / 19:00
2

@ resposta de stephen-harris acima só funcionou para mim parcialmente. Se eu tentei usá-lo duas vezes na página, não funcionou. Além disso, a ideia de enterrar consultas do mysql como essa me preocupa - acho que é uma prática melhor usar os principais métodos para obter uma solução, para evitar conflitos com futuras atualizações do WP. Aqui está a minha solução, baseada em alguns comentário # 7 sobre o bilhete do Trac que ele faz referência

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

Isso funciona apenas para um tipo de postagem e uma taxonomia, porque era disso que eu precisava, mas não seria muito difícil modificar isso para aceitar vários valores.

Houve alguma menção no tópico do Trac que isso pode não escalar bem, mas estou trabalhando em uma escala muito pequena e não tive problemas com velocidade.

    
por Mark Pruce 07.03.2017 / 17:52
2

Dois tipos de postagem personalizados 'país' e 'cidade' e uma 'bandeira' de taxonomia compartilhada. Você deseja limitar a lista ao tipo de postagem "país".

Aqui está uma solução mais simples:

$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' ) ); ?>
    
por Alex 07.11.2017 / 13:44
1

[edit] Este é um comentário sobre a excelente resposta de Stephen Harris.

Ele não retorna nenhum termo se usado com vários tipos de postagem como este $flags = wpse57444_get_terms('flags', array('post_types' => array('country','city'))); . Isso ocorre porque o $ wpdb- > prepara sanitiza a string $ post_types_str como p.post_type IN('country,city') , enquanto deveria ser p.post_type IN('country','city') . Veja este ticket: 11102 . Use a solução deste tópico para contornar isso: enlace

    
por keesiemeijer 13.02.2013 / 15:42
1

Eu também tentei usar a resposta do @Stephen Harris, mas a consulta que eu precisava era muito difícil de escrever como uma única consulta e usar os filtros.

Além disso, também precisei usar essa função várias vezes na mesma página e resolvi o problema de declarar a função wpse_filter_terms_by_cpt fora da função de wrapper.

De qualquer forma, a resposta de @Mark Pruce, na minha opinião, se encaixa melhor, pelas mesmas razões que ele disse, embora precise de mais uma consulta (e o loop relacionado) para preparar os argumentos para a função wp_get_object_terms .

    
por Sgaddo 03.08.2017 / 11:31