Zapytanie, aby najpierw posortować listę według meta-klucza (jeśli istnieje) i wyświetlić pozostałe posty bez meta-klucza uporządkowane według tytułu

22

Pracuję nad niestandardowym szablonem strony z terminologią taksonomii, w której chcemy, aby elementy powiązane z terminem były sortowane według daty publikacji (niestandardowe pole daty) - i jeśli w tym samym dniu jest wiele pozycji (sformatowanych jak RRRR-MM- DD), aby następnie posortować je według tytułu, a na koniec posortować według tytułu, jeśli niestandardowe pole nie zostało wypełnione (starsze elementy).

Tak więc wypróbowałem go na sto różnych sposobów z WP_query i zwraca większość wyników, tak jak chcę, ale w tym przypadku zwraca tylko te elementy, które mają meta_klucz z data_publikacji. Wszystkie pozostałe elementy są ignorowane i nie są wyświetlane. Próbowałem meta_query przy użyciu relacji „lub” i porównałem data_opublikowania jako EXISTS i NOT EXISTS, ale to zwróciło dla mnie 0 wyników.

Ponadto witryna nadal działa w wersji 3.5.2 i nie chcą jej aktualizować.

Oto moje ostatnie zapytanie, które powoduje, że posty z polem niestandardowym data_publikacji są wyświetlane we właściwej kolejności:

$term = get_queried_object(); // find the term of the taxonomy page we are on
$wp_query = new WP_Query( array(
'post_type' => 'resource',
'tax_query' => array(
    array(
        'taxonomy' => 'resource_types',
        'field' => 'slug',
        'terms' => $term->name,
    )), 

'meta_key' => 'publication_date',
'orderby' => 'meta_value_num',
'order' => 'DESC',
'paged' => $paged,
'posts_per_page' => '10',
));

Próbowałem także użyć wpdb i uruchomić zapytanie SQL, ale tak naprawdę nie jestem pewien, jak to zrobić. Gdyby ktoś mógł mi pomóc, byłoby wspaniale!

Z góry dziękuję.

CSSgirl
źródło
Zaskakujące, że podejście meta_query nie zadziałało, ale z drugiej strony nie można uporządkować według wartości meta z meta_query bez ustawienia meta_key.
sanchothefat
Myślę, że to jest problem, który mam. W końcu udało mi się uruchomić meta kwerendę: 'meta_query' => array( 'relation' => 'OR', array( //check to see if date has been filled out 'key' => 'publication_date', 'compare' => '!=', 'value' => date('Y-m-d'), ), array( //if no date has been added show these posts too 'key' => 'publication_date', 'value' => date('Y-m-d'), 'compare' => 'NOT EXISTS' ) ),ale kolejność nie działa: \
CSSgirl
tak, zamawianie polega na tym, że meta_key jest ustawiony niestety poza tax_query. Moja odpowiedź poniżej może jednak pomóc.
sanchothefat

Odpowiedzi:

19

Dziękuję wszystkim za waszą pomoc!

Na koniec poniższe zapytanie dostarczyło mi pożądane wyniki - które miały najpierw wyświetlać i sortować posty według niestandardowego pola „data_publikacji” - sortowanie według daty, a jeśli było wiele takich samych dat (powiedzmy 4 oznaczone Czerwiec 2013), posortuje je według tytułu. Następnie, po przejściu przez wszystkie posty z wypełnioną datą publikacji, ponownie przejdzie przez pozostałe posty, alfabetycznie według tytułów.

Dzięki temu otrzymuję wyniki ustawione w tym samym zapytaniu i zachowuje moją paginację:

$term = get_queried_object();
the_post();
$wp_query = new WP_Query( array(
'post_type' => 'resource',
    'tax_query' => array(
        array(
            'taxonomy' => 'resource_types',
            'field' => 'slug',
            'terms' => $term->name,
        )),
 'meta_query' => array(
       'relation' => 'OR',
        array( //check to see if date has been filled out
                'key' => 'publication_date',
                'compare' => '=',
                'value' => date('Y-m-d')
            ),
          array( //if no date has been added show these posts too
                'key' => 'publication_date',
                'value' => date('Y-m-d'),
                'compare' => 'NOT EXISTS'
            )
        ),
'meta_key' => 'publication_date',
'orderby' => 'meta_value title',
'order' => 'ASC',
'paged' => $paged,
'posts_per_page' => '10',
));
CSSgirl
źródło
1
Ładny. Nigdy nie myślałem, żeby uruchomić dwa meta_queryna tym samym kluczu!
GhostToast,
5
Dla mnie (używając WordPress 4.1.1), jeśli ustawię meta_keygo automatycznie, nie będzie go zawierał nawet z NOT EXISTS. Naprawdę mam nadzieję, że robię coś źle.
Ryan Taylor
1
@RyanTaylor to samo tutaj - klucz meta_key nie może być ustawiony w zapytaniu, aby to zadziałało, ale wydaje się, że porządkuje poprawnie według wartości meta, nawet jeśli klucz meta nie jest ustawiony.
jammypeach 21.01.16
2
Jak powyższe komentarze, w przypadku WP 4.1+ usuń lub skomentuj 'meta_key' => 'publication_date',.
MikeiLL
7

Kilka lat później kod opublikowany przez CSSGirl nie działał dla mnie, ponieważ były posty, które nie miały meta-klucza lub meta-klucz był pusty, więc to właśnie musiałem zrobić, aby wszystkie posty były uporządkowane według daty i najpierw pokaż te z meta-kluczem:

$args          = array(
'post_type'   => $type,
'post_status' => 'publish',
'nopaging'    => TRUE,
'meta_query'  => array(
    'relation' => 'OR',
    array(
        'key'     => $meta_key,
        'compare' => 'NOT EXISTS',
    ),
    array(
        'relation' => 'OR',
        array(
            'key'   => $meta_key,
            'value' => 'on',
        ),
        array(
            'key'     => $meta_key,
            'value'   => 'on',
            'compare' => '!=',
        ),
    ),
),
'orderby'     => array( 'meta_value' => 'DESC', 'date' => 'DESC' ),
);
Ciprian Tepes
źródło
1

Myślę, że musisz zrobić 2 osobne pętle. Możesz łatwo przechwycić wszystkie posty znalezione w pierwszej pętli i łatwo wykluczyć je z drugiej pętli:

$found_posts = array();
while($loop->have_posts()): $loop->the_post();
    // loop stuff
    $found_posts[] = get_the_id();
endwhile;

wp_reset_query();

$args = array(
    // other args
    'post__not_in' => $found_posts,
);

Następnie uruchom drugą pętlę.

GhostToast
źródło
Próbuję tego teraz, dzięki. Powiadomi Cię, jeśli to zadziała!
CSSgirl,
1
zadziałało - ale złamało podział na strony - jakiś pomysł, jak to zrobić? Oto, jak teraz wygląda:echo paginate_links( array( 'base' => str_replace( $big, '%#%', esc_url( get_pagenum_link( $big ) ) ), 'format' => '?page=%#%', 'current' => max( 1, get_query_var('paged') ), 'total' => $publication_query->max_num_pages, 'prev_text' => __('Previous |'), 'next_text' => __('| Next'), ) );
CSSgirl
Hmm Nie o tym mogę myśleć.
GhostToast,
1

Czy istnieje powód, dla którego nie można wymusić istnienia meta-klucza public_date dla każdego postu z pustą wartością?

Więc w swoim save_postdziałaniu dodałeś / zaktualizowałeś meta klucz, niezależnie od tego, czy $_POSTwartość jest pusta, czy nie.

Będziesz musiał uruchomić skrypt aktualizacyjny, aby przejrzeć starsze posty i dodać klucz z pustą wartością, np .:

add_action( 'admin_init', 'update_old_posts' );
function update_old_posts() {
    if ( ! isset( $_GET[ 'update_old_posts' ] ) )
         return;

    foreach( get_posts() as $post ) {
        if ( false === get_post_meta( $post->ID, 'publication_date', true ) ) {
             update_post_meta( $post->ID, 'publication_date', '' );
             echo "Updated {$post->post_title} <br />";
        }
    }

    die;
}

Uruchom go, przeglądając http://example.com/wp-admin/?update_old_posts

Następnie możesz użyć tego samego zapytania, co masz. Możesz chcieć dodać dodatkowy filtr, aby umożliwić Ci porządkowanie według różnych kolumn w różnych kierunkach, sensowne byłoby dla mnie sortowanie według daty w porządku malejącym i tytułu w porządku rosnącym.

add_filter( 'posts_orderby', 'multicolumn_orderby', 10, 2 );
function multicolumn_orderby( $orderby, $query ) {
    global $wpdb;

    // check it's the right query
    if ( $query->get( 'meta_key' ) == 'publication_date' ) {
         $orderby = "$wpdb->postmeta.meta_value+0 DESC, $wpdb->posts.post_title ASC";
    }

    return $orderby;
}
sanchothefat
źródło
Hmm, nie myślałem o tym. Spróbuję i zobaczę, jak leci, dzięki!
CSSgirl,
0

Stworzyłem niestandardową klauzulę where. Testowałem go przy użyciu $wp_query->requesttuż przed moją główną pętlą, tak naprawdę nie znam dobrze SQL, ale wydawało się, że to działa.

add_action('pre_get_posts', 'add_trending_sort', 11, 1);
function add_trending_sort($query){
  if(!$query->is_main_query())
    return;

  //Overwrite query arguments
  $query->set('meta_query', array(
    array(
      'key' => 'TRENDING',
      //'value' => 'asdfasdf',//may need a value for older versions of WordPress
      'compare' => 'NOT EXISTS',
    )
  ));
  $query->set('orderby', 'meta_value_num date');
  $query->set('order', 'DESC');
}

add_filter('posts_where', 'add_trending_where');
function add_trending_where($where = ''){
  global $wpdb, $wp_query;
  if(!$wp_query->is_main_query())//Not sure if this really works.  Should be OK
    return $where;

  $where .= " OR ( $wpdb->postmeta.meta_key = 'TRENDING' )";

  // Don't run this twice
  remove_filter('posts_where', 'add_trending_where');

  return $where;
}

Alternatywnie, można ustawić comparesię 'EXISTS'i zmienić linię w add_trending_where do $where .= " OR ($wpdb->postmeta.post_id IS NULL)";. Wtedy wystarczy zmienić wartość klucza tylko w jednym miejscu. Ponownie wykonaj echo $wp_query->requesti baw się, jeśli chcesz to lepiej zrozumieć lub dostosować.

EDYCJA: Właśnie zauważyłem, że to nie działa, jeśli meta_keyjest ustawione w zapytaniu. Możesz użyć, $query->set('meta_key', NULL);jeśli musisz.

EDYCJA 2: Mam tę pracę z powyższą metodą. Z jakiegoś powodu nie było na początku (może ustawiono meta_key ... nie wiem).

add_action('pre_get_posts', 'add_trending_sort', 11, 1);
function add_trending_sort($query){
  // Bail if not the main "hidden" query, as opposed to a 'new WP_Query()' call
  if(!$query->is_main_query())
    return;

  // Set meta_query to get shares for orderby, and also get non-shared content.
  $query->set('meta_query', array(
    'relation' => 'OR',
    array(
      'key' => 'TRENDING',
      'compare' => 'NOT EXISTS',
    ),
    array(
      'key' => 'TRENDING',
      'compare' => 'EXISTS',
    )
  ));
  //$query->set('meta_key', NULL);
  $query->set('orderby', array('meta_value_num' => 'DESC', 'date' => 'DESC'));
}
Ryan Taylor
źródło