Sortuj według wartości meta, ale uwzględniaj posty, które jej nie mają

37

Modyfikowałem wbudowane wyszukiwanie WP za pomocą pre_get_postsfiltra, 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_priceklucza 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_postfiltra - 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);
});
powerbuoy
źródło
Pokaż nam swój kod. Ułatwia odpowiedź.
kaiser
Po pierwsze: meta_queryi 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_nummeta_value_numWP_QueryorderASC DESCorderbyASCDESCposts_clauses
kaiser
I upewnij się, że twoje meta_value_numwpisy 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.
kaiser
Dzięki za pomoc, spróbuję to i skontaktuję się z Tobą. Powód ASC DESCjest taki, że sortuje na meta_valuew ASCi datew DESCmiarę mogę powiedzieć, że działa.
powerbuoy
1
@Howdy_McGee, które są poprawne. Niektóre z moich niestandardowych typów postów mają ten zestaw wartości. Niektórzy nie. A wbudowane typy postów (takie jak POST i PAGE) nie. Kiedy więc próbuję sortować według tego niestandardowego pola, pojawiają się tylko posty z niestandardowym polem.
powerbuoy

Odpowiedzi:

4

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_posti 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.

Steven Jones
źródło
1
Trzy lata później znów miałem ten sam problem: P Musiałem skorzystać z save_postmetody (zaktualizowałem swoje pytanie kodem, którego użyłem).
powerbuoy
10

Easy Peasy, właśnie przetestowane w 2018 roku, obecnie używane w produkcji.

$query->set( 'meta_query', array(
    'relation' => 'OR',
    array(
        'key' => 'custom_meta_key', 
        'compare' => 'EXISTS'
    ),
    array(
        'key' => 'custom_meta_key', 
        'compare' => 'NOT EXISTS'
    )
) );
$query->set( 'orderby', 'meta_value title' ); 

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

/**
 * Modifies query before retrieving posts. Sets the 
 * `meta_query` and `orderby` param when no `orderby` 
 * param is set, (default ordering).
 * 
 * @param   WP_Query  $query  The full `WP_Query` object.
 * @return  void
 */
function example_post_ordering( $query ) {

    // if not in wp-admin, 
    // and the query is the main query, 
    // and the query is not a singular query, 
    // and the query does not have an orderby param set...
    // Note: check for post types, etc. here as desired.
    if ( ! is_admin() 
    && $query->is_main_query() 
    && ! $query->is_singular() 
    && empty( $query->get( 'orderby' ) ) ) {

        // Setting just `meta_key` is not sufficient, as this 
        // will ignore posts that do not yet, or never will have 
        // a value for the specified key. This meta query will 
        // register the `meta_key` for ordering, but will not 
        // ignore those posts without a value for this key.
        $query->set( 'meta_query', array(
            'relation' => 'OR',
            array(
                'key' => 'custom_meta_key', 
                'compare' => 'EXISTS'
            ),
            array(
                'key' => 'custom_meta_key', 
                'compare' => 'NOT EXISTS'
            )
        ) );

        // Order by the meta value, then by the title if multiple 
        // posts share the same value for the provided meta key.
        // Use `meta_value_num` if the meta values are numeric.
        $query->set( 'orderby', 'meta_value title' );
    }

}

add_action( 'pre_get_posts', 'example_post_ordering', 10 );

To custom_meta_keydomyślnie porządkuje posty i nie ignoruje postów bez wartości dla tego klucza.

noahmason
źródło
Po przeczytaniu kodu wszystko, co wydaje się robić, to pobieranie postów, które mają custom_meta_keyi otrzymywanie postów, których nie ma custom_meta_key. Dołącz rzeczywisty przykładowy dział sortowania.
powerbuoy
1
Masz rację, to wszystko, co robi, ale poniższy wiersz odpowiada za porządkowanie według meta_value (zapytania o meta-klucz). $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ć na pre_get_postshaku, używając $queryzmiennej 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.
noahmason 18.04.2018
@powerbuoy Zobacz zaktualizowany przykład praktyczny
noahmason
W porządku, spróbuję następnym razem, gdy napotkam ten problem.
powerbuoy
1
Pracowałem dla mnie w niestandardowym get_posts()wywołaniu, aby przesunąć posty z _featuredmeta na górę, a następnie posortować według daty. Dzięki!
natebeaty
8

Ta metoda zwróci wszystkie posty, w tym te z żądaniem i bez meta_key, ale przy zamówieniu zrobi dziwne rzeczy.

add_action('pre_get_posts', 'my_stuff');
function my_stuff ($qry) {
    $qry->set(
        'meta_query',
        array(
            'relation' => 'OR', # Matches to this meta_query should be added to those matching the 'meta_key' query
            array(
                'key' => 'item_price', 
                'value' => 'bug #23268', 
                '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');
}

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ów LEFT JOINzamiast odpowiedniego INNER JOINjest konieczne, aby uwzględnić posty z brakującymi metadanymi. Określenie NOT EXISTSzapobiegaWHERE filtrowaniu klauzulę postów pozbawionych pola meta. W tym WP_Queryprzypadku wygenerowany kod SQL to (dodano wcięcia / znaki nowej linii):

SELECT SQL_CALC_FOUND_ROWS
    wp_posts.ID
    FROM wp_posts
    INNER JOIN wp_term_relationships ON (wp_posts.ID = wp_term_relationships.object_id)
    INNER JOIN wp_postmeta ON wp_posts.ID = wp_postmeta.post_id
    LEFT JOIN wp_postmeta AS mt1 ON (wp_posts.ID = mt1.post_id AND mt1.meta_key = 'item_price')
    WHERE 1=1
    AND ( wp_term_relationships.term_taxonomy_id IN (2) )
    AND wp_posts.post_type = 'post'
    AND (wp_posts.post_status = 'publish'
        OR wp_posts.post_status = 'private')
    AND (wp_postmeta.meta_key = 'item_price'
        -- Oh look, here we give SQL permission to choose a random
        -- row from wp_postmeta when this particular post is missing
        -- 'item_price':
        OR  mt1.post_id IS NULL )
    GROUP BY wp_posts.ID
    ORDER BY wp_postmeta.meta_value,wp_posts.post_date DESC
    LIMIT 0, 10

Wynikiem jest lista wszystkich postów z meta_value item_pricei tych, których brakuje item_price. Wszystkie posty z item_pricebędą porządkowane względem siebie poprawnie, ale brakujące posty item_pricewykorzystają losową inną meta wartość (powiedzmy, _edit_lastktóra wydaje się 1dość często w mojej bazie danych lub innym wewnętrznym metadanych wordpress, które są całkowicie arbitralne) dla jegowp_postmeta.meta_value w ORDER BYklauzula. 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 twoje item_pricewartości nie powodują konfliktu z przypadkowymi meta polami, które MySQL wybiera dla brakujących postów item_price, może to działać dobrze. Jeśli wszystko, czego potrzebujesz, to gwarancja, że ​​Twoje postyitem_pricesą 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_postmetaMySQL wybiera losowy wiersz spośród wielu postmetawierszy powiązanych z postem, gdy meta_keybrakuje go w danym poście. Z perspektywy SQL musimy dowiedzieć się, jak powiedzieć WordPressowi wyjście ORDER BY mt1.meta_value. Ta kolumna jest poprawnie, NULLgdy meta_keybrakuje naszej prośby , w przeciwieństwie do wp_postmeta.meta_value. Gdybyśmy mogli to zrobić, SQL posortowałby te NULL(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 niezachwiany wp_postmetajest zawsze, a INNER JOINnie zawsze LEFT JOIN, znaczeniem wp_postmeta.meta_valuei wp_postmeta.meta_keymożenigdy nie będzie NULL.

Myślę, że muszę powiedzieć, że nie jest to możliwe przy wbudowanym wordpressie, WP_Queryponieważ 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 .

Binki
źródło
Wygląda bardzo obiecująco! Spróbuję to następnym razem, gdy będę mieć ten problem. Chciałbym ci teraz odpowiedzieć, ale wolę najpierw potwierdzić, że to działa.
powerbuoy
Dzięki temu wszystko się nie pokazywało. Nic nie pokazało po wdrożeniu tego.
Jake
@Jake Tak to samo tutaj. Miałem ten problem jeszcze dziś i próbowałem tego. Zwraca 0 wyników.
powerbuoy
Jakiej wersji wordpress używacie? Myślę, że ten post opisuje, jak używać wewnętrznego, nieudokumentowanego API, który nie jest obsługiwany przez wordpress, a więc prawdopodobnie działa tylko, jeśli korzystasz z wordpress-3.9.1 lub nie ma zbyt wielu wersji poza tym.
binki
2

Myślę, że mam rozwiązanie.

Możesz użyć dwóch meta_keys, jednego, który mają wszystkie posty (like "_thumbnail_id"), i tego, meta_keyktórego chcesz użyć jako filtra.

Więc twoje argumenty:

$qry->set(
    'meta_query',
    array(
        'relation' => 'OR',
        array(
            'key' => 'item_price', 
            'value' => '', 
            'compare' => 'EXISTS'
        ),
        array(
            'key' => 'item_price', 
            'value' => '', 
            'compare' => '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');
Rafael M31
źródło
1
Problemem jest tutaj porównanie pustych ciągów, usuń je i działa 'value' => '', również drugie porównanie powinno być NOT EXISTSi ostatnia instrukcja zestawu nie jest wymagana
nodws 24.04.18
2

Problem, 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:

$pageQuery = new WP_Query([
    'meta_query' => [
        'relation' => 'OR',
        ['key' => 'item_price', 'compare' => 'NOT EXISTS'], // this comes first!
        ['key' => 'item_price', 'compare' => 'EXISTS'],
    ],
    'order' => 'DESC',
    'orderby' => 'meta_value_num',
    'post_status' => 'publish',
    'post_type' => 'page',
    'posts_per_page' => 10,
]);
Paweł
źródło
1

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.

function addDefaultMetaValue($post_id) {
    add_post_meta($post_id, 'item_price', 0, true);
}
add_action('save_post', 'addDefaultMetaValue');

Jeśli używasz niestandardowego typu postu, zastąp go add_action('save_post', 'addDefaultMetaValue');przez add_action('save_post_{post_type}', 'addDefaultMetaValue');npadd_action('save_post_product', 'addDefaultMetaValue');

rjpedrosa
źródło
1

Miałem problem z liczbowymi meta wartościami i zwróciłem uwagę, że kolejność zapytania jest również ważna. Dla mnie NOT EXISTSzapytanie musi być pierwsze.

Przykład:

$query->set( 'orderby', 'meta_value_num' );
$query->set( 'meta_query', [
    'relation' => 'OR',
    [ 'key' => 'your_meta_name', 'compare' => 'NOT EXISTS' ],
    [
        'key' => 'your_meta_name',
        'compare' => 'EXISTS',
    ],
] );

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

KittMedia
źródło
1

Napotkałem również podobny problem i następujące rozwiązanie pomogło mi:

$args = array(
'post_type' => 'kosh_products',
'posts_per_page' => -1,
'meta_query' => array(
    'relation' => 'OR',
    'category_sort_order' => array(
        'key' => '_sort_order',
        'compare' => 'EXISTS'
    ),
    'category_sort_order_not_exists' => array(
        'key' => '_sort_order',
        'compare' => 'NOT EXISTS'
    ), 
),
'orderby' => array( 
    'category_sort_order' => 'ASC',
    'date' => 'ASC'
));
$query = new WP_Query( $args );

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 wprowadź opis zdjęcia tutaj

Ilya Kogan
źródło
0

Jest do tego możliwa orderbywartość meta_value.

$query = new WP_Query( array ( 
    'meta_key'   => 'your_keys_name',
    'orderby'    => 'meta_value',
    'order'      => 'DESC',
    'meta_query' => array( array(
         'key'     => 'your_meta_key',
         'value'   => '',
         'compare' => 'NOT EXISTS',
         // 'type'    => 'CHAR',
    ) )
) );

Jeśli masz wartości liczbowe, po prostu użyj meta_value_numzamiast tego.

Oświadczenie: To nie jest przetestowane, ale powinno działać. Chodzi o to, że musisz podać swoje meta_keyi keywartoś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 ...

kajzer
źródło
Dziękuję za odpowiedź. Sprawdź moje zaktualizowane pytanie. Nie jestem pewien, czy dobrze cię zrozumiałem.
powerbuoy
Nadal nie działałem, więc jeśli masz rozwiązanie, chciałbym wiedzieć, co robię źle. Ponadto ustawiam nagrodę za SO, jeśli chcesz ją odebrać: stackoverflow.com/questions/17016770/…
powerbuoy
1
Dwie rzeczy. '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 (przez meta_query) i wyklucza wszelkie posty, w których klucz nie istnieje (przez meta_key), co powoduje, że posty nie są wyświetlane. Jednak ta odpowiedź jest krokiem w kierunku czegoś, co przynajmniej słowa ;-).
binki
1
Och, co ciekawe, odpowiedź ta działa, jeśli po prostu dodać 'relation' => 'OR'do meta_query. Zwariowane rzeczy o_o.
binki
@binki Po prostu edytuj edycję mojego pytania i zmień bity, które Twoim zdaniem powinny zostać zmienione. To jest strona prowadzona przez społeczność :)
kaiser
0

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 ! = (' „) :

$query = new WP_Query( array ( 
    'orderby'    => 'meta_value_num',
    'order'      => 'DESC',
    'meta_query' => array( array(
         'key'     => 'item_price',
         'value'   => '',
         'compare' => '!=',
    ) )
) );

Też nie testowany, ale wydaje się, że warto spróbować :-).

Jon
źródło
1
Naprawdę nie mogę teraz tego przetestować, ale całkiem pewne, że zwróci tylko posty, w których ustawiono item_price, a nie jest to ''.
powerbuoy
0

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! :)

add_filter('posts_join_paged', 'edit_join', 999, 2);
add_filter('posts_orderby', 'edit_orderby', 999, 2);

/**
 * Edit join
 *
 * @param string $join_paged_statement
 * @param WP_Query $wp_query
 * @return string
 */
function edit_join($join_paged_statement, $wp_query)
{
    global $wpdb;
    if (
        !isset($wp_query->query)
        || $wp_query->is_page
        || $wp_query->is_admin
        || (isset($wp_query->query['post_type']) && $wp_query->query['post_type'] != 'my_custom_post_type')
    ) {
        return $join_paged_statement;
    }

    $join_to_add = "
        LEFT JOIN {$wpdb->prefix}postmeta AS my_custom_meta_key
            ON ({$wpdb->prefix}posts.ID = my_custom_meta_key.post_id
                AND my_custom_meta_key.meta_key = 'my_custom_meta_key')
    ";

    // Only add if it's not already in there
    if (strpos($join_paged_statement, $join_to_add) === false) {
        $join_paged_statement = $join_paged_statement . $join_to_add;
    }

    return $join_paged_statement;
}

/** 
 * Edit orderby
 *
 * @param string $orderby_statement
 * @param WP_Query $wp_query
 * @return string
 */
function edit_orderby($orderby_statement, $wp_query)
{
    if (
        !isset($wp_query->query)
        || $wp_query->is_page
        || $wp_query->is_admin
        || (isset($wp_query->query['post_type']) && $wp_query->query['post_type'] != 'my_custom_post_type')
    ) {
        return $orderby_statement;
    }

    $orderby_statement = "my_custom_meta_key.meta_value DESC";

    return $orderby_statement;
}
Scruffy Paws
źródło
Kod działa. Ale wartość meta_value jest traktowana jako ciąg. Tak więc 6 ma wyższą ocenę jako 50. Czy są możliwe modyfikacje, aby traktować je jak liczby?
Drivingralle
@Drivingralle cast(my_custom_meta_key.meta_value as unsigned) DESCpowinien załatwić sprawę ...
tfrommen
1
Dzięki @tfrommen. $orderby_statement = "cast(my_custom_meta_key.meta_value as unsigned) DESC";działa świetnie.
Drivingralle
0

To rozwiązanie działało dla mnie:

add_action( 'pre_get_posts', 'orden_portfolio' );
function orden_portfolio( $query ) {

    if( ! is_admin() ) {

        $query->set( 'orderby', 'meta_value_num' );
        $query->set( 'order', 'ASC' );
        $query->set( 'meta_query', [
            'relation' => 'OR',
            [ 
                'key' => 'ce_orden', 
                'compare' => 'NOT EXISTS' ],
            [
                'key' => 'ce_orden',
                'compare' => 'EXISTS',
            ],
        ] );

        return $query;

    }

}

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:

function custom_join($join) {
    global $wpdb;

    if( ! is_admin() ) {
        $join .= $wpdb->prepare(
        ' LEFT JOIN ' . $wpdb->postmeta . ' cpm ON cpm.post_id = ' . $wpdb->posts . '.ID AND cpm.meta_key = %s'
        , 'ce_orden' );
    }

    return $join;
}

add_filter('posts_join','custom_join');

function custom_orderby($orderby_statement){
    global $wpdb;

    if ( ! is_admin() ) {
        $orderby_statement = "CAST( COALESCE(cpm.meta_value,99999) as SIGNED INTEGER) ASC";
    }

    return $orderby_statement;
}

add_filter('posts_orderby','custom_orderby', 10, 2 ); 
jpussacq
źródło