Eu tentei aplicar a resposta de @Manny Fleurmond e como @Jake eu não poderia obtê-lo a trabalhar mesmo depois de corrigir o erro de digitação que 'orderby' => 'meta_key'
deve ser 'orderby' => 'meta_value'
. (E, para completar, deve ser 'posts_per_page'
não 'post_per_page'
, mas que não afeta a questão que está sendo olhado.)
Se você olhar para a consulta SQL realmente gerada pela resposta de @Manny Fleurmond (após corrigir 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 maneira como o WP está analisando os vars de consulta: está criando uma tabela para cada cláusula meta_query e, em seguida, descobrindo como se juntar a eles e o que pedir. A ordem funcionaria bem se você estivesse usando apenas uma única cláusula com 'compare' => 'EXISTS'
, mas a junção da segunda 'compare' => 'NOT EXISTS'
cláusula com OR (como devemos) atrapalha a ordem. O resultado é que LEFT JOIN é usado para unir a primeira cláusula / tabela e a segunda cláusula / tabela - e a maneira como o WP reúne tudo significa que a tabela criada usando 'compare' => 'EXISTS'
está realmente sendo preenchida com meta_values de QUALQUER campo personalizado, não apenas o 'custom_author_name'
no qual estamos interessados. Portanto, acho que a ordenação por essa cláusula / tabela fornecerá apenas os resultados desejados se o tipo de post específico de 'news' tiver apenas um único campo personalizado.
A solução que funcionou para minha situação foi pedir pela outra cláusula / tabela - a NÃO EXISTE. Aparentemente contra-intuitivo, eu sei, mas devido à maneira como o WP analisa os vars de consulta, é nesta tabela que meta_value
é preenchida apenas pelo campo personalizado que buscamos.
(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 fiz foi alterar as colunas exibidas e remover a cláusula GROUP BY. Isso então me mostrou o que estava acontecendo - que a coluna postmeta.meta_value estava obtendo valores de todas as meta_keys, enquanto a coluna mt1.meta_value estava obtendo apenas meta_values do campo personalizado de notícias.)
A solução
Como @Manny Fleurmond diz, é a primeira cláusula que é usada para o pedido, então a resposta é apenas trocar as cláusulas, dando o seguinte:
$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);
Como alternativa, você pode criar as cláusulas matrizes associativas e ordenar pela chave correspondente, da seguinte forma:
$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);
'orderby' => 'meta_value'
, mudou a ordem, mas não teve nada a ver com o meta campo real.