Obținerea tuturor valorilor pentru o cheie de câmp personalizat (cross-post)
Știu cum să obțin valoarea unui câmp personalizat pentru un articol specific.
get_post_meta($post_id, $key, $single);
Ceea ce am nevoie este să obțin toate valorile asociate cu o cheie specifică de câmp personalizat, din toate articolele.
Știe cineva o modalitate eficientă de a face acest lucru? Nu aș vrea să parcurg toate ID-urile articolelor din baza de date.
Exemplu:
4 articole, toate cu valori diferite pentru un câmp personalizat numit 'Mood'. 2 articole au valoarea 'fericit', 1 articol are 'furios' și 1 articol are 'trist'
Vreau să afișez: în toate articolele avem: doi autori fericiți, unul furios și unul trist.
Dar pentru MULTE articole.
Ceea ce caut este fie:
- o funcție WP pentru a obține acest lucru. sau
- o interogare personalizată pentru a obține acest lucru cât mai eficient posibil.

O abordare posibilă ar fi să folosești una dintre metodele helper din clasa WPDB pentru a face o interogare mai rafinată bazată pe meta date.
Folosind funcția $wpdb
get_col
este posibil să obții un array simplu și plat cu date.
Iată o funcție exemplu care interoghează baza de date pentru toate articolele de un anumit tip, cu un anumit status și o anumită cheie meta (sau câmp personalizat pentru cei mai puțin tehnici).
function get_meta_values( $meta_key = '', $post_type = 'post', $post_status = 'publish' ) {
global $wpdb;
if( empty( $meta_key ) )
return;
$meta_values = $wpdb->get_col( $wpdb->prepare( "
SELECT pm.meta_value FROM {$wpdb->postmeta} pm
LEFT JOIN {$wpdb->posts} p ON p.ID = pm.post_id
WHERE pm.meta_key = %s
AND p.post_type = %s
AND p.post_status = %s
", $meta_key, $post_type, $post_status ) );
return $meta_values;
}
De exemplu, dacă ai dori să afli care articole au o cheie meta rating, pentru tipul de articol movies și să stochezi această informație într-o variabilă, un exemplu de apel ar fi.
$movie_ratings = get_meta_values( 'rating', 'movies' );
Dacă ai dori să faci ceva mai mult decât să afișezi aceste date pe ecran, funcția PHP implode
poate transforma rapid array-ul într-un șir de caractere.
// Afișează valorile meta separate de un line break
echo implode( '<br />', get_meta_values( 'YOURKEY' ));
Poți folosi și datele returnate pentru a calcula câte articole au anumite valori meta prin iterarea (buclă) peste datele returnate și construirea unui array cu numărătoarea, de exemplu.
$movie_ratings = get_meta_values( 'rating', 'movies' );
if( !empty( $movie_ratings ) ) {
$num_of_ratings = [];
foreach( $movie_ratings as $meta_value ) {
$num_of_ratings[$meta_value] = isset( $num_of_ratings[$meta_value] ) ? $num_of_ratings[$meta_value] + 1 : 1;
}
}
// Afișează numărul de rating-uri
printf( '<pre>%s</pre>', print_r( $num_of_ratings ) );
/*
Output:
Array(
[5] => 10
[9] => 2
)
adică sunt 10 filme cu rating 5 și 2 filme cu rating 9.
*/
Această logică poate fi aplicată la diverse tipuri de date și extinsă pentru a funcționa în diferite moduri. Sper că exemplele mele au fost utile și suficient de simple de urmărit.
Folosirea transientelor pentru a cache-ui rezultatele
Și iată o versiune actualizată care folosește transiente WordPress pentru a cache-ui interogarea, deoarece acesta pare a fi principalul criticism pentru folosirea $wpdb
în alte răspunsuri oferite.
function get_meta_values( string $meta_key, string $post_type = 'post', bool $distinct = false, string $post_status = 'publish' ) {
global $wpdb, $wp_post_types;
if( !isset( $wp_post_types[$post_type] ) )
// Existing WP string, it should translate as is
return __( 'Invalid post type.' );
$transient_key = 'get_' . $wp_post_types[$post_type]->name . '_type_meta_values';
$get_meta_values = get_transient( $transient_key );
if( true === (bool)$get_meta_values )
return $get_meta_values;
$distinct = $distinct ? ' DISTINCT' : '';
$get_meta_values = $wpdb->get_col( $wpdb->prepare( "
SELECT{$distinct} pm.meta_value FROM {$wpdb->postmeta} pm
LEFT JOIN {$wpdb->posts} p ON p.ID = pm.post_id
WHERE pm.meta_key = %s
AND p.post_type = %s
AND p.post_status = %s
", $meta_key, $post_type, $post_status ) );
set_transient( $transient_key, $get_meta_values, DAY_IN_SECONDS );
return $get_meta_values;
}
Constanta DAY_IN_SECONDS
este una dintre diversele constante de timp în secunde configurate de WordPress.
Am actualizat numele argumentelor și variabilelor pentru a le face mai consistente cu convențiile WordPress și am implementat DISTINCT
ca parametru opțional după sugestia lui Howdy_McGee din comentarii.

De asemenea, un fun-fact pentru viitorii vizitatori, dacă doriți să extrageți doar valorile meta unice - trebuie să scrieți DISTINCT
imediat după SELECT
în funcția de mai sus. Ar putea fi util.

Nu este bine sau necesar să folosești variabila globală $wpdb:
// funcție pentru a obține toate valorile meta posibile ale cheii meta alese.
function get_meta_values( $meta_key, $post_type = 'post' ) {
$posts = get_posts(
array(
'post_type' => $post_type,
'meta_key' => $meta_key,
'posts_per_page' => -1,
)
);
$meta_values = array();
foreach( $posts as $post ) {
$meta_values[] = get_post_meta( $post->ID, $meta_key, true );
}
return $meta_values;
}
$meta_values = get_meta_values( $meta_key, $post_type );

Aceasta ar fi metoda mea preferată în majoritatea cazurilor. Efectuează cinci interogări în loc de una singură, dar, deoarece utilizează procedurile standard WordPress pentru a le genera și trimite, orice mecanism de caching specific platformei (cum ar fi Object Caching de la WP Engine sau un plugin oarecare) va intra în acțiune. Datele vor fi, de asemenea, stocate în cache-ul intern WordPress pe durata cererii, așa că nu va fi nevoie să fie preluate din nou din baza de date, dacă este necesar.

Orice filtru va fi, de asemenea, aplicat datelor, ceea ce ar putea fi extrem de important pe, de exemplu, un site multilingv. În cele din urmă, deoarece utilizează doar funcții standard din nucleul WordPress, este mult mai puțin probabil să fie afectat de o actualizare viitoare.

Aceasta ar putea fi optimizată prin limitarea interogării la ID-ul postului?
Adăugați: 'fields' => 'ids'
Deci, matricea de interogare ar arăta astfel:
array(
'post_type' => $post_type,
'meta_key' => $meta_key,
'posts_per_page' => -1,
'fields' => 'ids'
)

Îmi pot imagina cazuri în care ar fi valid să ai multiple valori meta cu aceeași valoare, motiv pentru care nu am adăugat acest lucru în codul meu. Dacă dorești valori distincte, aceasta ar fi calea de urmat. În plus, ai putea să adaugi asta ca argument al funcției (pentru a o putea folosi sau nu, după caz).

Pentru a obține toate valorile meta după o cheie meta
Verifică wp->db în codex-ul WordPress
$values = $wpdb->get_col("SELECT meta_value
FROM $wpdb->postmeta WHERE meta_key = 'yourmetakey'" );

Problema cu această abordare este lipsa de specificitate, vei obține numeroase rezultate dintr-o astfel de interogare, care ar putea include drafturi, elemente șterse, articole, pagini și orice alt tip de postare care există. Nu ar trebui să interoghezi niciodată ceea ce nu ai nevoie, specificitatea este cu siguranță necesară aici.

Deși este adevărat că ai putea obține valori din alte tipuri de postări și stări, există momente când tot ce ai nevoie sunt valorile și nu ai folosit acel meta_key decât acolo unde ai nevoie de el. Dacă majoritatea/toate valorile sunt unice, aceasta ar putea fi cea mai bună soluție.

cea mai rapidă metodă ar fi o interogare SQL personalizată și nu sunt sigur, dar poți încerca
$wpdb->get_results("
SELECT posts.* , COUNT(*) 'moodcount'
FROM $wpdb->posts as posts
JOIN $wpdb->postmeta as postmeta
ON postmeta.post_id = posts.ID
AND postmeta.meta_key = 'Mood'
GROUP BY postmeta.meta_key
");
Dacă nimic altceva, măcar e un început.

mulțumesc, dar nu ar trebui evitate interogările personalizate 'cu orice preț'? Aș prefera să folosesc stratul de abstractizare WP (cam așa se numește?)... dar desigur, dacă nu este posibil..

Interogările personalizate, dacă sunt scrise corect, pot fi mai bune și ar trebui să le evitați doar dacă nu știți ce faceți.

Nu există niciun motiv pentru care nu ai putea combina codurile lui t31os și Bainternet pentru a avea o declarație pregătită reutilizabilă (în stil WordPress) care returnează atât numărul cât și valorile într-o singură operație eficientă.
Este o interogare personalizată dar totuși utilizează stratul de abstractizare al bazei de date WordPress - astfel încât, de exemplu, nu contează cum se numesc tabelele cu adevărat sau dacă acestea se schimbă, și este o declarație pregătită deci suntem mult mai protejați de atacurile SQL etc.
În acest caz nu mai verific tipul postării și exclud șirurile goale:
$r = $wpdb->get_results( $wpdb->prepare( "
SELECT pm.meta_value AS name, count(*) AS count FROM {$wpdb->postmeta} pm
LEFT JOIN {$wpdb->posts} p ON p.ID = pm.post_id
WHERE pm.meta_key = '%s'
AND pm.meta_value != ''
AND p.post_type = '%s'
GROUP BY pm.meta_value
ORDER BY pm.meta_value
", $key, $type)
);
return $r;
În acest caz particular
Aceasta va returna un array de obiecte astfel:
array
0 =>
object(stdClass)[359]
public 'name' => string 'Hamish' (length=6)
public 'count' => string '3' (length=1)
1 =>
object(stdClass)[360]
public 'name' => string 'Ida' (length=11)
public 'count' => string '1' (length=1)
2 =>
object(stdClass)[361]
public 'name' => string 'John' (length=12)
public 'count' => string '1' (length=1)

Rețineți că implicit această funcție se referă la postarea curentă, când nu este specificat niciun post_id.

Aceasta returnează toate câmpurile personalizate pentru o singură postare, care implicit este cea cu ID-ul "0". Rețineți că documentația menționează explicit că "parametrii nu trebuie considerați opționali".
