Я попытался применить ответ @Manny Fleurmond и, как @Jake, я не мог заставить его работать даже после исправления опечатки, которая 'orderby' => 'meta_key'
должна быть 'orderby' => 'meta_value'
. (И для полноты это должно быть 'posts_per_page'
не так, 'post_per_page'
но это не влияет на рассматриваемый вопрос.)
Если вы посмотрите на SQL-запрос, фактически сгенерированный ответом @Manny Fleurmond (исправив опечатки), то вот что вы получите:
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
Это иллюстрирует, как WP выполняет синтаксический анализ запросов: он создает таблицу для каждого предложения meta_query, а затем выясняет, как их объединить и как упорядочить. Порядок работал бы хорошо, если бы вы использовали только одно предложение с 'compare' => 'EXISTS'
, но при объединении второго 'compare' => 'NOT EXISTS'
предложения с помощью OR (как мы должны) портит порядок. В результате LEFT JOIN используется для соединения как первого предложения / таблицы, так и второго предложения / таблицы - и то, как WP собирает все вместе, означает, что таблица, созданная с использованием, 'compare' => 'EXISTS'
на самом деле заполняется meta_values из ЛЮБОГО настраиваемого поля, а не только 'custom_author_name'
интересующее нас поле. Поэтому я думаю, что упорядочение по этому предложению / таблице даст желаемые результаты только в том случае, если конкретный post_type для «news» имеет только одно настраиваемое поле.
Решение, которое сработало для моей ситуации, состояло в том, чтобы заказать другой пункт / таблицу - НЕ СУЩЕСТВУЕТ. Кажется, мне кажется это нелогичным, но из-за того, как WP анализирует переменные запросов, именно эта таблица meta_value
заполняется только настраиваемым полем, к которому мы стремимся.
(Единственный способ, которым я понял это, - выполнить эквивалент этого запроса для моего случая:
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
Все, что я сделал, это изменил отображаемые столбцы и удалил предложение GROUP BY. Затем это показало мне, что происходит - что столбец postmeta.meta_value извлекал значения из всех meta_keys, в то время как столбец mt1.meta_value извлекал только meta_values из настраиваемого поля новостей.)
Решение
Как говорит @Manny Fleurmond, это первое предложение, которое используется для orderby, поэтому ответ заключается в том, чтобы просто поменять местами предложения, получив следующее:
$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);
В качестве альтернативы вы можете сделать предложения ассоциативными массивами и упорядочить по соответствующему ключу, например так:
$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'
, это изменило порядок, но это не имело ничего общего с фактическим метаполем.