Order_ meta_value apenas retorna postagens que tenham uma meta_key existente

Eu tenho a seguinte wp_query:

$args = array( 'post_type' => 'news', 'orderby' => 'meta_key', 'order' => 'ASC', 'meta_key'=>'custom_author_name', 'post_per_page'=>-1 ); $query = new WP_Query($args); echo $query->found_posts; 

echo = 10 resultados porque há apenas 10 postagens de news com um meta_key = custom_author_name . Mas existem centenas de postagens de news que não têm uma linha post_meta com essa meta_key específica. Observe que não há nenhuma meta_query envolvida. Nenhum meta_valor é atribuído, porque eu só estou tentando classificar as postagens por meta_key e não filtrar por meta_value.

Não deve ordenar selecionar todas as postagens? e apenas ordene-os?

Em caso afirmativo, por que o resultado é filtrado? Se a meta_key não for encontrada, por que não usar apenas uma string vazia ou uma combinação de tudo?

Se não, por que não?

Se eu inserir uma meta_key em todas as notícias (mesmo que seja uma string vazia), então recebo o resultado esperado. Mas isso parece ser um monte de linhas de tabelas que não precisam estar lá.

Solutions Collecting From Web of "Order_ meta_value apenas retorna postagens que tenham uma meta_key existente"

Como afirmado na resposta de @ ambroseya, é suposto funcionar desse jeito. Uma vez que você declara uma meta consulta, mesmo se você não estiver procurando por um valor específico, ele só consultará postagens com essa meta-chave declarada. Se você deseja include todas as mensagens classificá-las pela meta-chave, use o seguinte código:

 $args = array( 'post_type' => 'news', 'orderby' => 'meta_key', 'order' => 'ASC', 'meta_query' => array( 'relation' => 'OR', array( 'key'=>'custom_author_name', 'compare' => 'EXISTS' ), array( 'key'=>'custom_author_name', 'compare' => 'NOT EXISTS' ) ), 'post_per_page'=>-1 ); $query = new WP_Query($args); echo $query->found_posts; 

O que isso faz é usar uma meta-pesquisa avançada que procura mensagens que façam e não tenham essa meta-chave declarada. Uma vez que aquele com EXISTS é primeiro, quando você classifica por meta_value , ele usará a primeira consulta.

Na verdade, isso funciona.

Se você quer fazer isso sem adicionar linhas de tabela, você terá que fazer duas consultas. Um com a meta_key que tem os resultados limitados e o outro que obtém toda a lista; em seguida, use PHP para comparar os dois resultados da consulta (possivelmente removendo os resultados da meta_key da outra consulta para remover duplicatas, ou o que faz sentido na sua configuração).

Infelizmente, não é assim que o WP_Query funciona. Assim que você adiciona esse componente “meta”, você criou um tipo de filtro. Dump $query->request e você verá o que quero dizer.

Em segundo lugar, o WP_Query não suporta a ordenação por uma meta- chave . Você pode ordenar por um meta valor para uma chave específica, mas não pela própria chave. Mais uma vez, despeje a consulta para ver o que quero dizer. Você notará que os componentes da “ordem” são descartados se você tentar.

A maneira mais limpa de conseguir isso funcionar, na minha opinião, é um par de filtros curtos:

 function join_meta_wpse_188287($join) { remove_filter('posts_join','join_meta_wpse_188287'); global $wpdb; return ' INNER JOIN '.$wpdb->postmeta.' ON ('.$wpdb->posts.'.ID = '.$wpdb->postmeta.'.post_id)'; } add_filter('posts_join','join_meta_wpse_188287'); function orderby_meta_wpse_188287($orderby) { remove_filter('posts_orderby','orderby_meta_wpse_188287'); global $wpdb; return $wpdb->postmeta.'.meta_key ASC'; } add_filter('posts_orderby','orderby_meta_wpse_188287'); $args = array( 'post_type' => 'news', 'post_per_page'=>-1 ); $q = new WP_Query($args); var_dump($q->request); // debug var_dump(wp_list_pluck($q->posts,'post_title')); // debug 

Eu tentei aplicar a resposta de @Manny Fleurmond e, como @Jake, não consegui-lo funcionar, mesmo depois de corrigir o erro de digitação que 'orderby' => 'meta_key' deveria ser 'orderby' => 'meta_value' . (E, por completo, deve ser 'posts_per_page' não 'post_per_page' mas isso não afeta a questão que está sendo analisada.)

Se você olhar para a consulta SQL realmente gerada pela resposta do @Manny Fleurmond (corrigindo os erros de digitação), é isso que você obtém:

 SELECT wp_{prefix}_posts.* FROM wp_{prefix}_posts LEFT JOIN wp_{prefix}_postmeta ON (wp_{prefix}_posts.ID = wp_{prefix}_postmeta.post_id AND wp_{prefix}_postmeta.meta_key = 'custom_author_name' ) LEFT JOIN wp_{prefix}_postmeta AS mt1 ON ( wp_{prefix}_posts.ID = mt1.post_id ) WHERE 1=1 AND ( wp_{prefix}_postmeta.post_id IS NULL OR mt1.meta_key = 'custom_author_name' ) AND wp_{prefix}_posts.post_type = 'news' AND (wp_{prefix}_posts.post_status = 'publish' OR wp_{prefix}_posts.post_author = 1 AND wp_{prefix}_posts.post_status = 'private') GROUP BY wp_{prefix}_posts.ID ORDER BY wp_{prefix}_postmeta.meta_value ASC 

Isso ilustra a forma como o WP está analisando a consulta vars: está criando uma tabela para cada cláusula meta_query e depois descobre como juntar-se a elas e para o qual ordenar. O pedido funcionaria bem se você estivesse usando apenas uma única cláusula com 'compare' => 'EXISTS' , mas juntando a segunda cláusula 'compare' => 'NOT EXISTS' com OR (como devemos) sujar o pedido. O resultado é que LEFT JOIN é usado para se associar à primeira cláusula / tabela e à segunda cláusula / tabela – e a forma como o WP coloca tudo em conjunto significa que a tabela criada usando 'compare' => 'EXISTS' está sendo preenchida com meta_values de qualquer campo personalizado, não apenas o campo 'custom_author_name' que nos interessa. Então, eu acho que o pedido por essa cláusula / tabela só dará os resultados desejados se o tipo de publicação específico de ‘novidades’ tiver apenas um único campo personalizado.

A solução que funcionou para a minha situação era encomendar pela outra cláusula / tabela – NÃO EXISTE uma. Aparentemente contra-intuitivo, eu sei, mas por causa da forma como o WP analisa a consulta, é esta tabela onde meta_value é preenchido apenas pelo campo personalizado que estamos procurando.

(A única maneira de descobrir isso foi executando o equivalente a essa consulta para o meu caso:

 SELECT wp_{prefix}_posts.ID, wp_{prefix}_postmeta.meta_value, mt1.meta_value FROM wp_{prefix}_posts LEFT JOIN wp_{prefix}_postmeta ON (wp_{prefix}_posts.ID = wp_{prefix}_postmeta.post_id AND wp_{prefix}_postmeta.meta_key = 'custom_author_name' ) LEFT JOIN wp_{prefix}_postmeta AS mt1 ON ( wp_{prefix}_posts.ID = mt1.post_id ) WHERE 1=1 AND ( wp_{prefix}_postmeta.post_id IS NULL OR mt1.meta_key = 'custom_author_name' ) AND wp_{prefix}_posts.post_type = 'news' AND (wp_{prefix}_posts.post_status = 'publish' OR wp_{prefix}_posts.post_author = 1 AND wp_{prefix}_posts.post_status = 'private') ORDER BY wp_{prefix}_postmeta.meta_value ASC 

Tudo o que eu fiz é mudar as colunas mostradas e remover a cláusula GROUP BY. Isso então me mostrou o que estava acontecendo – que a coluna postmeta.meta_value estava puxando valores de todas as meta_keys, enquanto a coluna mt1.meta_value estava puxando apenas meta_values ​​do campo personalizado de notícias.)

A solução

Como @Manny Fleurmond diz, é a primeira cláusula que é usada para o orderby, então a resposta é apenas para trocar as cláusulas em volta, dando isso:

 $args = array( 'post_type' => 'news', 'orderby' => 'meta_value', 'order' => 'ASC', 'meta_query' => array( 'relation' => 'OR', array( 'key' => 'custom_author_name', 'compare' => 'NOT EXISTS' ), array( 'key' => 'custom_author_name', 'compare' => 'EXISTS' ) ), 'posts_per_page' => -1 ); $query = new WP_Query($args); 

Alternativamente, você pode fazer as matrizes associativas das cláusulas e encomendar pela chave correspondente, assim:

 $args = array( 'post_type' => 'news', 'orderby' => 'not_exists_clause', 'order' => 'ASC', 'meta_query' => array( 'relation' => 'OR', 'exists_clause' => array( 'key' => 'custom_author_name', 'compare' => 'EXISTS' ), 'not_exists_clause' => array( 'key' => 'custom_author_name', 'compare' => 'NOT EXISTS' ) ), 'posts_per_page' => -1 ); $query = new WP_Query($args);