Ich habe versucht, die Antwort von @Manny Fleurmond anzuwenden, und wie bei @Jake konnte ich sie nicht zum Laufen bringen, selbst nachdem ich den Tippfehler korrigiert hatte, der 'orderby' => 'meta_key'
sein sollte 'orderby' => 'meta_value'
. (Und der Vollständigkeit halber sollte es 'posts_per_page'
nicht sein, 'post_per_page'
aber das hat keinen Einfluss auf das betrachtete Problem.)
Wenn Sie sich die SQL-Abfrage ansehen, die tatsächlich durch die Antwort von @Manny Fleurmond generiert wurde (nachdem Sie die Tippfehler korrigiert haben), erhalten Sie Folgendes:
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
Dies zeigt, wie WP die Abfragevariablen analysiert: Es erstellt eine Tabelle für jede meta_query-Klausel und findet dann heraus, wie sie verbunden werden sollen und nach was sortiert werden soll. Die Bestellung würde gut funktionieren, wenn Sie nur eine einzige Klausel mit verwenden würden 'compare' => 'EXISTS'
, aber wenn Sie die zweite 'compare' => 'NOT EXISTS'
Klausel mit OR verbinden (wie wir müssen), wird die Bestellung durcheinander gebracht. Das Ergebnis ist, dass LEFT JOIN verwendet wird, um sowohl die erste Klausel / Tabelle als auch die zweite Klausel / Tabelle zu verbinden. Die Art und Weise, wie WP alles zusammenfügt, bedeutet, dass die mit erstellte Tabelle 'compare' => 'EXISTS'
tatsächlich mit meta_values aus JEDEM benutzerdefinierten Feld gefüllt wird, nicht nur mit 'custom_author_name'
Feld, an dem wir interessiert sind. Daher denke ich, dass die Bestellung nach dieser Klausel / Tabelle nur dann die gewünschten Ergebnisse liefert, wenn der bestimmte post_type von 'news' nur ein einziges benutzerdefiniertes Feld enthält.
Die Lösung, die für meine Situation funktionierte, bestand darin, nach der anderen Klausel / Tabelle zu bestellen - der NOT EXISTS-Klausel. Ich weiß, dass dies scheinbar kontraintuitiv ist, aber aufgrund der Art und Weise, wie WP die Abfragevariablen analysiert, wird diese Tabelle meta_value
nur mit dem benutzerdefinierten Feld gefüllt, nach dem wir suchen.
(Der einzige Weg, dies herauszufinden, bestand darin, das Äquivalent dieser Abfrage für meinen Fall auszuführen:
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
Ich habe lediglich die angezeigten Spalten geändert und die GROUP BY-Klausel entfernt. Dies zeigte mir dann, was los war - dass die Spalte postmeta.meta_value Werte aus allen meta_keys abrief, während die Spalte mt1.meta_value nur meta_values aus dem benutzerdefinierten Nachrichtenfeld abrief.)
Die Lösung
Wie @Manny Fleurmond sagt, ist es die erste Klausel, die für die Bestellung verwendet wird. Die Antwort besteht also darin, die Klauseln zu vertauschen und Folgendes zu geben:
$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);
Alternativ können Sie die Klauseln zu assoziativen Arrays machen und nach dem entsprechenden Schlüssel sortieren, wie folgt:
$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'
, hat sie die Reihenfolge geändert, aber es hatte nichts mit dem tatsächlichen Metafeld zu tun.