get_terms por tipo de postagem personalizada

19

Eu tenho dois tipos de postagem personalizados 'country' e 'city' e uma taxonomia compartilhada 'flag'.

Se eu usar:

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

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

Como eu 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 repetir o nome $ childTerm->. Por quê?

user1443216
fonte
Você poderia ser um pouco mais claro?
TheDeadMedic

Respostas:

16

Receio que isso não seja possível nativamente (ainda?). Veja este trac: http://core.trac.wordpress.org/ticket/18106

Da mesma forma, na página de administração de taxonomia, a contagem de postagens reflete todos os tipos de postagens. ( Tenho certeza de que também existe um tíquete trac ) http://core.trac.wordpress.org/ticket/14084

Veja também este post relacionado .


Nova solução

Depois de escrever o texto abaixo, lancei uma maneira muito melhor (pelo menos no sentido de que você pode fazer mais) é usar os filtros fornecidos na get_terms()chamada. Você pode criar uma função de wrapper que use get_termse (condicionalmente) adicione 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). $argsutiliza o argumento adicional, post_typesque utiliza uma matriz | de tipos de postagem.

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

Solução alternativa original

Inspirado no tíquete 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');
Stephen Harris
fonte
Funciona, mas o que posso fazer com meus $ args? Eu quero dizer ... parent = 0 & orderby = name & hide_empty = 0
user1443216 4/12/12
Não - isso tem que ser uma matriz: $args = array('parent'=>0,'orderby'=>'name','hide_empty'=>0);. Vou editar isso para permitir seqüências de consulta ...
Stephen Harris
Onde posso colocar meus $ args neste exemplo $terms = wpse57444_filter_terms_by_cpt('flag',array('country','city'));:?
user1443216
Você não pode nessa, apenas na nova solução:wpse57444_get_terms()
Stephen Harris
@ user1443216 $argsé o segundo argumento. Lá você acabou de colocarwpse57444_get_terms( 'flag', array( 'country', 'city' ) );
kaiser
2

A resposta de @ stephen-harris acima funcionou apenas para mim parcialmente. Se eu tentasse usá-lo duas vezes na página, não funcionaria. Além disso, a idéia de enterrar consultas mysql como essa me preocupa - acho que é melhor prática usar métodos principais para obter uma solução, evitar conflitos com futuras atualizações do WP. Aqui está a minha solução, com base em algum comentário nº 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 é disso que eu precisava, mas não seria muito difícil modificar isso para aceitar vários valores.

Houve alguma menção nesse segmento do Trac que pode não ter uma boa escala, mas estou trabalhando em uma escala bem pequena e não tive problemas com a velocidade.

Mark Pruce
fonte
Esta solução parece mais "nativos" para mee - de qualquer maneira -> Você deve chamar "wp_reset_postdata ()" logo após o "EndWhile" do loop: wordpress.stackexchange.com/questions/144343/...
Thomas Fellinger
2

Dois tipos de postagem personalizados 'country' e 'city' e uma taxonomia compartilhada 'flag'. 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' ) ); ?>
Alex
fonte
1

[editar] 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 $ wpdb-> prepare limpa a string $ post_types_str para p.post_type IN('country,city')enquanto deveria p.post_type IN('country','city'). Veja este ingresso: 11102 . Use a solução deste tópico para contornar isso: /programming//a/10634225

keesiemeijer
fonte
1

Também tentei usar a resposta de @Stephen Harris, mas a consulta que eu precisava era bastante difícil de escrever como uma única consulta e usando as partes do filtro.

Além disso, eu também precisava usar essa função várias vezes na mesma página e resolvi o problema declarando a wpse_filter_terms_by_cptfunção fora da função wrapper.

De qualquer forma, a resposta de @Mark Pruce se encaixa melhor, pelas mesmas razões que ele disse, mesmo que seja necessário fazer mais uma consulta (e o loop relacionado) para preparar os argumentos para a wp_get_object_termsfunção.

Sgaddo
fonte