Poate wp_query să returneze meta datele postărilor într-o singură cerere?

12 dec. 2014, 05:09:07
Vizualizări: 44.3K
Voturi: 27

Aș dori să creez o interogare wp_query care să returneze meta datele postărilor în interiorul array-ului posts.

$args = array (
    'post_type' => 'page', 
    'meta_key' => 'someMetaKeyName',
);

// Interogarea
$query = new WP_Query( $args );

Aceasta returnează ceva de genul:

Exemplu rezultat WP_Query fără meta date

După cum puteți vedea, postările nu au nicio meta dată, este posibil să includem meta datele în array-ul returnat de asemenea?

PS Nu doresc interogări wp_queries suplimentare din motive de performanță.

1
Comentarii

Standardul WP_Query nu returnează metadatele postărilor. Singurele opțiuni pe care le ai sunt: 1) să rulezi get_post_meta pentru chei individuale, 2) să rulezi get_post_custom pentru a obține toate câmpurile personalizate ale unei postări dintr-o singură operațiune, sau 3) să creezi propria interogare folosind clasa $wpdb (get_results()) pentru a construi propriul obiect de returnare. (Documentația clasei $wpdb: http://codex.wordpress.org/Class_Reference/wpdb)

BODA82 BODA82
12 dec. 2014 06:28:40
Toate răspunsurile la întrebare 5
5
26

În mod implicit, WP_Query returnează obiectele standard WP_Post pentru postările interogate. Cred că, cu o rescriere inteligentă și utilizarea filtrelor furnizate în WP_Query, poți adăuga obiecte la tabloul de obiecte WP_Post returnat.

Va fi acest lucru performant? După părerea mea, va afecta performanța mai mult, deoarece va trebui să alături rezultate în interogarea ta, deoarece câmpurile personalizate nu sunt salvate în tabelul wp_posts, ci în tabelul wp_postmeta.

Preluarea metadatelor postărilor este foarte rapidă și nu necesită nicio instanță suplimentară a WP_Query. Poți apela simplu câmpul personalizat cu get_post_meta(). WordPress a fost foarte grijuliu când au fost introduse câmpurile personalizate. Au adăugat un cache pentru a le stoca, astfel încât indiferent dacă interoghezi 1 sau 100 de câmpuri personalizate, accesezi baza de date o singură dată, foarte rapid. Pentru un test complet și o explicație, vezi acest articol pe care l-am scris recent pe acest subiect.

În opinia mea, apelul suplimentar la baza de date și timpul efectiv petrecut merită și este mai rapid decât rescrierea WP_Query într-un mod care să includă câmpurile personalizate în obiectul standard de post returnat de $posts.

12 dec. 2014 06:37:59
Comentarii

OK, mulțumesc, voi alege acest răspuns ca acceptat, dar să fiu sincer, este atât de obositor să apelezi get_post_meta() pentru fiecare post în parte.. Aș prefera să existe o modalitate de a stoca date suplimentare fie direct în tabela wp_posts, fie într-o tabelă asociată care nu este atât de complicată precum wp_postsmeta.

YemSalat YemSalat
12 dec. 2014 06:57:01

Ei bine, să fiu sincer, indiferent dacă apelezi get_post_meta() sau o folosești ca obiect post, va trebui să o apelezi pentru fiecare post. Este la fel cu funcțiile de tip template precum the_content(), trebuie să le apelezi pentru fiecare post.

Pieter Goosen Pieter Goosen
12 dec. 2014 07:02:54

Asta înseamnă că dacă trebuie să afișezi 120 de postări, vei avea încă 120 de interogări suplimentare pe pagină?

chifliiiii chifliiiii
14 sept. 2015 22:25:00

Toate datele postării sunt salvate într-un cache, astfel încât nu veți avea interogări suplimentare când apelați meta postării

Pieter Goosen Pieter Goosen
14 sept. 2015 22:27:53

Aveți dreptate. Mă refeream la post_thumbnails, dar recent am descoperit update_post_thumbnail_cache( $the_query ). Oricum, mulțumesc pentru clarificare

chifliiiii chifliiiii
14 sept. 2015 22:50:04
1

Am avut o problemă similară recent, aveam nevoie să obțin 7 câmpuri de metadate dintr-un tip de postare personalizat, dar și să obțin postarea bazată pe un câmp de metadate.

Așa că am creat următoarea declarație SQL, pe care o folosesc des. Sper să ajute pe cineva. Încerc să o explic cât mai bine posibil.

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

Mai întâi obțin funcțiile de bază de date WordPress cu global $wpdb. Apoi setez tipul de postare cu $pt. Pentru a obține postarea corectă care se potrivește cu o valoare specifică în post_meta, setez $mk (meta_key)

Apoi setez variabila $mv (meta_value) (în acest caz valoarea meta se potrivește cu un ID de postare)

$mk1-$mk7 sunt cheile meta pe care le doresc de la fiecare postare. (Le voi prelua valorile în declarația SELECT)

De asemenea, fac clauza 'order by' o variabilă, setând $ord

Declarația SELECT merge astfel: Selectez ID-ul postării și post_title din POST sau 'p.'

Apoi selectez toate metadatele de care am nevoie selectându-le cu pm1. -> pm.7 și preluând meta_value și redenumindu-le (AS) pentru a fi mai ușor de citit când preiau datele din obiectul meu.

Creez un LEFT JOIN pentru metadatele pe care trebuie să le potrivesc cu postarea. (pm)

Creez 7 LEFT JOIN-uri pentru fiecare dintre metadatele pe care trebuie să le obțin. (pm1-pm7)

Clauza WHERE se bazează pe primul LEFT JOIN (pm) astfel încât să știe că am nevoie doar de postările unde metadatele se potrivesc.

De asemenea, adaug o condiție 'AND' pentru tipul de postare și pentru post_status-urile care nu sunt draft. (deci doar postări publicate)

În final, adaug clauza 'order by'.

Această metodă funcționează rapid și folosind indexurile încorporate în WordPress, deci pare eficientă.

Nu știu dacă există ceva mai bun decât asta, dar dacă există, aș dori să-l folosesc.

Sper că vă ajută.

Marcus

14 feb. 2017 03:21:29
Comentarii

Mulțumesc, acest articol este foarte util. Am creat o vizualizare cu toate câmpurile meta de care am nevoie și acum este foarte rapid și ușor să obțin orice date doresc

Liko Liko
23 nov. 2017 14:01:22
1

Această întrebare are mai mult de 1 an, dar am aceeași problemă, iar aici este o funcție care va adăuga fiecare meta_value și meta_key la obiectul $wp_query,

în loc să interogăm fiecare post meta în bucla while, această funcție va face o singură interogare suplimentară exemplu:

"SELECT meta_key, meta_value, post_id FROM $wpdb->postmeta WHERE post_id IN (1,2,3,4,5...)"

unde (1,2,3,4,5...) sunt ID-urile posturilor curent interogate din $wp_query

if(!function_exists('add_query_meta')) {
  function add_query_meta($wp_query = "") {

      // Returnează dacă wp_query este gol sau dacă postmeta există deja
      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;
  }
}

Informația suplimentară "postmeta" va fi adăugată la fiecare $wp_query->posts[$i]

$wp_query->posts[0]->postmeta

Exemplu cu 'someMetaKeyName' nu uitați să adăugați

add_query_meta() în fișierul functions.php al temei

$args = array (
    'post_type' => 'page',
    'meta_key' => 'someMetaKeyName',
);

// Interogarea
$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();

      //Obține $someMetaKeyName în postul curent
      foreach($wp_query->posts[$i]->postmeta as $k => $v) {
        switch($v->meta_key) {
          case('someMetaKeyName') : {
            $someMetaKeyName = $v->meta_value;
            break;
          }
        }
      }

      //Codul tău aici
      //Exemplu 
      echo isset($someMetaKeyName) ? '<h3>'.$someMetaKeyName.'</h3>' : '';


      $i++;
    }
}
5 mai 2016 16:10:27
Comentarii

Îmi place această soluție.

Armstrongest Armstrongest
1 aug. 2017 18:29:58
1

Am avut nevoie doar de o singură valoare suplimentară pentru post_meta (șablonul în cazul meu) și am reușit să obțin ceva similar cu ceea ce cauți folosind get_pages cu un parametru meta_key.

$args = [
  'parent' => $post_id, // în exemplul meu, găsesc copiii unui anumit post
  'meta_key' => '_wp_page_template', // caut șablonul folosit de post
];

$posts = get_pages($args);

Și aceasta returnează un array de obiecte post ca acesta

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 // <-- AICI E!
      ...
    )

Și apoi poți accesa o valoare meta_value astfel

echo $posts[0]->meta_value;

// returnează 'template-module-content.php' în cazul meu

Recunosc, acest lucru poate fi util doar într-un caz specific, dar era exact ceea ce aveam nevoie

16 mar. 2022 04:39:25
Comentarii

WordPress 6.3 pare să fi eliminat complet acest mic truc

Todd Todd
10 aug. 2023 19:20:17
3
-1

Hei, te rog să încerci această variantă, cred că funcționează corect.

$args = array(
            'post_type' => 'page',
            'meta_key' => 'someMetaKeyName',
            'meta_query' => array(
                array(
                        'key' => 'someMetaKeyName',
                        'type' => 'CHAR',
                   ),
                ),
        );

    $query = new WP_Query( $args );
12 dec. 2014 05:44:43
Comentarii

Care este motivul pentru care ai folosit atât meta_key cât și meta_query[]['key']?

kaiser kaiser
12 dec. 2014 05:56:06

Nu, acest lucru nu funcționează și returnează matricea de postări fără meta asociate cu ele.

YemSalat YemSalat
12 dec. 2014 05:57:53

meta_key și/sau meta_query nu modifică tipul de rezultate returnate, ci doar interogarea în sine.

BODA82 BODA82
12 dec. 2014 06:39:20