WP_Query può restituire i meta dei post in una singola richiesta?
Vorrei creare una wp_query che restituisca i meta dei post all'interno dell'array posts
.
$args = array (
'post_type' => 'page',
'meta_key' => 'someMetaKeyName',
);
// La Query
$query = new WP_Query( $args );
Questo restituisce qualcosa del genere:
Come si può vedere i post non hanno alcun meta dato, è possibile includere i meta dati nell'array restituito?
PS Non voglio query wp aggiuntive per ragioni di performance.

Di default, WP_Query
restituisce gli oggetti standard WP_Post
per i post interrogati. Credo che con una riscrittura intelligente e l'uso dei filtri forniti in WP_Query
sia possibile aggiungere oggetti all'array di oggetti WP_Post
restituiti.
Sarà performante? Secondo me, danneggerà maggiormente le prestazioni poiché sarà necessario unire i risultati nella query, dato che i campi personalizzati non sono salvati nella tabella wp_posts
, ma nella tabella wp_postmeta
.
Recuperare i meta dei post è molto veloce e non richiede un'istanza aggiuntiva di WP_Query
. Puoi semplicemente chiamare il campo personalizzato con get_post_meta()
. WordPress è stato molto attento quando sono stati introdotti i campi personalizzati. Hanno aggiunto una cache per memorizzarli, quindi che tu stia interrogando 1 o 100 campi personalizzati, stai colpendo il database una sola volta, in modo super veloce. Per un test completo e una spiegazione, vedi questo post che ho recentemente scritto sull'argomento.
Secondo me, la chiamata aggiuntiva al database e il tempo effettivo speso ne valgono la pena ed è più veloce che riscrivere WP_Query
in modo da includere i campi personalizzati nell'oggetto post standard restituito da $posts
.

OK, grazie, accetterò questa soluzione, ma per essere sincero è davvero una seccatura chiamare get_post_meta()
per ogni singolo post.. Preferirei che ci fosse un modo per memorizzare dati aggiuntivi direttamente nella tabella wp_posts
, o in una tabella correlata che non sia un incubo come wp_postsmeta
.

Beh, a dirla tutta, sia che chiami get_post_meta()
sia che lo faccia come oggetto post, dovrai chiamarlo per ogni post. È lo stesso con i tag template come the_content()
, devi chiamarlo per ogni post.

Questo significa che se devi mostrare 120 post avrai 120 query extra nella tua pagina?

Tutti i postdata vengono salvati in una cache, quindi non avrai query aggiuntive quando richiami i meta dei post

Recentemente ho avuto un problema simile, dovevo ottenere 7 metadati da un custom post type, ma anche filtrare i post in base a un pezzo di metadato.
Quindi ho creato la seguente query SQL, che uso spesso. Spero possa aiutare qualcun altro. Proverò a spiegarla al meglio delle mie capacità.
global $wpdb;
$pt = 'clients';
$mk = 'trainerid';
$mv = $pid;
$mk1 = 'email';
$mk2 = 'phone';
$mk3 = 'gender';
$mk4 = 'dob';
$mk5 = 'photo';
$mk6 = 'registrationts';
$mk7 = 'activationts';
$ord = 'p.post_name ASC';
$sql = "
SELECT p.ID, p.post_title AS fullname, pm1.meta_value AS email, pm2.meta_value AS phone, pm3.meta_value AS gender, pm4.meta_value AS dob, pm5.meta_value AS photo, pm6.meta_value AS regts, pm7.meta_value AS actemailts
FROM {$wpdb->posts} p
LEFT JOIN {$wpdb->postmeta} pm ON pm.post_id = p.ID
AND pm.meta_key = '{$mk}'
LEFT JOIN {$wpdb->postmeta} pm1 ON pm1.post_id = p.ID
AND pm1.meta_key = '{$mk1}'
LEFT JOIN {$wpdb->postmeta} pm2 ON pm2.post_id = p.ID
AND pm2.meta_key = '{$mk2}'
LEFT JOIN {$wpdb->postmeta} pm3 ON pm3.post_id = p.ID
AND pm3.meta_key = '{$mk3}'
LEFT JOIN {$wpdb->postmeta} pm4 ON pm4.post_id = p.ID
AND pm4.meta_key = '{$mk4}'
LEFT JOIN {$wpdb->postmeta} pm5 ON pm5.post_id = p.ID
AND pm5.meta_key = '{$mk5}'
LEFT JOIN {$wpdb->postmeta} pm6 ON pm6.post_id = p.ID
AND pm6.meta_key = '{$mk6}'
LEFT JOIN {$wpdb->postmeta} pm7 ON pm7.post_id = p.ID
AND pm7.meta_key = '{$mk7}'
WHERE pm.meta_value = '{$mv}'
AND p.post_type = '{$pt}'
AND p.post_status NOT IN ('draft','auto-draft')
ORDER BY {$ord}
";
$clients = $wpdb->get_results( $wpdb->prepare( $sql ), OBJECT );
Per prima cosa ottengo le funzioni del database di WordPress con global $wpdb. Poi imposto il tipo di post con $pt. Per ottenere il post corretto che corrisponde a un valore specifico in post_meta, imposto $mk (meta_key)
Poi imposto la variabile $mv (meta_value) (in questo caso il meta value corrisponde a un postid)
$mk1-$mk7 sono i meta_key che voglio ottenere da ogni post. (Recupererò i valori nella select)
Rendo anche l'ordinamento una variabile, impostando $ord
La select funziona così: Seleziono l'ID del post e il post_title dalla tabella POSTS o 'p.'
Poi seleziono tutti i metadati di cui ho bisogno usando pm1. -> pm7 e prendendo meta_value rinominandoli (AS) per renderli più leggibili quando recupero i dati dal mio oggetto.
Creo un LEFT JOIN per i metadati che devono corrispondere al post. (pm)
Creo 7 left join per ognuno dei metadati che devo recuperare. (pm1-pm7)
La clausola WHERE si basa sul primo LEFT JOIN (pm) così che sappia che voglio solo i post dove i metadati corrispondono.
Aggiungo anche un 'AND' per il tipo di post, e per gli stati del post che non sono bozze. (quindi solo post pubblicati)
Infine aggiungo la clausola 'order by'.
Questa query è veloce e sfrutta gli indici built-in di WordPress, quindi sembra efficiente.
Non so se esiste qualcosa di meglio di questo, ma se c'è, mi piacerebbe usarlo.
Spero sia utile.
Marcus

Questa domanda ha più di 1 anno, ma ho lo stesso problema, e qui c'è una funzione che aggiungerà ogni meta_value e meta_key all'oggetto $wp_query,
invece di interrogare ogni post meta nel ciclo while, questa funzione farà una query extra esempio:
"SELECT meta_key, meta_value, post_id FROM $wpdb->postmeta WHERE post_id IN (1,2,3,4,5...)"
dove (1,2,3,4,5...) sono gli ID dei post attualmente interrogati da $wp_query
if(!function_exists('add_query_meta')) {
function add_query_meta($wp_query = "") {
//Ritorna nel caso in cui wp_query sia vuoto o postmeta esista già
if( (empty($wp_query)) || (!empty($wp_query) && !empty($wp_query->posts) && isset($wp_query->posts[0]->postmeta)) ) { return $wp_query; }
$sql = $postmeta = '';
$post_ids = array();
$post_ids = wp_list_pluck( $wp_query->posts, 'ID' );
if(!empty($post_ids)) {
global $wpdb;
$post_ids = implode(',', $post_ids);
$sql = "SELECT meta_key, meta_value, post_id FROM $wpdb->postmeta WHERE post_id IN ($post_ids)";
$postmeta = $wpdb->get_results($sql, OBJECT);
if(!empty($postmeta)) {
foreach($wp_query->posts as $pKey => $pVal) {
$wp_query->posts[$pKey]->postmeta = new StdClass();
foreach($postmeta as $mKey => $mVal) {
if($postmeta[$mKey]->post_id == $wp_query->posts[$pKey]->ID) {
$newmeta[$mKey] = new stdClass();
$newmeta[$mKey]->meta_key = $postmeta[$mKey]->meta_key;
$newmeta[$mKey]->meta_value = maybe_unserialize($postmeta[$mKey]->meta_value);
$wp_query->posts[$pKey]->postmeta = (object) array_merge((array) $wp_query->posts[$pKey]->postmeta, (array) $newmeta);
unset($newmeta);
}
}
}
}
unset($post_ids); unset($sql); unset($postmeta);
}
return $wp_query;
}
}
Un "postmeta" aggiuntivo verrà scritto per ogni $wp_query->posts[$i]
$wp_query->posts[0]->postmeta
Esempio con 'someMetaKeyName' non dimenticare di inserire
add_query_meta()
nel tuo file function.php del tema
$args = array (
'post_type' => 'page',
'meta_key' => 'someMetaKeyName',
);
// La Query
$query = new WP_Query( $args );
if($wp_query->have_posts()) {
$wp_query = add_query_meta($wp_query);
$i = 0;
while($wp_query->have_posts()) {
$wp_query->the_post();
$post_id = get_the_id();
//Ottieni $someMetaKeyName nel post corrente
foreach($wp_query->posts[$i]->postmeta as $k => $v) {
switch($v->meta_key) {
case('someMetaKeyName') : {
$someMetaKeyName = $v->meta_value;
break;
}
}
}
//Il tuo codice qui
//Esempio
echo isset($someMetaKeyName) ? '<h3>'.$someMetaKeyName.'</h3>' : '';
$i++;
}
}

Avevo bisogno di un solo valore extra post_meta (il template nel mio caso) e sono riuscito a ottenere qualcosa di simile a quello che cerchi utilizzando get_pages
con un parametro meta_key
.
$args = [
'parent' => $post_id, // nel mio esempio, trovo i figli di un post specifico
'meta_key' => '_wp_page_template', // cerco il template usato dal post
];
$posts = get_pages($args);
E questo restituisce un array di oggetti post come questo
Array
(
[0] => WP_Post Object
(
[ID] => 22765
[post_author] => 173
[post_date] => 2022-03-14 21:11:18
...
[meta_key] => _wp_page_template
[meta_value] => template-module-content.php // <-- ECCOLO!
...
)
E poi puoi accedere a un meta_value
in questo modo
echo $posts[0]->meta_value;
// restituisce 'template-module-content.php' nel mio caso
Ammetto che potrebbe essere un caso d'uso limitato, ma era esattamente quello che mi serviva

Qual è il motivo per cui hai usato sia meta_key
che meta_query[]['key']
?

No, questo non funziona e restituisce l'array di post senza i meta associati.
