Modyfikowałem wbudowane wyszukiwanie WP za pomocą pre_get_posts
filtra, pozwalając użytkownikowi sortować posty (w tym kilka niestandardowych typów postów) według różnych pól.
Problemem jest to, że gdy mówię WP, aby sortowała według wartości meta, wyklucza wszystkie posty, które nie mają tej wartości meta. Powoduje to zmianę liczby wyników, jeśli zmienisz sortowanie z powiedz „Cena” na „Data”, ponieważ w „Postach” nie ma ustawionej „Ceny”, ale „Pozycje”.
Nie tego chcę, więc chciałbym wiedzieć, czy istnieje sposób na dołączenie WSZYSTKICH postów - nawet tych, które nie mają meta wartości, którą sortuję - i umieszczenia tych bez wartości na końcu.
Wiem, jak sortować według więcej niż jednego pola, ale to nie pomaga.
Dzięki
Wydaje się, że nie jestem jedyny z tym pytaniem: sposób na dołączanie postów zarówno z, jak i bez określonego meta_key w args dla wp_query? ale nie ma tam rozwiązania.
Aktualizacja
Próbowałem odpowiedzi, ale nie jestem pewien, czy dobrze zrozumiałem, oto co mam teraz:
<?php
function my_stuff ($qry) {
$qry->set('meta_query', array(array(
'key' => 'item_price',
'value' => '',
'compare' => 'NOT EXISTS'
)));
$qry->set('orderby', 'meta_value date'); # Sorting works with meta_value as well as meta_value_num - I've tried both
$qry->set('order', 'ASC DESC');
$qry->set('meta_key', 'item_price');
}
Meta wartość jest liczbą (służy do przechowywania ceny, jak sugeruje nazwa)
Aktualizacja 2
Skomentowałem zamówienia i wszystko, co teraz mam, to:
<?php
$qry->set('meta_query', array(array(
'key' => 'item_price',
'value' => '',
'compare' => 'NOT EXISTS'
)));
Z tym kodem zapytanie wydaje się zwracać wszystkie posty, które nie mają item_price
klucza i żaden z nich nie ma klucza. IE problem jest teraz odwrócony.
Jeśli dodam również kod zamówienia, otrzymam 0 wyników.
Edycja: ... trzy lata później ... : PI znów miał ten problem. Próbowałem wszystkich podanych odpowiedzi i żadna nie działała. Nie jestem pewien, dlaczego niektórzy ludzie myślą, że działają, ale przynajmniej dla mnie nie działają.
Rozwiązaniem, w którym się znalazłem, jest użycie save_post
filtra - upewniając się, że wszystkie posty mają niestandardowe pola, na których chcę sortować. To trochę denerwujące, że muszę to zrobić, ale dopóki robisz to wcześniej, prawdopodobnie nie będziesz mieć problemów.
W tym przypadku budowałem „licznik wyświetleń” na postach i chciałem, aby użytkownicy mogli sortować według najczęściej czytanych postów. Znów posty, które nigdy nie były oglądane (myślę, że to raczej mało prawdopodobne - ale nadal) zniknęły podczas sortowania według liczby wyświetleń. Dodałem ten fragment kodu, aby upewnić się, że wszystkie posty mają liczbę wyświetleń:
add_action('save_post', function ($postId) {
add_post_meta($postId, '_sleek_view_count', 0, true);
});
źródło
meta_query
i zawszetax_query
są , ponieważ łączą wiele tablic. Po drugie - jak wspomniano w mojej odpowiedzi - musisz użyć liczb. Równie dobrze może być konieczne zdefiniowanie (patrz pozycja strony Kodeksu). Ostatnio, to nie ma sensu się i kierunek. To nie jest możliwe. Ogranicznik spacji działa tylko dla i nie można nakazać sortowania pierwszego i drugiego . Do tego służy filtr.array( array() )
meta_value_num
meta_value_num
WP_Query
order
ASC
DESC
orderby
ASC
DESC
posts_clauses
meta_value_num
wpisy są liczbami rzeczywistymi . Zbyt często zdarza się, że ktoś twierdzi, że jest to liczba, ale w rzeczywistości zapisuje ją jako ciąg znaków w bazie danych.ASC DESC
jest taki, że sortuje nameta_value
wASC
idate
wDESC
miarę mogę powiedzieć, że działa.Odpowiedzi:
Istnieją dwa możliwe rozwiązania tego:
1. Wszystkie posty mają meta
Najlepszym rozwiązaniem, jakie znalazłem tutaj, jest nadanie pozostałym postom / produktom ceny produktu równej 0. Możesz to zrobić ręcznie lub przejrzeć wszystkie posty, a jeśli cena jest pusta, zaktualizuj ją.
Aby w przyszłości było to możliwe do zarządzania, możesz podłączyć się
save_post
i nadać im wartość, gdy zostaną dodane po raz pierwszy (tylko jeśli jest puste).2. Wiele zapytań
Możesz uruchomić pierwsze zapytanie i zapisać identyfikatory zwróconych postów. Następnie można uruchomić kolejne zapytanie dla wszystkich postów i według daty zamówienia, z wyłączeniem identyfikatorów zwróconych z pierwszego zapytania.
Następnie możesz wydrukować osobno dwa wyniki, a uzyskasz pożądane wyniki.
źródło
save_post
metody (zaktualizowałem swoje pytanie kodem, którego użyłem).Easy Peasy, właśnie przetestowane w 2018 roku, obecnie używane w produkcji.
Sprawdza wszystkie elementy z meta-kluczem i bez niego, bez określonej wartości. meta kwerenda zapewnia niezawodnie klucz do zamówienia. Został przetestowany. Nie jestem jednak pewien, jak to będzie działać, gdy kwerenda meta używa wielu kluczy.
Praktyczny przykład
To
custom_meta_key
domyślnie porządkuje posty i nie ignoruje postów bez wartości dla tego klucza.źródło
custom_meta_key
i otrzymywanie postów, których nie macustom_meta_key
. Dołącz rzeczywisty przykładowy dział sortowania.$query->set( 'orderby', 'meta_value title' );
(Sortuj według wartości meta, a następnie według tytułu, gdy wiele postów ma tę samą wartość dla klucza meta). Należy to zrobić napre_get_posts
haku, używając$query
zmiennej przekazywanej . Pamiętaj, że zadane pytanie dotyczyło sposobu zamawiania według wartości meta, nie ignorując postów, które nie mają wartości dla tego meta klucza.get_posts()
wywołaniu, aby przesunąć posty z_featured
meta na górę, a następnie posortować według daty. Dzięki!Ta metoda zwróci wszystkie posty, w tym te z żądaniem i bez
meta_key
, ale przy zamówieniu zrobi dziwne rzeczy.Znalazłem to, bawiąc się wszystkimi odpowiedziami na to pytanie i analizując wygenerowany kod SQL metodą prób i błędów. Wygląda na to, że ustawienie
array('meta_query' => array('relation' => 'OR'))
wynikówLEFT JOIN
zamiast odpowiedniegoINNER JOIN
jest konieczne, aby uwzględnić posty z brakującymi metadanymi. OkreślenieNOT EXISTS
zapobiegaWHERE
filtrowaniu klauzulę postów pozbawionych pola meta. W tymWP_Query
przypadku wygenerowany kod SQL to (dodano wcięcia / znaki nowej linii):Wynikiem jest lista wszystkich postów z meta_value
item_price
i tych, których brakujeitem_price
. Wszystkie posty zitem_price
będą porządkowane względem siebie poprawnie, ale brakujące postyitem_price
wykorzystają losową inną meta wartość (powiedzmy,_edit_last
która wydaje się1
dość często w mojej bazie danych lub innym wewnętrznym metadanych wordpress, które są całkowicie arbitralne) dla jegowp_postmeta.meta_value
wORDER BY
klauzula. Tak więc, chociaż ta metoda jest bliska i może wydawać się działać dla niektórych danych, jest zepsuta. Mogę tylko powiedzieć, że jeśli twojeitem_price
wartości nie powodują konfliktu z przypadkowymi meta polami, które MySQL wybiera dla brakujących postówitem_price
, może to działać dobrze. Jeśli wszystko, czego potrzebujesz, to gwarancja, że Twoje postyitem_price
są prawidłowo uporządkowane względem siebie bez względu na kolejność innych postów, może być OK. Ale myślę, że to tylko wada w wordpress. Proszę mnie poprawić, mam nadzieję, że się mylę i jest na to sposób ;-).Wydaje się, że w przypadku
INNER JOIN wp_postmeta
MySQL wybiera losowy wiersz spośród wielupostmeta
wierszy powiązanych z postem, gdymeta_key
brakuje go w danym poście. Z perspektywy SQL musimy dowiedzieć się, jak powiedzieć WordPressowi wyjścieORDER BY mt1.meta_value
. Ta kolumna jest poprawnie,NULL
gdymeta_key
brakuje naszej prośby , w przeciwieństwie dowp_postmeta.meta_value
. Gdybyśmy mogli to zrobić, SQL posortowałby teNULL
(brakujące wpisy) przed jakąkolwiek inną wartością, dając nam dobrze zdefiniowaną kolejność: najpierw przychodzą wszystkie posty, w których brakuje określonego pola postmeta, a następnie przychodzą posty zawierające to pole. Ale to jest cały problem:'orderby' => 'meta_value'
można się tylko odwoływać,'meta_key' => 'item_price'
a niezachwianywp_postmeta
jest zawsze, aINNER JOIN
nie zawszeLEFT JOIN
, znaczeniemwp_postmeta.meta_value
iwp_postmeta.meta_key
możenigdy nie będzieNULL
.Myślę, że muszę powiedzieć, że nie jest to możliwe przy wbudowanym wordpressie,
WP_Query
ponieważ jest to teraz udokumentowane (w wordpress-3.9.1). Niepokoić. Więc jeśli faktycznie potrzebujesz, aby działało poprawnie, prawdopodobnie musisz podłączyć się do wordpress gdzie indziej i bezpośrednio zmodyfikować wygenerowany SQL .źródło
Myślę, że mam rozwiązanie.
Możesz użyć dwóch
meta_key
s, jednego, który mają wszystkie posty(like "_thumbnail_id")
, i tego,meta_key
którego chcesz użyć jako filtra.Więc twoje argumenty:
źródło
'value' => '',
również drugie porównanie powinno byćNOT EXISTS
i ostatnia instrukcja zestawu nie jest wymaganaProblem, który każdy tutaj ma, dotyczy kolejności zapytań meta. Aby sortować poprawnie, należy umieścić zapytanie „NOT EXISTS” przed zapytaniem „EXISTS”.
Powodem tego jest to, że WordPress używa meta_value ostatniej instrukcji „LEFT JOIN” w klauzuli „ORDER BY”.
Na przykład:
źródło
W razie potrzeby można dodać domyślną wartość meta za każdym razem, gdy post jest zapisywany lub aktualizowany, jeśli ta wartość nie istnieje.
Jeśli używasz niestandardowego typu postu, zastąp go
add_action('save_post', 'addDefaultMetaValue');
przezadd_action('save_post_{post_type}', 'addDefaultMetaValue');
npadd_action('save_post_product', 'addDefaultMetaValue');
źródło
Miałem problem z liczbowymi meta wartościami i zwróciłem uwagę, że kolejność zapytania jest również ważna. Dla mnie
NOT EXISTS
zapytanie musi być pierwsze.Przykład:
Ważne jest również,
’orderby’
aby ustawić właściwy kierunek wartości liczbowych’meta_value_num’
. W przeciwnym razie masz dziwne wyniki dla wartości liczbowych, np .:1, 2, 20, 21, 3, 4, 5…
Zamiast:
1, 2, 3, 4, 5… 20, 21
źródło
Napotkałem również podobny problem i następujące rozwiązanie pomogło mi:
Znalazłem opis na WordPress Codex z tytułem „ orderby” z wieloma „meta_key's ”: https://codex.wordpress.org/Class_Reference/WP_Query#Order_.26_Orderby_Parameters
źródło
Jest do tego możliwa
orderby
wartośćmeta_value
.Jeśli masz wartości liczbowe, po prostu użyj
meta_value_num
zamiast tego.Oświadczenie: To nie jest przetestowane, ale powinno działać. Chodzi o to, że musisz podać swoje
meta_key
ikey
wartości. W przeciwnym razie nie można porównać z nieistniejącymi wartościami, co powinno umożliwić przeszukiwanie obu rodzajów postów. To jakiś hack-hak, ale dopóki działa ...źródło
'your_keys_name'
i'your_meta_key'
oba powinny być tym samym ciągiem zamiast odrębnego, w przeciwnym razie wygląda na to, że źle zrozumiałeś pytanie. Po drugie, przetestowałem to na mojej lokalnej konfiguracji i wyklucza wszystkie posty, w których klucz istnieje (przezmeta_query
) i wyklucza wszelkie posty, w których klucz nie istnieje (przezmeta_key
), co powoduje, że posty nie są wyświetlane. Jednak ta odpowiedź jest krokiem w kierunku czegoś, co przynajmniej słowa ;-).'relation' => 'OR'
dometa_query
. Zwariowane rzeczy o_o.Myślę, że to, co @kaiser próbował zrobić, to powiedzieć zapytaniu, aby zwróciło wszystkie posty, które mają ten meta-klucz, poprzez zastosowanie pewnego rodzaju manekina, w którym warunek, aby nie filtrować żadnego z tych postów. Więc jeśli znasz wszystkie wartości, które mogą przyjmować pola niestandardowe, to x, y, z, możesz powiedzieć „GDZIE meta_key IN (x, y, z) ”, ale pomysł polega na tym, że możesz uniknąć tego problemu razem, mówiąc ! = (' „) :
Też nie testowany, ale wydaje się, że warto spróbować :-).
źródło
Skończyło się na tym, że trochę się zhackowałem (IMHO), ale w moim przypadku to zadziałało.
Możesz podłączyć filtry post_join_paged i posts_orderby, aby zaktualizować parametry łączenia i porządkowania. Pozwoli ci to na zamówienie według tego, co chcesz, pod warunkiem, że dołączysz jako pierwszy, a nie WP_Query, zakładając, że pole musi istnieć dla tego konkretnego postu. Następnie można usunąć
meta_key
,orderby
i `zlecenie od firmy args WP_Query.Poniżej znajduje się przykład. Na górze każdej funkcji musiałem uciec w niektórych przypadkach, ponieważ doda to do wszystkiego, co używa WP_Query. Może być konieczne zmodyfikowanie go, aby dopasować go do konkretnych potrzeb.
Niestety brakuje dokumentacji na temat tych dwóch filtrów, więc ... powodzenia! :)
źródło
cast(my_custom_meta_key.meta_value as unsigned) DESC
powinien załatwić sprawę ...$orderby_statement = "cast(my_custom_meta_key.meta_value as unsigned) DESC";
działa świetnie.To rozwiązanie działało dla mnie:
Jednak to rozwiązanie najpierw pokazuje rekordy o wartości null meta_value. To inne rozwiązanie pokazuje kolejność ASC i wartości zerowe na końcu:
źródło