Posso escludere un articolo tramite meta key usando la funzione pre_get_posts?
Vedo che molte persone preferiscono usare l'hook pre_get_posts
invece di query_posts
. Il codice seguente funziona e mostra tutti i post che hanno la meta key "featured"
function show_featured_posts ( $query ) {
if ( $query->is_main_query() ) {
$query->set( 'meta_key', 'featured' );
$query->set( 'meta_value', 'yes' );
}
}
add_action( 'pre_get_posts', 'show_featured_posts' );
Ma voglio che i post che hanno la meta_key 'featured
' vengano esclusi dalla query principale. C'è un modo semplice per farlo?

Vedo che molte persone preferiscono usare l'hook pre_get_posts invece di query_posts
Evviva!
Quindi pre_get_posts
filtra un WP_Query
object il che significa che qualsiasi cosa tu possa fare con query_posts()
puoi farla tramite $query->set()
e $query->get()
. In particolare possiamo utilizzare l'attributo meta_query
(vedi Codex):
$meta_query = array(
array(
'key'=>'featured',
'value'=>'yes',
'compare'=>'!=',
),
);
$query->set('meta_query',$meta_query);
Ma... questo sostituisce la 'meta query' originale (se ne aveva una). Quindi a meno che tu non voglia sostituire completamente la meta query originale, suggerisco:
//Ottieni la meta query originale
$meta_query = $query->get('meta_query');
//Aggiungi la nostra meta query alle meta query esistenti
$meta_query[] = array(
'key'=>'featured',
'value'=>'yes',
'compare'=>'!=',
);
$query->set('meta_query',$meta_query);
In questo modo aggiungiamo la nostra meta query insieme a quelle esistenti.
Potresti voler/non voler impostare la proprietà relation
di $meta_query
a AND
o OR
(per restituire post che soddisfano tutte, o almeno una, delle meta query).
* Nota: Questo tipo di query restituirà post con la meta key 'featured', ma il cui valore non è yes
. Non includerà post dove la meta key 'featured' non esiste. Sarai in grado di farlo nella versione 3.5.

Quindi non c'è modo di verificare se un meta_key per un post esiste o no / è vuoto o no? Dovrò aspettare la 3.5. allora. Grazie per la tua risposta.

Creerò semplicemente una meta box con opzioni Sì
e No
e 'No' sarà selezionato di default. Quando voglio mettere in evidenza un post selezionerò Sì
. Tuttavia, voglio che gli ultimi 5 post rimangano in evidenza e gli altri vengano visualizzati nella query principale. Non voglio tornare indietro e cambiare la selezione ogni volta, quindi devo trovare un modo per escludere solo i 5 post più recenti. Vedo molte domande simili su stackexchange e dovrebbe esserci un modo semplice per gestire questi post in evidenza. (un modo che non influisca sulle prestazioni generali, non crei molte query o non richieda query SQL miste)

BTW non sono sicuro che sia una buona idea creare un meta_key aggiuntivo con valore Sì
o No
per tutti i post. Sarebbe bello escludere quei post che semplicemente non hanno la chiave featured
.

Questa funzione ha smesso di funzionare sul mio sito dopo l'aggiornamento a PHP 7, generando un errore Uncaught Error: [] operator not supported for strings
poiché l'originale meta_query
risultava null. Puoi risolvere il problema facendo fallback a un array vuoto se non esiste, sostituendo $meta_query = $query->get('meta_query');
con $meta_query = ( is_array( $query->get('meta_query') ) ) ? $query->get('meta_query') : [];
.

Voglio condividere la mia soluzione temporanea per i post in evidenza nel caso possa essere utile ad altri. Non utilizzo l'hook pre_get_posts
qui, ma nemmeno query_posts
. Il problema è che devo lavorare con la query principale e devo eseguire una parte di query SQL.
Sarei felice se degli esperti potessero controllare il codice e farmi sapere se va bene e non causerà problemi di prestazioni. Sarebbe anche fantastico se qualcuno avesse un approccio migliore e lo condividesse con noi.
Creare la query per i post in evidenza
<?php
$featured_query = new WP_query( array(
'meta_key' =>'featured',
'meta_value' =>'yes',
'posts_per_page' => 5,
'no_found_rows' => true
)
);
while ($featured_query->have_posts()) :
$featured_query->the_post();
//Roba...
endwhile;
wp_reset_postdata();
?>
Creare la query principale, escludere i post che hanno il meta_key featured, limitare l'esclusione ai 5 post più recenti e mostrare tutti gli altri.
<?php
$excludeposts = $wpdb->get_col( "SELECT post_id FROM $wpdb->postmeta WHERE meta_key = 'featured' AND meta_value != '' ORDER BY post_id DESC LIMIT 0, 5" );
$main_query = new WP_Query( array(
'post__not_in' => $excludeposts,
'paged' => $paged
)
);
while ($main_query->have_posts()) :
$main_query->the_post();
//Roba...
endwhile;
?>

In risposta a @Carlisle, se vuoi escludere i 5 post più recenti contrassegnati come in evidenza, potresti fare quanto segue. Modifica posts_per_page con il numero di post che vuoi escludere e meta_query con il modo in cui stai designando la categoria in evidenza.
function cmp_exclude_featured_posts($query) {
$exclude = array(); //Crea un array vuoto per gli ID dei post da escludere
if ( $query->is_main_query() ) {
$featured = get_posts(array(
'post_type' => 'post',
'meta_query' => array(
array(
'key' => 'featured',
'value' => '1',
'compare' => '==',
),
),
'posts_per_page' => 2
));
foreach($featured as $hide) {
$exclude[] = $hide->ID;
}
$query->set('post__not_in', $exclude);
}
}
add_filter( 'pre_get_posts', 'cmp_exclude_featured_posts' );
