ottenere tutti i valori per una chiave di campo personalizzato (cross-post)

15 feb 2011, 15:01:03
Visualizzazioni: 66.9K
Voti: 54

So come ottenere il valore di un campo personalizzato per un post specifico.

get_post_meta($post_id, $key, $single);

Quello che mi serve è ottenere tutti i valori associati a una specifica chiave di campo personalizzato, attraverso tutti i post.

Qualcuno conosce un modo efficiente per farlo? Non vorrei dover ciclare attraverso tutti gli ID dei post nel database.

Esempio:

4 post tutti con valori diversi per un campo personalizzato chiamato 'Mood'. 2 post hanno il valore 'felice', 1 post ha 'arrabbiato' e 1 post ha 'triste'

Voglio ottenere come output: attraverso tutti i post abbiamo: due autori felici, uno arrabbiato e uno triste.

Ma per MOLTI post.

Quello che sto cercando è:

  • una funzione WP per ottenere questo. oppure
  • una query personalizzata per ottenere questo nel modo più efficiente possibile.
2
Commenti

Sembra che tu lo stia usando come una tassonomia. Perché non aggiungere semplicemente (automaticamente) un termine a questi post durante il salvataggio? Renderebbe le query molto più facili.

kaiser kaiser
15 feb 2011 17:11:16

@kaiser Non posso ringraziarti abbastanza per essere un genio!

user2128576 user2128576
27 ott 2016 00:24:02
Tutte le risposte alla domanda 7
3
65

Un approccio possibile sarebbe utilizzare uno dei metodi helper nella classe WPDB per eseguire una query più raffinata basata sui meta.

Utilizzando la funzione $wpdb get_col è possibile ottenere un semplice array piatto di dati.

Ecco una funzione di esempio che interroga il database per tutti i post di un determinato tipo di post, stato del post e chiave meta (o campo personalizzato per chi è meno tecnico).

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

Quindi, ad esempio, se vuoi scoprire quali post hanno una chiave meta rating, per il tipo di post movies e memorizzare queste informazioni in una variabile, un esempio di chiamata sarebbe:

$movie_ratings = get_meta_values( 'rating', 'movies' );

Se vuoi fare qualcosa in più che stampare semplicemente quei dati a schermo, la funzione PHP implode può condensare rapidamente l'array in una stringa.

// Stampa i valori meta separati da un'interruzione di riga
echo implode( '<br />', get_meta_values( 'YOURKEY' ));

Puoi anche utilizzare i dati restituiti per calcolare quanti post hanno i valori meta eseguendo una semplice iterazione (ciclo) sui dati restituiti e costruendo un array dei conteggi, ad esempio:

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

// Output del numero di valutazioni
printf( '<pre>%s</pre>', print_r( $num_of_ratings ) );  

/*
Output:
Array(
    [5] => 10
    [9] => 2
)
es. ci sono 10 post di film con valutazione 5 e 2 post di film con valutazione 9.
*/

Questa logica potrebbe essere applicata a vari tipi di dati e estesa per funzionare in molti modi diversi. Spero che i miei esempi siano stati utili e abbastanza semplici da seguire.


Utilizzo dei transient per memorizzare nella cache i risultati

Ed ecco una versione aggiornata che utilizza i transient di WordPress per memorizzare nella cache la query, poiché questo sembra essere la principale critica all'uso di $wpdb nelle altre risposte fornite.

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] ) )
        // Stringa WP esistente, dovrebbe essere tradotta così com'è
        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;
}

La costante DAY_IN_SECONDS è una delle varie costanti di tempo in secondi configurate da WordPress.

Ho aggiornato i nomi degli argomenti e delle variabili per renderli più coerenti con la denominazione di WordPress e ho anche implementato DISTINCT come parametro opzionale seguendo il suggerimento di Howdy_McGee nei commenti.

16 feb 2011 00:48:36
Commenti

Anche una curiosità per i futuri lettori: se vuoi estrarre solo valori meta unici, devi scrivere DISTINCT subito dopo il SELECT nella funzione sopra. Potrebbe essere utile.

Howdy_McGee Howdy_McGee
7 feb 2014 20:24:07

Penso che sia estremamente utile

Pablo S G Pacheco Pablo S G Pacheco
1 mag 2017 17:54:08

Come fare questo e restituire i valori ordinati? Penso di dover usare ORDER by ma non riesco a capire come usarlo

efirvida efirvida
17 apr 2018 06:43:28
4
20

Non è buona pratica né necessario utilizzare la variabile globale $wpdb:

// funzione per recuperare tutti i valori meta possibili della chiave meta specificata.
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 );
4 ott 2015 00:32:20
Commenti

Nella maggior parte dei casi, questo sarebbe il mio metodo preferito per farlo. Esegue cinque query invece di una sola, ma poiché utilizza le procedure standard di WordPress per generarle e inviarle, verrà attivata qualsiasi cache specifica della piattaforma (come la Object Caching di WP Engine o qualche plugin casuale). I dati verranno anche memorizzati nella cache interna di WordPress per la durata della richiesta, quindi non sarà necessario recuperarli nuovamente dal database, se necessario.

Andrew Dinmore Andrew Dinmore
2 giu 2017 18:33:49

Inoltre, eventuali filtri verranno applicati ai dati, il che potrebbe essere estremamente importante su, ad esempio, un sito multilingue. Infine, poiché utilizza solo le funzioni standard del core di WordPress, è molto meno probabile che venga interrotto da un aggiornamento futuro.

Andrew Dinmore Andrew Dinmore
2 giu 2017 18:34:59

Potrebbe essere reso più performante limitando la query agli ID dei post?

Aggiungi: 'fields' => 'ids'

Quindi, l'array della query sarebbe:

array( 'post_type' => $post_type, 'meta_key' => $meta_key, 'posts_per_page' => -1, 'fields' => 'ids' )

Pea Pea
13 apr 2020 21:31:16

Attenzione: questo filtra anche i valori meta che esistono solo su post non pubblicati, quindi assicurati di usare l'argomento 'post_status' per renderlo una funzionalità e non un bug

jnhghy - Alexandru Jantea jnhghy - Alexandru Jantea
24 lug 2020 01:25:19
1
14

Vorrei solo aggiungere una piccola cosa al codice di t31os sopra. Ho cambiato "SELECT" in "SELECT DISTINCT" per eliminare i duplicati quando ho utilizzato questo codice personalmente.

5 giu 2011 21:52:28
Commenti

Posso immaginare casi in cui sarebbe valido avere più meta valori dello stesso valore, e quindi non ho aggiunto questa modifica al mio codice. Se vuoi valori distinti, questo sarebbe il modo di procedere. Inoltre potresti anche aggiungerlo come argomento della funzione (in modo da poterlo usare o meno, a seconda dei casi).

t31os t31os
24 gen 2014 20:19:02
2

Per ottenere tutti i valori meta da una chiave meta

Consulta wp->db wordpress codex

$values = $wpdb->get_col("SELECT meta_value
    FROM $wpdb->postmeta WHERE meta_key = 'yourmetakey'" );
7 set 2013 14:07:25
Commenti

Il problema con questo approccio è la mancanza di specificità, otterrai numerosi risultati da una query di questo tipo, che potrebbero includere bozze, elementi cestinati, articoli, pagine e qualsiasi altro tipo di post esistente. Non dovresti mai interrogare ciò di cui non hai bisogno, la specificità è assolutamente necessaria in questo caso.

t31os t31os
24 gen 2014 20:23:09

Sebbene sia vero che potresti ottenere valori da altri tipi di post e stati, ci sono momenti in cui tutto ciò di cui hai bisogno sono i valori e non hai utilizzato quella meta_key da nessuna parte tranne dove ti serve. Se tutti/la maggior parte dei valori sono unici, questa potrebbe essere la soluzione migliore.

Luke Gedeon Luke Gedeon
23 giu 2018 21:36:44
3

il modo più veloce sarebbe una query SQL personalizzata e non sono sicuro ma puoi provare

$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
");

Se funziona è un buon punto di partenza.

15 feb 2011 17:01:49
Commenti

grazie, ma le query personalizzate non dovrebbero essere evitate "a tutti i costi"? Preferirei usare lo strato di astrazione di WP (è così che si chiama?)... ma ovviamente se non è possibile..

mikkelbreum mikkelbreum
8 giu 2011 13:53:26

Le query personalizzate, se scritte nel modo giusto, possono essere migliori e dovresti evitarle solo se non sai cosa stai facendo.

Bainternet Bainternet
8 giu 2011 16:07:58

Concordo con mwb. Le query personalizzate sono molto utili e pratiche, ma penso siano anche molto più pesanti per il DB.. specialmente usando funzioni SRT..

krembo99 krembo99
10 dic 2011 05:20:54
0

Non c'è motivo per cui non si possa combinare il codice di t31os e Bainternet per ottenere un'istruzione preparata riutilizzabile (in stile WordPress) che restituisca sia il conteggio che i valori in un'unica operazione efficiente.

È una query personalizzata ma utilizza comunque il livello di astrazione del database di WordPress - quindi, ad esempio, non importa quali siano i nomi reali delle tabelle o se cambiano, ed essendo un'istruzione preparata siamo molto più protetti da attacchi SQL injection, ecc.

In questo caso specifico non sto più verificando il tipo di post ed escludo le stringhe vuote:

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

In questo caso particolare restituirà un array di oggetti come questo:

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)
31 gen 2012 15:23:34
2

Utilizza il seguente codice con foreach

$key = get_post_custom_values('key');

Presuppone che il nome della tua chiave del campo personalizzato sia

29 lug 2017 14:06:22
Commenti

Nota che questo valore predefinito è il post corrente, quando non viene specificato alcun post_id.

birgire birgire
29 lug 2017 14:23:46

Questo restituisce semplicemente tutti i campi personalizzati per un singolo post, che per impostazione predefinita è quello con ID "0". Nota che la documentazione menziona esplicitamente che "i parametri non devono essere considerati opzionali".

Husky Husky
24 feb 2022 15:24:00