Orderby wartość_meta zwraca tylko posty, które mają istniejący klucz_meta

10

Mam następujące wp_query:

$args = array(
    'post_type' => 'news',
    'orderby' => 'meta_key',
    'order' => 'ASC',
    'meta_key'=>'custom_author_name',
    'post_per_page'=>-1
);

$query = new WP_Query($args);

echo $query->found_posts;

echo = 10 wyników, ponieważ jest tylko 10 newspostów z meta_key = custom_author_name. Ale istnieją setki newspostów, które nie mają wiersza post_meta z tym konkretnym meta_key. Zauważ, że nie ma w tym udziału meta_query. Nie przypisano żadnej wartości meta_wartości, ponieważ próbuję tylko posortować posty według meta_key, a nie filtrować według meta_value.

Czy nie należy zamawiać przez zaznaczenie wszystkich postów? i po prostu je zamówić?

Jeśli tak, dlaczego wynik jest filtrowany? Jeśli nie znaleziono klucza meta_key, dlaczego po prostu nie użyć pustego ciągu lub dopasować wszystko?

Jeśli nie, dlaczego nie?

Jeśli wprowadzę meta_key do każdego postu z wiadomościami (nawet jeśli jest to pusty ciąg), otrzymam oczekiwany wynik. Ale to wygląda na wiele rzędów tabel, które nie muszą tam być.

gdaniel
źródło

Odpowiedzi:

10

Jak stwierdzono w odpowiedzi @ ambroseya, ma tak działać. Po zadeklarowaniu meta kwerendy, nawet jeśli nie szukasz konkretnej wartości, będzie ona wyszukiwać tylko posty z zadeklarowanym meta-kluczem. Jeśli chcesz uwzględnić wszystkie posty, posortuj je według klucza meta, użyj następującego kodu:

$args = array(
    'post_type' => 'news',
    'orderby' => 'meta_value',
    'order' => 'ASC',
    'meta_query' => array(
        'relation' => 'OR',
        array( 
            'key'=>'custom_author_name',
            'compare' => 'EXISTS'           
        ),
        array( 
            'key'=>'custom_author_name',
            'compare' => 'NOT EXISTS'           
        )
    ),
    'posts_per_page'=>-1
);

$query = new WP_Query($args);

echo $query->found_posts;

W tym celu należy użyć zaawansowanego kwerendy meta, która wyszukuje posty zawierające takie meta-klucze i nie zadeklarowane. Ponieważ ten z EXISTSjest pierwszy, podczas sortowania meta_valueużyje pierwszego zapytania.

Manny Fleurmond
źródło
3
W ogóle nie zmieniło to dla mnie kolejności, kiedy użyłem 'orderby' => 'meta_value', zmieniło kolejność, ale nie miało nic wspólnego z rzeczywistym polem meta.
Jake
3

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_valuezapeł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);
jlad26
źródło
Warto zauważyć, że jeśli meta-klucz custom_author_namezostanie ustawiony, a następnie rozbrojony, to meta_keyzareaguje, EXISTSa efekt będzie taki, że będą one bąbelkowane obok postów, które mają custom_author_name. W moim przypadku mam pole wyboru, więc używam "value" => "1"zamiast EXISTS, ale ciągi będą wymagały innego podejścia.
djb
1

Właśnie tak to działa.

Jeśli chcesz to zrobić bez dodawania wierszy tabeli, musisz wykonać dwa zapytania. Jeden z meta_key, który ma ograniczone wyniki, a drugi z całą listą; następnie użyj PHP, aby porównać dwa wyniki zapytania (ewentualnie usuń wyniki meta_key z drugiego zapytania, aby usunąć duplikaty lub cokolwiek innego, co ma sens w twoim ustawieniu).

ambroseya
źródło
0

Niestety nie tak to WP_Querydziała. Jak tylko dodasz ten komponent „meta”, stworzyłeś swego rodzaju filtr. Zrzuć, $query->requesta zobaczysz, co mam na myśli.

Po drugie, w WP_Queryogóle nie obsługuje zamawiania według meta- klucza . Możesz zamówić według wartości meta dla określonego klucza, ale nie według samego klucza. Ponownie zrzuć zapytanie, aby zobaczyć, co mam na myśli. Zauważysz, że składniki „zamówienia” wypadają, jeśli spróbujesz.

Moim zdaniem najczystszym sposobem, aby to zadziałało, jest kilka krótkich filtrów:

function join_meta_wpse_188287($join) {
  remove_filter('posts_join','join_meta_wpse_188287');
  global $wpdb;
  return ' INNER JOIN '.$wpdb->postmeta.' ON ('.$wpdb->posts.'.ID = '.$wpdb->postmeta.'.post_id)';
}
add_filter('posts_join','join_meta_wpse_188287');

function orderby_meta_wpse_188287($orderby) {
  remove_filter('posts_orderby','orderby_meta_wpse_188287');
  global $wpdb;
  return $wpdb->postmeta.'.meta_key ASC';
}
add_filter('posts_orderby','orderby_meta_wpse_188287');

$args = array(
    'post_type' => 'news',
    'post_per_page'=>-1
);
$q = new WP_Query($args);
var_dump($q->request); // debug
var_dump(wp_list_pluck($q->posts,'post_title')); // debug
s_ha_dum
źródło