Intenté aplicar la respuesta de @Manny Fleurmond y, al igual que @Jake, no pude hacer que funcionara incluso después de corregir el error tipográfico que 'orderby' => 'meta_key'
debería ser 'orderby' => 'meta_value'
. (Y para completar, debe ser 'posts_per_page'
no 'post_per_page'
, pero eso no afecta el problema que se está analizando).
Si observas la consulta SQL generada realmente por la respuesta de @Manny Fleurmond (habiendo corregido los errores tipográficos) esto es lo que obtienes:
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
Esto ilustra la forma en que WP está analizando las variables de consulta: está creando una tabla para cada cláusula meta_query, y luego averigua cómo unirlas y qué ordenar. El ordenamiento funcionaría bien si solo estuviera usando una única cláusula con 'compare' => 'EXISTS'
, pero unir la segunda cláusula 'compare' => 'NOT EXISTS'
con OR (como debemos) desordena el orden. El resultado es que LEFT JOIN se usa para unir tanto la primera cláusula / tabla como la segunda cláusula / tabla, y la forma en que WP pone todo junto significa que la tabla creada con 'compare' => 'EXISTS'
se está completando con meta_values desde CUALQUIER campo personalizado, no solo el campo 'custom_author_name'
en el que estamos interesados. Por lo tanto, creo que ordenar por esa cláusula / tabla solo dará los resultados deseados si el tipo de publicación en particular de 'noticias' solo tiene un único campo personalizado.
La solución que funcionó para mi situación fue ordenar por la otra cláusula / tabla: la NO EXISTA. Al parecer, es contraintuitivo, pero debido a la forma en que WP analiza las variables de consulta, es en esta tabla donde meta_value
solo se llena con el campo personalizado que buscamos.
(La única forma en que me di cuenta de esto fue ejecutando el equivalente de esta consulta para mi 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
Todo lo que he hecho es cambiar las columnas que se muestran y eliminar la cláusula GROUP BY. Esto luego me mostró lo que estaba pasando: que la columna postmeta.meta_value estaba obteniendo valores de todas las meta_keys, mientras que la columna mt1.meta_value estaba obteniendo solo meta_values del campo personalizado de noticias.)
La solución
Como dice @Manny Fleurmond, es la primera cláusula que se utiliza para el pedido, por lo que la respuesta es simplemente intercambiar las cláusulas, dando esto:
$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, puede hacer las matrices asociativas de orden y las cláusulas por la clave correspondiente, de esta manera:
$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);