meta_query cu valori meta ca array-uri serializate

9 mai 2011, 05:06:35
Vizualizări: 81.7K
Voturi: 51

Lucrez la un proiect în care creez un tip de postare personalizat și date personalizate introduse prin meta box-uri asociate cu tipul meu de postare personalizat. Din anumite motive am decis să codez meta box-urile astfel încât input-urile din fiecare metabox să facă parte dintr-un array. De exemplu, stochez longitudinea și latitudinea:

<p> 
    <label for="latitude">Latitudine:</label><br /> 
    <input type="text" id="latitude" name="coordinates[latitude]" class="full-width" value="" /> 
</p> 
<p>     
    <label for="longitude">Longitudine:</label><br /> 
    <input type="text" id="longitude" name="coordinates[longitude]" class="full-width" value="" /> 
</p>

Din anumite motive, mi-a plăcut ideea de a avea o singură înregistrare postmeta pentru fiecare metabox. În hook-ul save_post, salvez datele astfel:

update_post_meta($post_id, '_coordinates', $_POST['coordinates']);

Am făcut acest lucru pentru că am trei metabox-uri și îmi place să am doar 3 valori postmeta pentru fiecare postare; totuși, acum am realizat o potențială problemă. S-ar putea să vreau să folosesc WP_Query pentru a extrage doar anumite postări bazate pe aceste valori meta. De exemplu, aș putea să vreau să obțin toate postările care au valori ale latitudinii peste 50. Dacă aș avea aceste date în baza de date individual, poate folosind cheia latitude, aș face ceva de genul:

$args = array(
    'post_type' => 'my-post-type',
    'meta_query' => array(
        array(
            'key' => 'latitude',
            'value' => '50',
            'compare' => '>'
        )
    )
 );
$query = new WP_Query( $args );

Având în vedere că am latitudinea ca parte a postmeta _coordinates, acest lucru nu ar funcționa.

Așadar, întrebarea mea este, există o modalitate de a utiliza meta_query pentru a interoga un array serializat așa cum am eu în acest scenariu?

0
Toate răspunsurile la întrebare 14
6
52

Nu, nu este posibil și chiar ar putea fi periculos.

Nu există o metodă fiabilă de a face acest lucru fără a întâlni capcane și probleme precum o căutare pentru 10 care să se potrivească cu 100 sau 210, sau să se potrivească cu o sub-valoare greșită etc. Astfel de soluții sunt nesigure și au probleme de performanță și securitate.

Datele serializate reprezintă un vector de atac și o problemă majoră de performanță.

Voi acoperi:

  • Remedierea și transformarea lor în date interogabile
  • De ce Nu Poți Interoga În Interiorul Datelor Serializate?
    • De ce LIKE nu este o soluție
  • O Notă despre Stocarea Înregistrărilor/Entităților/Obiectelor ca Obiecte Serializate în Meta
  • Securitate și Obiecte Serializate
  • Ce să faci Dacă am o Listă de ID-uri?
  • Ce să faci Dacă am un Array de Elemente Denumite?
  • Ocolirea Completă a Problemei
  • Concluzie

Dar Ce Spui Despre LIKE?

S-ar putea să întâlnești întrebări bine intenționate care sugerează utilizarea LIKE pentru a realiza acest lucru. Nu rezolvă aceasta problema? Aceasta nu este soluția, este o iluzie.

Există mai multe probleme majore:

  • potriviri false, căutarea pentru test cu LIKE va găsi și test, testing, untested și alte valori
  • nu există nicio modalitate de a restrânge acest lucru la sub-chei pentru array-uri cu chei sau obiecte
  • nu este posibilă sortarea
  • este extrem de lent și costisitor

LIKE va funcționa doar în situații specifice și limitate care sunt nerealiste și implică o penalizare mare de performanță.

Remedierea și Transformarea Lor în Date Interogabile

Recomand cu tărie să deserializați datele și să modificați rutina de salvare. Ceva similar cu acest exemplu ar trebui să convertească datele în noul format:

$args = [
    'post_type' => 'my-post-type',
    'meta_key' => '_coordinates',
    'posts_per_page' => -1,
];
$query = new WP_Query( $args );
if ( $query->have_posts() ) {
    while ( $query->have_posts() ) {
        $query->the_post();
        // obține datele
        $c = get_post_meta( $post->ID, '_coordinates', true );

        // salvează în noul format, meta separate, termen de taxonomie etc.
        add_post_meta( $post->ID, '_longitude', $c['longitude'] );
        add_post_meta( $post->ID, '_latitude', $c['latitude'] );

        // Opțional: curăță vechile meta
        delete_post_meta( $post->ID, '_coordinates', $c );
    }
    wp_reset_postdata();
}

Apoi vei putea interoga după cum dorești cu chei individuale

Dacă trebuie să stochezi mai multe longitudini și mai multe latitudini, poți stoca mai multe meta cu același nume. Pur și simplu folosește al treilea parametru al get_post_meta, și acesta le va returna pe toate ca un array

De ce Nu Poți Interoga În Interiorul Datelor Serializate?

MySQL le vede doar ca un șir de caractere și nu le poate despărți în date structurate. Despărțirea lor în date structurate este exact ceea ce face codul de mai sus

S-ar putea să poți interoga pentru porțiuni parțiale de date, dar acest lucru va fi extrem de nesigur, costisitor, lent și foarte fragil, cu multe cazuri limită. Datele serializate nu sunt destinate interogărilor SQL și nu sunt formatate într-un mod constant și regulat.

Pe lângă costurile căutărilor parțiale de șiruri, interogările de meta sunt lente, iar datele serializate se pot schimba în funcție de lucruri precum lungimea conținutului, făcând căutarea incredibil de costisitoare, dacă nu imposibilă, în funcție de valoarea pe care o cauți

O Notă despre Stocarea Înregistrărilor/Entităților/Obiectelor ca Obiecte Serializate în Meta

S-ar putea să dorești să stochezi o înregistrare de tranzacție în meta postului, sau o altă structură de date în meta utilizatorului, apoi să întâmpini problema menționată mai sus.

Soluția aici nu este să o desparți în meta individuale, ci să realizezi că nu ar fi trebuit să fie meta de la început, ci un tip de post personalizat. De exemplu, un jurnal sau o înregistrare poate fi un tip de post personalizat, cu postul original ca părinte sau asociat prin intermediul unui termen de taxonomie

Securitate și Obiecte Serializate

Stocarea obiectelor PHP serializate prin funcția serialize poate fi periculoasă, ceea ce este regretabil, deoarece transmiterea unui obiect către WordPress înseamnă că acesta va fi serializat. Acest lucru se datorează faptului că, atunci când obiectul este deserializat, se creează un obiect și toate metodele sale de trezire și constructori sunt executate. Acest lucru poate părea neînsemnat până când un utilizator reușește să introducă o intrare atent construită, ducând la execuția de cod la distanță atunci când datele sunt citite din baza de date și deserializate de WordPress.

Acest lucru poate fi evitat prin utilizarea JSON în schimb, ceea ce face și interogările mai ușoare, dar este mult mai ușor/rapid să stochezi datele corect și să eviți datele serializate structurate de la bun început.

Ce să faci Dacă am o Listă de ID-uri?

S-ar putea să fii tentat să dai lui WP un array sau să-l transformi într-o listă separată prin virgulă, dar nu trebuie!

Cheile meta nu sunt unice, poți stoca aceeași cheie de mai multe ori, de exemplu:


$id = ...;
add_post_meta( $id, 'mylist', 1 );
add_post_meta( $id, 'mylist', 2 );
add_post_meta( $id, 'mylist', 3 );
add_post_meta( $id, 'mylist', 4 );
add_post_meta( $id, 'mylist', 5 );
add_post_meta( $id, 'mylist', 6 );

Dar cum obțin datele înapoi? Ai observat vreodată că apelurile către get_post_meta au un al treilea parametru care este întotdeauna setat la true? Setează-l la false:

$mylist = get_post_meta( $id, 'mylist', false );
foreach ( $mylist as $number ) {
    echo '<p>' . esc_html( $number ) . '</p>;
}

Ce să faci Dacă am un Array de Elemente Denumite?

Ce se întâmplă dacă aș dori să stochez această structură de date într-un mod care să-mi permită să interogez câmpurile?

{
  "foo": "bar",
  "fizz": "buzz"
  "parent": {
    "child": "value"
  }
}

Este ușor, desparte-le cu prefixe:

add_post_meta( $id, "tomsdata_foo", "bar" );
add_post_meta( $id, "tomsdata_fizz", "buzz" );
add_post_meta( $id, "tomsdata_parent_child", "value" );

Și dacă trebuie să parcurgi unele dintre aceste valori, folosește get_post_meta( $id ); pentru a obține toate meta și a parcurge cheile, de exemplu:

$all_meta = get_post_meta( $id );
$look_for = 'tomsdata_parent';
foreach ( $all_meta as $key => $value ) {
    if ( substr($string, 0, strlen($look_for)) !== $look_for ) {
        continue; // nu se potrivește, sare peste!
    }
    echo '<p>' . $key . ' = ' . $value . '</p>';
}

Care ar afișa:

<p>tomsdata_parent_child = value</p>

Reține, când WordPress preia un post, preia toate meta-urile sale în același timp, astfel încât apelurile get_post_meta sunt foarte ieftine și nu declanșează interogări suplimentare la baza de date

Ocolirea Completă a Problemei

Dacă știi că vei avea nevoie să cauți/interoghezi/filtrezi o sub-valoare, de ce nu stochezi un meta suplimentar cu acea valoare pentru a o putea căuta?

Concluzie

Deci nu trebuie să stochezi date structurate ca șir în baza de date și nu ar trebui să o faci dacă intenționezi să cauți/interoghezi/filtrezi aceste valori.

S-ar putea să fie posibil să utilizezi o expresie regulată și un LIKE, dar acest lucru este extrem de nesigur, nu funcționează pentru majoritatea tipurilor de date și este foarte, foarte lent și solicitant pentru baza de date. De asemenea, nu poți efectua operații matematice pe rezultate așa cum ai putea dacă ar fi valori separate

20 aug. 2012 18:19:49
Comentarii

Pentru cei care trec pe aici, nu încetați să citiți: mai multe răspunsuri utile (și mai recente) se găsesc mai jos

Erenor Paz Erenor Paz
13 apr. 2017 13:07:01

Ce se întâmplă dacă am un array de ID-uri de salvat - și fiecare nu reprezintă o cheie diferită sub care le-aș putea salva precum 'latitude' etc., ci este doar o singură cheie pentru toate (cum ar fi la salvarea relațiilor etc.). Ce să fac atunci? Soluția lui @rabni?

trainoasis trainoasis
16 iun. 2017 10:52:59

Poți stoca o cheie de mai multe ori, perechile cheie-valoare nu sunt unice. Cât despre relații, pentru asta sunt taxonomiile, dacă folosești meta pentru a mapa mai multe lucruri pe ceva, pune-le într-un termen de taxonomie în schimb

Tom J Nowell Tom J Nowell
19 iun. 2017 20:31:41

Desigur, este posibil. Da, trebuie să vă asigurați că aveți valori unice, ceea ce reprezintă esența acestor postmeta. De obicei, astfel de valori serializate provin din checkbox-uri care sunt array-uri. Fiecare checkbox din set ar trebui să aibă o valoare unică. Și dacă nu, se asigură că opțiunea sa (în php: cheia array-ului) este unică, astfel încât să o puteți găsi.

Ulterior, interogarea este o sarcină simplă comparativ cu soluția prezentată de dvs.: 'meta_query' => array( array( 'key' => 'thekey', 'value' => 'thevalue', 'compare' => 'LIKE', 'type' => 'CHAR', ), ),

User User
17 feb. 2023 09:42:18

@BedaSchmid asta nu face ceea ce crezi tu, dacă ai fi citit răspunsul meu ai vedea că am abordat clauza LIKE și am evidențiat defecte majore care o fac ineficientă și cauzează erori. Vezi partea intitulată "Ce zici de LIKE?". Am editat răspunsul meu pentru a o muta mai sus pentru oamenii care nu citesc întregul răspuns, deoarece au existat câteva de-a lungul anilor

Tom J Nowell Tom J Nowell
17 feb. 2023 11:42:52

@TomJNowell - din cele 4 motive menționate, doar unul este o problemă serioasă și este, după cum am explicat în comentariu, evitabil. Lent? Da. Orice interogare meta este lentă. Sortare după? Ok. Presupun că dacă chiar trebuie să interoghezi după acel câmp, poți renunța la sortare. E chiar ciudat să sortezi după un array unde pot fi selectate multiple opțiuni. Este posibil să interoghezi după astfel de valori și nu returnează rezultate inexacte, atâta timp cât array-ul serializat are valori unice, așa cum am menționat în comentariul meu

User User
18 feb. 2023 12:50:12
Arată celelalte 1 comentarii
6
41

Am întâlnit și eu această situație. Iată ce am făcut:

$args = array(
    'post_type' => 'my-post-type',
    'meta_query' => array(
        array(
            'key' => 'latitude',
            'value' => sprintf(':"%s";', $value),
            'compare' => 'LIKE'
        )
    )
);

Sper că acest lucru vă ajută

16 apr. 2015 15:38:57
Comentarii

Mi-a plăcut foarte mult această soluție. Din păcate, aceasta nu este aplicabilă atunci când $value este și el un ID. În acest caz, sugerez să creați două funcții pentru a adăuga un caracter fiecărui element din matrice înainte de salvarea datelor și o altă funcție pentru a elimina caracterul înainte de a folosi datele. În acest fel, indexul serializat i:2 nu va fi confundat cu i:D2 din datele "reale". Parametrul meta query ar trebui să devină atunci 'value' => sprintf(':"D%s";', $value), și veți păstra funcționalitatea corectă a acestui răspuns minunat!

Erenor Paz Erenor Paz
13 apr. 2017 12:30:09

Această soluție funcționează pentru mine

Rakhi Rakhi
12 ian. 2018 11:32:02

Și pentru mine a funcționat perfect. Am avut o mică panică când am văzut soluția acceptată însă

Shane Jones Shane Jones
26 feb. 2018 12:48:20

@Erenor Paz, tocmai am postat o soluție care funcționează bine atât cu ID-uri cât și cu șiruri de caractere: https://wordpress.stackexchange.com/a/299325/25264

Pablo S G Pacheco Pablo S G Pacheco
29 mar. 2018 22:09:08

folosirea LIKE este o metodă excelentă și rapidă de a-ți pune serverul în genunchi (fără a mai menționa rezultatele false pozitive) - mai bine ai un sistem de caching foarte bun.

Mark Kaplun Mark Kaplun
2 apr. 2018 08:23:41

Rețineți că cu această soluție, se vor potrivi orice subvalori care conțin acea valoare. Deci dacă cauți o latitudine de 5, se va potrivi și cu longitudini de 5. Aceasta este mai puțin problematică în acest caz particular, dar este ceva de care trebuie să ții cont. De asemenea, este imposibil să sortezi rezultatele și nu este posibil să efectuezi orice logică/matematică precum preluarea tuturor valorilor care sunt deasupra sau sub un anumit număr.

Tom J Nowell Tom J Nowell
29 mai 2020 12:29:37
Arată celelalte 1 comentarii
0
11

Vei pierde cu adevărat capacitatea de a interoga datele într-un mod eficient atunci când serializezi intrările în baza de date WordPress.

Economia și câștigul de performanță generale pe care crezi că le obții prin serializare nu vor fi vizibile într-o măsură semnificativă. S-ar putea să obții o dimensiune ușor mai mică a bazei de date, dar costul tranzacțiilor SQL va fi mare dacă interoghezi acele câmpuri și încerci să le compari într-un mod util și semnificativ.

În schimb, folosește serializarea pentru date pe care nu intenționezi să le interoghezi în acel fel, ci pe care le vei accesa doar într-un mod pasiv prin apelul direct al API-ului WordPress get_post_meta() - din această funcție poți despacheta o intrare serializată pentru a accesa și proprietățile sale de tip array.

De fapt, atribuind valoarea true ca în:

$meta = get_post_meta( $post->ID, 'key', true );

Va returna datele ca un array, accesibil pentru a itera în mod normal.

Te poți concentra pe alte optimizări ale bazei de date/site-ului, cum ar fi caching-ul, minificarea CSS și JS și utilizarea unor servicii precum un CDN dacă este necesar. Pentru a numi doar câteva... WordPress Codex este un punct de plecare bun pentru a descoperi mai multe pe această temă: AICI

20 aug. 2012 17:36:42
5

Cred că există 2 soluții care pot încerca să rezolve problema rezultatelor stocate atât ca Șiruri de caractere cât și ca Numere întregi. Cu toate acestea, este important de menționat, așa cum au subliniat și alții, că nu este posibil să garantăm integritatea rezultatelor stocate ca Numere întregi, deoarece aceste valori sunt stocate ca tablouri serializate, indicele și valorile sunt stocate exact cu același model. Exemplu:

array(37,87);

este stocat ca un tablou serializat, astfel:

a:2:{i:0;i:37;i:1;i:87;}

Observați i:0 ca prima poziție a tabloului și i:37 ca prima valoare. Modelul este același. Dar să trecem la soluții


1) Soluție REGEXP

Această soluție funcționează pentru mine indiferent dacă valoarea meta este salvată ca șir de caractere sau ca număr / id. Cu toate acestea, utilizează REGEXP, care nu este la fel de rapid ca utilizarea LIKE

$args = array(
    'post_type' => 'my-post-type',
    'meta_query' => array(
        array(
            'key' => 'latitude',
            'value' => '\;i\:' . $value . '\;|\"' . $value . '\";',
            'compare' => 'REGEXP'
        )
    )
);

2) Soluție LIKE

Nu sunt sigur de diferența de performanță, dar aceasta este o soluție care utilizează LIKE și funcționează atât pentru numere cât și pentru șiruri de caractere

 $args = array(
        'post_type' => 'my-post-type',
        'meta_query' => array(
            'relation' => 'OR',
            array(
                'key' => 'latitude',
                'value' => sprintf(':"%s";', $value),
                'compare' => 'LIKE'
            ),
            array(
                'key' => 'latitude',
                'value' => sprintf(';i:%d;', $value),
                'compare' => 'LIKE'
            )
        )
    );
29 mar. 2018 22:07:17
Comentarii

REGEXP este util în anumite situații, dar dacă poți folosi LIKE, cred că este metoda preferabilă. Un link vechi, dar încă destul de util, după părerea mea: https://thingsilearn.wordpress.com/2008/02/28/mysql-query-speed-regexp-vs-like/ :-)

Erenor Paz Erenor Paz
30 mar. 2018 11:44:57

@ErenorPaz Ai dreptate. LIKE este mai rapid. Dar aceasta este o soluție care funcționează atât pentru șiruri de caractere cât și pentru numere

Pablo S G Pacheco Pablo S G Pacheco
30 mar. 2018 23:37:19

Da..deci, răspunsul este (ca întotdeauna): în funcție de situație, dacă poți folosi "LIKE"; este preferabil, altfel REGEXP va funcționa la fel de bine :-)

Erenor Paz Erenor Paz
31 mar. 2018 16:10:05

@ErenorPaz, am editat răspunsul meu adăugând o nouă soluție care folosește LIKE dar funcționează atât pentru numere cât și pentru șiruri de caractere. Nu sunt sigur de performanță pentru că trebuie să compare rezultatele folosind OR

Pablo S G Pacheco Pablo S G Pacheco
1 apr. 2018 22:41:09

Exact !!! asta am nevoie pentru a obține același rezultat ca aici....

Mulțumesc frumos!!!

kuldip Makadiya kuldip Makadiya
27 sept. 2018 14:23:28
0

Tocmai am lucrat cu câmpuri serializate și am reușit să interoghez aceste date. Nu am folosit meta_query ci o interogare SQL directă.

global $wpdb; 

$search = serialize('latitude').serialize(50);

$query = $wpdb->prepare("SELECT `post_id`
FROM `wp_postmeta`
WHERE `post_id` IN (SELECT `ID` FROM `wp_posts` WHERE `post_type` = 'my-post-type')
AND `meta_key` = '_coordinates'
AND `meta_value` LIKE '%s'",'%'.$search.'%');

$ids = $wpdb->get_col($query);

$args = array(
    'post__in' => $ids
    'post_type' => 'team' //specifică tipul postării deoarece implicit va fi 'post'
);

$posts = get_posts($args);

Interogarea caută mai întâi postările cu tipul specificat, reducând astfel numărul de înregistrări din wp_postmeta care trebuie filtrate. Apoi am adăugat o condiție WHERE pentru a reduce și mai mult rândurile prin filtrarea după meta_key.

ID-urile rezultate sunt stocate corect într-un array, așa cum este necesar pentru funcția get_posts.

PS. Este necesară versiunea MySQL 5.6 sau mai mare pentru o performanță bună la subinterogări

22 aug. 2013 12:41:49
2

Un hack simplu pentru această situație este să folosești comparația LIKE cu formatul serializat (lungime cu tip și valoarea în sine) ca mai jos:

$id = 123; // id-ul de verificat din datele serializate.
//(presupunând că numerele sunt stocate ca șir de caractere. În cazul meu așa era.)

$args = array(
    'post_type' => 'custom_post_type',
    'meta_query' => array(
        array(
            'key' => 'meta_key_to_check_from',
            'value' => 's:' . strlen($id) . ':"' . $id . '";',
            'compare' => 'LIKE'
        )
    )
);

$query = new WP_Query( $args );

Dacă căutăm în taxonomii personalizate:

$id = 123; // id-ul de verificat în datele serializate.
//(presupunând că numerele sunt stocate ca șir de caractere. În cazul meu așa era.)

$args = array(
    'hide_empty' => false, // returnează și termenii neutilizați încă
    'meta_query' => array(
        array(
            'key' => 'meta_key_to_check_from',
            'value' => 's:' . strlen($id) . ':"' . $id . '";',
            'compare' => 'LIKE'
        )
    ),
    'taxonomy' => 'custom_taxonomy'
);

$terms = get_terms( $args );
15 mai 2022 16:22:19
Comentarii

Aș spune că acest exemplu răspunde direct la întrebare și este exact ceea ce căutam.

Sharpey Sharpey
18 mai 2023 01:25:34

Aceasta rezolvă exact problema, cel mai bun răspuns de aici!

rank rank
20 feb. 2024 19:55:03
1

Acest exemplu m-a ajutat foarte mult. Este specific pentru plugin-ul S2Members (care serializează metadatele utilizatorilor). Dar vă permite să interogați o porțiune dintr-un array serializat în cadrul meta_key.

Funcționează folosind funcția MySQL REGEXP.

Aici este sursa

Iată codul care interoghează toți utilizatorii care locuiesc în SUA. L-am modificat cu ușurință pentru a interoga unul dintre câmpurile mele personalizate de înregistrare și a funcționat imediat.

  <?php
global $wpdb;
$users = $wpdb->get_results ("SELECT `user_id` as `ID` FROM `" . $wpdb->usermeta . 
          "` WHERE `meta_key` = '" . $wpdb->prefix . "s2member_custom_fields' AND 
           `meta_value` REGEXP '.*\"country_code\";s:[0-9]+:\"US\".*'");
if (is_array ($users) && count ($users) > 0)
    {
        foreach ($users as $user)
            {
                $user = /* Obține acum întregul obiect User. */ new WP_User ($user->ID);
                print_r($user); /* Obține o listă completă de proprietăți pentru depanare. */
            }
    }
?>
12 dec. 2012 20:43:48
Comentarii

Mulțumesc. Aceasta a fost singura soluție care a funcționat când încercam să obțin date serializate de la un plugin de la terți.

adamalexanderw adamalexanderw
25 apr. 2023 12:40:45
0

După ce am citit o grămadă de sfaturi pentru a rula un WP_Query cu filtrare după array-uri serializate, iată cum am reușit în final: prin crearea unui array de valori separate prin virgulă folosind implode împreună cu o interogare SQL personalizată $wpdb care utilizează FIND_IN_SET pentru a căuta în lista separată prin virgulă valoarea dorită.

(acest lucru este similar cu răspunsul lui Tomas, dar este puțin mai puțin intensiv din punct de vedere al performanței pentru interogarea SQL)

1. În functions.php:

În fișierul functions.php (sau oriunde configurați meta box-ul) în funcția yourname_save_post() utilizați

update_post_meta($post->ID, 'checkboxArray', implode(",", $checkboxArray)); //adaugăm implode

pentru a crea array-ul care conține valori separate prin virgulă.

De asemenea, veți dori să schimbați variabila de ieșire în funcția de construire a meta box-ului administrativ yourname_post_meta() în

$checkboxArray = explode(",", get_post_custom($post->ID)["checkboxArray"][0]); //adaugăm explode

2. În fișierul PHP al template-ului:

Test: dacă rulați un get_post_meta( $id ); ar trebui să vedeți checkboxArray ca un array care conține valorile voastre separate prin virgulă în loc de un array serializat.

Acum, construim interogarea noastră SQL personalizată folosind $wpdb.

global $wpdb;

$search = $post->ID;

$query = "SELECT * FROM wp_posts
          WHERE FIND_IN_SET( $search, (
              SELECT wp_postmeta.meta_value FROM wp_postmeta
              WHERE wp_postmeta.meta_key = 'blogLocations'
              AND wp_postmeta.post_id = wp_posts.ID )
          )
          AND ( wp_posts.post_type = 'post' )
          AND ( wp_posts.post_status = 'publish' );";

$posts = $wpdb->get_results($query);

foreach ($posts as $post) {
    //conținutul postării aici
}

Observați FIND_IN_SET, acolo se întâmplă magia.

Acum... deoarece folosesc SELECT * acest lucru returnează toate datele postării și în cadrul foreach puteți afișa ceea ce doriți din acele date (faceți un print_r($posts); dacă nu știți ce este inclus. Nu configurează "loop-ul" pentru voi (prefer astfel), dar poate fi ușor modificat pentru a configura loop-ul dacă preferați (aruncați o privire la setup_postdata($post); în codex, probabil va trebui să schimbați SELECT * pentru a selecta doar ID-urile postărilor și $wpdb->get_results la tipul corect $wpdb -- consultați codex-ul pentru $wpdb pentru informații despre acest subiect).

Păi, a necesitat ceva efort, dar deoarece wp_query nu suportă utilizarea 'compare' => 'IN' pentru valori serializate sau separate prin virgulă, această soluție este cea mai bună opțiune!

Sper că acest lucru ajută pe cineva.

23 ian. 2015 00:10:32
0

Dacă utilizați operatorul de comparație like în interogarea meta, ar trebui să funcționeze corect pentru a căuta în interiorul unui array serializat.

$wp_user_search = new WP_User_Query(array(
    'meta_query' => array(
        array(
            'key'     => 'wp_capabilities',
            'value'   => 'subscriber',
            'compare' => 'not like'
            )
        )
    )
);

rezultă în:

[query_where] => WHERE 1=1 AND (
  ( wp_usermeta.meta_key = 'wp_capabilities' 
  AND CAST(wp_usermeta.meta_value AS CHAR) NOT LIKE '%subscriber%' )
4 iul. 2015 00:14:38
1

Dacă metadatele mele sunt de tip array, folosesc această metodă pentru interogare după meta:

$args = array(
    'post_type' => 'fotobank',
    'posts_per_page' => -1,
    'meta_query' => array(
            array(
                   'key' => 'collections',
                   'value' => ':"'.$post->ID.'";',
                   'compare' => 'LIKE'
            )
     )
);
$fotos = new WP_Query($args);
7 iul. 2016 09:50:49
Comentarii

Acest lucru ar putea duce la rezultate nedorite atunci când ID-ul unui post are aceeași valoare ca și ID-ul șirului serializat

Erenor Paz Erenor Paz
13 apr. 2017 13:05:22
0

Am devenit curios despre răspunsurile de mai sus, unde meta_query avea ca țintă cheia latitude în loc de _coordinates. A trebuit să testez dacă este cu adevărat posibil în interogările meta să țintești o cheie specifică dintr-un array serializat. :)

Evident, nu a fost cazul.

Așadar, rețineți că cheia corectă de țintat este _coordinates în loc de latitude.

$args = array(
     'post_type' => 'my-post-type',
     'meta_query' => array(
         array(
             'key' => '_coordinates',
             'value' => sprintf(':"%s";', $value),
             'compare' => 'LIKE'
         )
     )
 );

NOTIȚE:

  1. Această abordare face posibilă țintirea doar a potrivirilor exacte. Așadar, lucruri precum toate latitudinile mai mari de 50 nu sunt posibile.

  2. Pentru a include potriviri de subșiruri, s-ar putea folosi 'value' => sprintf(':"%%%s%%";', $value),. (nu am testat)

6 iul. 2017 14:57:01
0

Puteți încadra valoarea cu % pentru a interoga valoarea serializată:

$args = array(
    'post_type' => 'my-post-type',
    'meta_query' => array(
        array(
            'key' => 'latitude',
            'value' => '%' . 50 . '%',
            'compare' => '>'
        )
    )
 );
$query = new WP_Query( $args );
30 sept. 2023 20:09:06
3
-1

Am aceeași întrebare. Poate ai nevoie de parametrul 'type'? Verifică această întrebare înrudită: Interogare Câmp Personalizat - Valoarea Meta este Array

Poate încercați:

    $args = array(
    'post_type' => 'my-post-type',
    'meta_query' => array(
        array(
            'key' => 'latitude',
            'value' => '50',
            'compare' => '>',
            'type' => 'numeric'
        )
    )
    );
12 mai 2011 20:44:40
Comentarii

Mulțumesc pentru sugestie, dar nu exact asta caut. Problema este că valoarea pe care încerc să o potrivesc face parte dintr-un array care este serializat în baza de date.

tollmanz tollmanz
13 mai 2011 06:10:57

Da, ai dreptate. Am încercat asta dimineață și nici pentru mine nu a funcționat.

Am aceeași problemă. Stochez valoarea unei chei meta ca un array. Încep să cred că nu se poate face asta și că va trebui să le stochez ca câmpuri meta separate cu același nume... și să gestionez corespunzător ștergerea/actualizarea lor.

user4356 user4356
13 mai 2011 18:05:58

@user4356... exact asta am de gând să fac. Speram să reduc numărul de rânduri pe care le-aș insera pentru fiecare post, dar se pare că nu este posibil.

tollmanz tollmanz
14 mai 2011 22:15:09
5
-1

Am întâlnit ceva similar în timp ce foloseam pluginul Magic Fields. Aceasta ar putea fi soluția

$values_serialized = serialize(array('50'));
$args = array(
    'post_type' => 'my-post-type',
    'meta_query' => array(
        array(
            'key' => 'latitude',
            'value' => $values_serialized,
            'compare' => '>'
        )
    )
);
13 mai 2011 00:10:32
Comentarii

Mulțumesc pentru sugestie! Cred că aceasta este cea mai apropiată soluție posibilă, dar nu va funcționa deoarece compararea unui array serializat cu alt array serializat nu are sens decât dacă aș căuta o potrivire exactă.

tollmanz tollmanz
13 mai 2011 06:08:22

Atunci acesta nu ar trebui marcat ca răspuns corect și este iresponsabil din partea ta să faci asta. Răspunsul corect ar fi atunci 'Nu, nu este posibil'.

Tom J Nowell Tom J Nowell
20 aug. 2012 18:14:28

De acord, de asemenea WP se ocupă de serializare pentru tine, serialize() nu este necesar în acest caz...

Adam Adam
20 aug. 2012 19:11:31

De fapt, răspunsul lui @seth-stevenson este excelent atunci când faci exact ce a spus el, folosind pluginul "Magic Fields". Deoarece acel plugin serializează anumite tipuri de date în mod implicit, aceasta este cea mai bună metodă pentru a face o potrivire EXACTĂ.

zmonteca zmonteca
9 ian. 2013 07:02:53

@TomJNowell Gata! Mi-a luat doar 5 luni ;)

tollmanz tollmanz
18 ian. 2013 00:15:31