Query per ordinare una lista per chiave meta (se esiste) e mostrare i post rimanenti senza chiave meta ordinati per titolo

17 dic 2013, 18:06:39
Visualizzazioni: 54.2K
Voti: 32

Sto lavorando su un template di pagina per termini di tassonomia personalizzata dove vogliamo che gli elementi collegati al termine siano ordinati per data di pubblicazione (campo data personalizzato) - e se ci sono più elementi nello stesso giorno (formattato come AAAA-MM-GG) ordinarli per titolo, e infine ordinare per titolo se il campo personalizzato non è stato compilato (elementi più vecchi).

Ho provato in centinaia di modi diversi con WP_Query e restituisce la maggior parte dei risultati come li voglio - ma in questo caso restituisce solo gli elementi che hanno la meta_key di publication_date. Tutti gli altri elementi vengono ignorati e non visualizzati. Ho provato una meta_query usando una relazione "or" e confrontato publication_date come EXISTS e NOT EXISTS, ma questo mi ha restituito 0 risultati.

Inoltre, il sito sta ancora eseguendo la versione 3.5.2 e non vogliono aggiornare.

Ecco la mia query più recente che mi restituisce i post che hanno il campo personalizzato publication_date visualizzato nell'ordine corretto:

$term = get_queried_object(); // trova il termine della pagina di tassonomia in cui ci troviamo
$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',
));

Ho anche provato a utilizzare wpdb ed eseguire una query SQL, ma non sono sicuro di come ottenere quello che voglio in quel modo. Se qualcuno potesse aiutarmi sarebbe fantastico!

Grazie in anticipo.

3
Commenti

Sorpreso che l'approccio meta_query non abbia funzionato, ma d'altra parte non puoi ordinare per meta value con una meta_query senza aver impostato il meta_key.

sanchothefat sanchothefat
17 dic 2013 18:54:33

Penso che sia il problema che sto avendo. Alla fine sono riuscito a far funzionare una meta query: `'meta_query' => array( 'relation' => 'OR', array( //controlla se la data è stata inserita 'key' => 'publication_date', 'compare' => '!=', 'value' => date('Y-m-d'), ), array( //se nessuna data è stata aggiunta mostra anche questi post 'key' => 'publication_date', 'value' => date('Y-m-d'), 'compare' => 'NOT EXISTS' )

    ),` ma l'ordinamento non funziona :\
CSSgirl CSSgirl
17 dic 2013 19:01:23

sì, purtroppo l'ordinamento si basa sul meta_key impostato al di fuori del tax_query. Comunque la mia risposta qui sotto potrebbe aiutare.

sanchothefat sanchothefat
18 dic 2013 18:09:05
Tutte le risposte alla domanda 5
5
25

Grazie a tutti per il vostro aiuto!

Alla fine la query qui sotto mi ha dato i risultati che desideravo - ovvero mostrare e ordinare i post prima in base a un campo personalizzato "publication_date", ordinando per data, e se c'erano più post con la stessa data (ad esempio, 4 impostati su giugno 2013), li ordinava per titolo. Poi, dopo aver esaminato tutti i post che avevano la Data di Pubblicazione compilata, ripeteva il ciclo per i post rimanenti, in ordine alfabetico per titolo.

Questo mi permette di ottenere i risultati in un'unica query e mantiene la mia paginazione:

$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( //controlla se la data è stata compilata
                'key' => 'publication_date',
                'compare' => '=',
                'value' => date('Y-m-d')
            ),
          array( //se nessuna data è stata aggiunta mostra anche questi post
                '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 dic 2013 19:00:10
Commenti

Bello. Non avevo mai pensato di eseguire due meta_query sulla stessa chiave!

GhostToast GhostToast
19 dic 2013 18:13:05

Per me (usando WordPress 4.1.1), se imposto meta_key automaticamente non lo include anche con NOT EXISTS. Spero davvero di star facendo qualcosa di sbagliato.

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

@RyanTaylor idem qui - meta_key non deve essere impostato nella query perché funzioni, ma sembra ordinare correttamente per valore meta anche quando meta key non è impostata.

jammypeach jammypeach
21 gen 2016 12:50:50

Come nei commenti precedenti, per WP 4.1+ rimuovi o commenta 'meta_key' => 'publication_date',.

MikeiLL MikeiLL
14 lug 2016 08:35:29

Letteralmente tutto quello che ho dovuto fare è stato rimuovere la meta key. Tante risposte inutili su stackoverflow ma grazie mille!!

Jacob Raccuia Jacob Raccuia
11 lug 2020 07:34:55
2
18

Alcuni anni dopo, il codice pubblicato da CSSGirl non funzionava per me perché c'erano alcuni articoli che non avevano la meta chiave o la meta chiave era vuota, quindi ho dovuto fare così per avere tutti gli articoli ordinati per data e mostrare prima quelli con un valore nella meta chiave:

$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
Commenti

grazie, questo mi è stato molto utile.

Dragi Postolovski Dragi Postolovski
8 set 2021 16:39:45

Anche per me, mi stavo mordendo i denti, ora funziona perfettamente, GRAZIE!

physalis physalis
27 giu 2023 14:39:05
3

Penso che tu debba fare 2 loop separati. Puoi catturare tutti i post trovati nel primo loop ed escluderli facilmente dal loop secondario:

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

wp_reset_query();

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

Poi esegui il tuo secondo loop.

17 dic 2013 18:16:17
Commenti

Lo sto provando ora, grazie. Ti farò sapere se funziona!

CSSgirl CSSgirl
17 dic 2013 19:00:47

questo ha funzionato - ma ha rotto la paginazione - hai idea di come farlo funzionare? Ecco come appare ora: 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 dic 2013 19:11:19

Mmm. Non che mi venga in mente.

GhostToast GhostToast
17 dic 2013 19:18:11
1

C'è qualche motivo per cui non potresti imporre che la chiave meta publication_date esista per ogni articolo anche solo con un valore vuoto?

Quindi nella tua azione save_post aggiungeresti/aggiorneresti la chiave meta indipendentemente dal fatto che il valore $_POST sia vuoto o meno.

Dovresti eseguire uno script di aggiornamento per scorrere i tuoi articoli più vecchi e aggiungere la chiave con un valore vuoto, ad esempio:

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

    die;
}

Eseguilo navigando su http://example.com/wp-admin/?update_old_posts

Quindi puoi usare la stessa query che hai. Potresti voler aggiungere un filtro extra per permetterti di ordinare per colonne diverse in direzioni diverse, non avrebbe senso per me ordinare per data in ordine decrescente e per titolo in ordine crescente.

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

    // verifica che sia la query corretta
    if ( $query->get( 'meta_key' ) == 'publication_date' ) {
         $orderby = "$wpdb->postmeta.meta_value+0 DESC, $wpdb->posts.post_title ASC";
    }

    return $orderby;
}
17 dic 2013 19:25:32
Commenti

Hmm, non ci avevo pensato. Proverò a fare così e vedrò come va, grazie!

CSSgirl CSSgirl
17 dic 2013 20:24:44
0

Ho creato una clausola WHERE personalizzata. L'ho testata usando $wp_query->request appena prima del mio loop principale, non conosco molto bene SQL, ma questo sembra aver fatto funzionare le cose.

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

  // Sovrascrivi gli argomenti della query
  $query->set('meta_query', array(
    array(
      'key' => 'TRENDING',
      //'value' => 'asdfasdf', //potrebbe essere necessario un valore per versioni più vecchie di 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()) //Non sono sicuro che funzioni veramente. Dovrebbe essere OK
    return $where;

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

  // Non eseguire questo due volte
  remove_filter('posts_where', 'add_trending_where');

  return $where;
}

In alternativa, potresti impostare compare su 'EXISTS' e cambiare la riga in add_trending_where con $where .= " OR ($wpdb->postmeta.post_id IS NULL)";. Così dovresti cambiare il valore della chiave solo in un posto. Ancora una volta, fai echo di $wp_query->request e sperimenta se vuoi capire meglio o modificare questo codice.

MODIFICA: Ho appena notato che questo non funziona se meta_key è impostato nella query. Potresti usare $query->set('meta_key', NULL); se necessario.

MODIFICA 2: Ho fatto funzionare questo con il metodo sopra. Per qualche motivo all'inizio non funzionava (forse meta_key era impostato... non lo so).

add_action('pre_get_posts', 'add_trending_sort', 11, 1);
function add_trending_sort($query){
  // Esci se non è la query principale "nascosta", a differenza di una chiamata 'new WP_Query()'
  if(!$query->is_main_query())
    return;

  // Imposta meta_query per ottenere le condivisioni per orderby, e anche contenuti non condivisi.
  $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