Próbowałem stosowania odpowiedź @Manny Fleurmond i jak @Jake nie mogę zmusić go do pracy nawet po skorygowaniu literówkę, że 'orderby' => 'meta_key'
powinna być 'orderby' => 'meta_value'
. (I dla kompletności powinno być 'posts_per_page'
nie 'post_per_page'
ale to nie wpływa na kwestię badana).
Jeśli spojrzysz na zapytanie SQL faktycznie wygenerowane przez odpowiedź @Manny Fleurmond (poprawiając literówki), otrzymujesz:
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
To ilustruje sposób, w jaki WP analizuje zmienne zapytania: tworzy tabelę dla każdej klauzuli meta_query, a następnie zastanawia się, jak do nich dołączyć i jak zamówić. Kolejność działałaby dobrze, gdybyś używał tylko jednej klauzuli z 'compare' => 'EXISTS'
, ale połączenie drugiej 'compare' => 'NOT EXISTS'
klauzuli z OR (jak musimy) zakłóca porządkowanie. W rezultacie LEFT JOIN jest używany do łączenia zarówno pierwszej klauzuli / tabeli, jak i drugiej klauzuli / tabeli - a sposób, w jaki WP 'compare' => 'EXISTS'
składa wszystko razem, oznacza, że tabela utworzona za pomocą jest faktycznie wypełniana meta_wartościami z DOWOLNEGO niestandardowego pola, a nie tylko 'custom_author_name'
pole, którym jesteśmy zainteresowani. Myślę więc, że uporządkowanie według tej klauzuli / tabeli da pożądane wyniki tylko wtedy, gdy określony typ postu „news” ma tylko jedno niestandardowe pole.
Rozwiązaniem, które zadziałało w mojej sytuacji, było zamówienie według drugiej klauzuli / tabeli - NIE ISTNIEJĄCEJ. Wiem, pozornie intuicyjne, ale ze względu na sposób, w jaki WP analizuje zmienne zapytania, jest to tabela, w której meta_value
zapełniane są tylko pola niestandardowe, których szukamy.
(Jedynym sposobem, w jaki do tego doszedłem, było uruchomienie odpowiednika tego zapytania dla mojej sprawy:
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
Wszystko, co zrobiłem, to zmiana wyświetlanych kolumn i usunięcie klauzuli GROUP BY. To pokazało mi, co się dzieje - że kolumna postmeta.meta_value pobierała wartości ze wszystkich kluczy meta_keys, a kolumna mt1.meta_value pobierała tylko wartości meta_value z niestandardowego pola wiadomości.)
Rozwiązanie
Jak mówi @Manny Fleurmond, jest to pierwsza klauzula używana do zamówienia, więc odpowiedź polega na zamianie rund klauzul, co daje:
$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);
Alternatywnie możesz utworzyć klauzule tablic asocjacyjnych i uporządkować według odpowiedniego klucza, na przykład:
$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'
, zmieniło kolejność, ale nie miało nic wspólnego z rzeczywistym polem meta.