Obținerea tuturor valorilor pentru o cheie de câmp personalizat (cross-post)

15 feb. 2011, 15:01:03
Vizualizări: 66.9K
Voturi: 54

Ș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.
2
Comentarii

Se pare că folosești asta ca o taxonomie. De ce nu adaugi pur și simplu (automat) un termen la aceste articole când le salvezi? Ar face interogările mult mai ușoare.

kaiser kaiser
15 feb. 2011 17:11:16

@kaiser Nu pot să-ți mulțumesc suficient pentru că ești un geniu!

user2128576 user2128576
27 oct. 2016 00:24:02
Toate răspunsurile la întrebare 7
3
65

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.

16 feb. 2011 00:48:36
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.

Howdy_McGee Howdy_McGee
7 feb. 2014 20:24:07

Cred că acest lucru este extrem de util

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

Cum să fac asta și să returnez valorile sortate? Cred că trebuie să folosesc ORDER by dar nu-mi dau seama cum să-l folosesc

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

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 );
4 oct. 2015 00:32:20
Comentarii

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.

Andrew Dinmore Andrew Dinmore
2 iun. 2017 18:33:49

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.

Andrew Dinmore Andrew Dinmore
2 iun. 2017 18:34:59

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

Pea Pea
13 apr. 2020 21:31:16

Atenție: acest lucru filtrează și valorile meta care există doar pe postări nepublicate, așa că asigurați-vă că utilizați argumentul 'post_status' pentru a face din aceasta o funcționalitate, nu o eroare.

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

Aș dori să adaug un mic detaliu la codul lui t31os de mai sus. Am schimbat "SELECT" în "SELECT DISTINCT" pentru a elimina intrările duplicate când am folosit acest cod personal.

5 iun. 2011 21:52:28
Comentarii

Î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).

t31os t31os
24 ian. 2014 20:19:02
2

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'" );
7 sept. 2013 14:07:25
Comentarii

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.

t31os t31os
24 ian. 2014 20:23:09

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.

Luke Gedeon Luke Gedeon
23 iun. 2018 21:36:44
3

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.

15 feb. 2011 17:01:49
Comentarii

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

mikkelbreum mikkelbreum
8 iun. 2011 13:53:26

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.

Bainternet Bainternet
8 iun. 2011 16:07:58

Sunt de acord cu mwb. Interogările personalizate sunt foarte utile și practice, dar cred că sunt și mult mai grele pentru baza de date.. mai ales când folosiți funcții SRT..

krembo99 krembo99
10 dec. 2011 05:20:54
0

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

Folosește următoarele cu foreach

 $key = get_post_custom_values( 'key' );

Presupune că numele câmpului tău personalizat este

29 iul. 2017 14:06:22
Comentarii

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

birgire birgire
29 iul. 2017 14:23:46

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

Husky Husky
24 feb. 2022 15:24:00