Query per ordinare una lista per chiave meta (se esiste) e mostrare i post rimanenti senza chiave meta ordinati per titolo
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.

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',
));

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

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.

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

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

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' ),
);

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.

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'),
) );

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;
}

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'));
}
