Interogare pentru sortarea unei liste după meta key întâi (dacă există) și afișarea postărilor rămase fără meta key ordonate după titlu

17 dec. 2013, 18:06:39
Vizualizări: 54.2K
Voturi: 32

Lucrez la un șablon pentru o pagină de taxonomie personalizată unde dorim ca elementele conectate la termen să fie sortate după o dată de publicare (câmp de dată personalizat) - și dacă există mai multe elemente în aceeași zi (formatate ca YYYY-MM-DD) să fie apoi sortate după titlu, iar în final să sorteze după titlu dacă câmpul personalizat nu a fost completat (elementele mai vechi).

Așadar, am încercat în sute de moduri diferite cu WP_Query și returnează majoritatea rezultatelor așa cum doresc - dar în acest caz returnează doar elementele care au meta_key-ul publication_date. Toate celelalte elemente sunt ignorate și nu sunt afișate. Am încercat o meta_query folosind o relație "or" și am comparat publication_date ca EXISTS și NOT EXISTS, dar asta mi-a returnat 0 rezultate.

De asemenea, site-ul rulează încă versiunea 3.5.2 și nu doresc să facă upgrade.

Iată cea mai recentă interogare care îmi aduce postările care au câmpul personalizat publication_date afișat în ordinea corectă:

$term = get_queried_object(); // găsește termenul paginii de taxonomie pe care ne aflăm
$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',
));

Am încercat și să folosesc wpdb și să rulez o interogare SQL, dar chiar nu sunt sigur cum să realizez ceea ce vreau făcând asta. Dacă cineva m-ar putea ajuta ar fi minunat!

Mulțumesc anticipat.

3
Comentarii

Sunt surprins că abordarea cu meta_query nu a funcționat, dar din nou, nu poți folosi orderby cu o valoare meta fără a avea meta_key setat.

sanchothefat sanchothefat
17 dec. 2013 18:54:33

Cred că asta e problema pe care o am. În final am reușit să fac să funcționeze un meta_query: `'meta_query' => array( 'relation' => 'OR', array( //verifică dacă data a fost completată 'key' => 'publication_date', 'compare' => '!=', 'value' => date('Y-m-d'), ), array( //dacă nu a fost adăugată nicio dată, afișează și aceste articole 'key' => 'publication_date', 'value' => date('Y-m-d'), 'compare' => 'NOT EXISTS' )

    ),` dar ordonarea nu funcționează :\
CSSgirl CSSgirl
17 dec. 2013 19:01:23

da, din păcate ordonarea se bazează pe meta_key setat în afara tax_query. Totuși, răspunsul meu de mai jos ar putea ajuta.

sanchothefat sanchothefat
18 dec. 2013 18:09:05
Toate răspunsurile la întrebare 5
5
25

Mulțumesc tuturor pentru ajutor!

În final, interogarea de mai jos mi-a oferit rezultatele dorite - anume să afișez și să ordonez postările după un câmp personalizat "publication_date" mai întâi - sortând după dată, iar dacă există mai multe cu aceeași dată (de exemplu, 4 marcate cu iunie 2013), să le ordonez acestea după titlu. Apoi, după ce parcurge toate postările care au completat câmpul Publication Date, va parcurge din nou postările rămase, ordonate alfabetic după titlu.

Această soluție obține setul de rezultate într-o singură interogare și păstrează paginarea:

$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( //verifică dacă data a fost completată
                'key' => 'publication_date',
                'compare' => '=',
                'value' => date('Y-m-d')
            ),
          array( //dacă nu există dată adăugată, afișează și aceste postări
                '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',
));
18 dec. 2013 19:00:10
Comentarii

Fain. Niciodată nu m-am gândit să rulez două meta_query pe aceeași cheie!

GhostToast GhostToast
19 dec. 2013 18:13:05

Pentru mine (folosind WordPress 4.1.1), dacă setez meta_key automat nu-l include chiar și cu NOT EXISTS. Chiar sper că fac ceva greșit.

Ryan Taylor Ryan Taylor
25 mar. 2015 00:59:59

@RyanTaylor la fel și la mine - meta_key nu trebuie setat în interogare pentru ca asta să funcționeze, dar se pare că ordonează corect după valoarea meta chiar și când cheia meta nu este setată.

jammypeach jammypeach
21 ian. 2016 12:50:50

Conform comentariilor de mai sus, pentru WP 4.1+ eliminați sau comentați 'meta_key' => 'publication_date',.

MikeiLL MikeiLL
14 iul. 2016 08:35:29

Literalmente tot ce a trebuit să fac a fost să elimin meta key-ul. Multe răspunsuri nefolositoare pe stackoverflow, dar îți mulțumesc!!

Jacob Raccuia Jacob Raccuia
11 iul. 2020 07:34:55
2
18

La câțiva ani mai târziu, codul postat de CSSGirl nu a funcționat pentru mine deoarece existau unele articole care nu aveau cheia meta sau cheia meta era goală, așa că iată ce a trebuit să fac pentru a avea toate articolele ordonate după dată și pentru a afișa mai întâi cele cu o valoare a cheii meta:

$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' ),
);
26 feb. 2016 18:27:56
Comentarii

mulțumesc, asta m-a ajutat foarte mult.

Dragi Postolovski Dragi Postolovski
8 sept. 2021 16:39:45

La fel și pentru mine, îmi râdeam nervos dinții, acum funcționează perfect, MULȚUMESC!

physalis physalis
27 iun. 2023 14:39:05
3

Cred că ar trebui să folosești două bucle separate. Poți captura toate articolele găsite în prima buclă și apoi să le excludi ușor din a doua buclă:

$found_posts = array();
while($loop->have_posts()): $loop->the_post();
    // conținutul buclei
    $found_posts[] = get_the_id();
endwhile;

wp_reset_query();

$args = array(
    // alți parametri
    'post__not_in' => $found_posts,
);

Apoi poți rula a doua buclă.

17 dec. 2013 18:16:17
Comentarii

Încerc asta acum, mulțumesc. O să te anunț dacă funcționează!

CSSgirl CSSgirl
17 dec. 2013 19:00:47

a funcționat - dar a stricat paginarea - ai vreo idee cum să rezolvăm asta? Iată cum arată acum: 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 CSSgirl
17 dec. 2013 19:11:19

Hmm. Nu îmi vine în minte nimic acum.

GhostToast GhostToast
17 dec. 2013 19:18:11
1

Există vreun motiv pentru care nu ai putea impune ca cheia meta publication_date să existe pentru fiecare articol, chiar și cu o valoare goală?

Deci în acțiunea ta save_post ai adăuga/actualiza cheia meta indiferent dacă valoarea din $_POST este goală sau nu.

Ar trebui să rulezi un script de actualizare pentru a parcurge articolele mai vechi și a adăuga cheia cu o valoare goală, de exemplu:

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 "Actualizat {$post->post_title} <br />";
        }
    }

    die;
}

Rulează-l accesând http://example.com/wp-admin/?update_old_posts

Apoi poți folosi aceeași interogare pe care o ai. Poate dorești să adaugi un filtru suplimentar pentru a putea ordona după diferite coloane în direcții diferite, ar avea sens să sortezi după dată în ordine descrescătoare și după titlu în ordine crescătoare.

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

    // verifică dacă este interogarea corectă
    if ( $query->get( 'meta_key' ) == 'publication_date' ) {
         $orderby = "$wpdb->postmeta.meta_value+0 DESC, $wpdb->posts.post_title ASC";
    }

    return $orderby;
}
17 dec. 2013 19:25:32
Comentarii

Hmm, nu m-am gândit la asta. O să încerc și voi vedea cum merge, mulțumesc!

CSSgirl CSSgirl
17 dec. 2013 20:24:44
0

Am creat o clauză WHERE personalizată. Am testat-o folosind $wp_query->request chiar înainte de bucla mea principală, nu cunosc foarte bine SQL, dar acest lucru a funcționat.

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

  //Suprascrie argumentele interogării
  $query->set('meta_query', array(
    array(
      'key' => 'TRENDING',
      //'value' => 'asdfasdf',//poate fi necesară o valoare pentru versiunile mai vechi de 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())//Nu sunt sigur dacă funcționează cu adevărat. Ar trebui să fie OK
    return $where;

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

  // Nu rula acest cod de două ori
  remove_filter('posts_where', 'add_trending_where');

  return $where;
}

Alternativ, ai putea seta compare la 'EXISTS' și să schimbi linia din add_trending_where în $where .= " OR ($wpdb->postmeta.post_id IS NULL)";. Atunci ar trebui să modifici valoarea cheii doar într-un singur loc. Din nou, folosește $wp_query->request și experimentează dacă vrei să înțelegi mai bine sau să ajustezi acest lucru.

EDIT: Tocmai am observat că acest lucru nu funcționează dacă meta_key este setat în interogare. Ai putea folosi $query->set('meta_key', NULL); dacă este necesar.

EDIT 2: Am reușit să fac acest lucru să funcționeze cu metoda de mai sus. Din nu știu ce motiv, nu a funcționat la început (poate meta_key era setat... nu știu).

add_action('pre_get_posts', 'add_trending_sort', 11, 1);
function add_trending_sort($query){
  // Renunță dacă nu este interogarea principală "ascunsă", spre deosebire de un apel 'new WP_Query()'
  if(!$query->is_main_query())
    return;

  // Setează meta_query pentru a obține share-uri pentru orderby și, de asemenea, conținut nepartajat.
  $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'));
}
25 mar. 2015 02:08:04