Domanda

Sto lavorando su un progetto in cui sto creando un tipo messaggio personalizzato e su misura dati inseriti tramite scatole metadati associati con il mio tipo di messaggio personalizzato. Per una qualche ragione ho deciso di codificare le scatole meta in modo tale che gli ingressi in ogni METABOX sono parte di un array. Per esempio, sto memorizzazione longitudine e la latitudine:

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

Per una qualche ragione, mi piaceva l'idea di avere una voce postmeta singolare per ogni METABOX. Sul gancio save_post, risparmio i dati in questo modo:

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

L'ho fatto perché ho tre Metabox e mi piace solo avere 3 valori postmeta per ogni post; tuttavia, ora ho capito un potenziale problema con questo. Mi consiglia di utilizzare WP_Query per tirare solo alcuni posti a base di questi valori meta. Per esempio, mi può essere utile per ottenere tutti i post che hanno valori di latitudine sopra 50. Se ho avuto questi dati nel database singolarmente, magari utilizzando il latitude chiave, vorrei fare qualcosa di simile:

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

Da quando ho la latitudine come parte del postmeta _coordinates, questo non sarebbe il lavoro.

Quindi, la mia domanda è: esiste un modo per utilizzare meta_query per interrogare una matrice serializzato come se avessi in questo scenario?

È stato utile?

Soluzione

No, non è possibile, e potrebbe anche essere pericoloso.

vi consigliamo caldamente di unserialize i dati e modificare il salvataggio di routine. Qualcosa di simile a questo dovrebbe convertire i dati nel nuovo formato:

$args = array(
    '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();
        $c = get_post_meta($post->id,'_coordinates',true);
        add_post_meta($post->ID,'_longitude',$c['longitude']);
        add_post_meta($post->ID,'_latitude',$c['latitude']);
        delete_post_meta($post->ID,'_coordinates',$c);
    }
}

Allora sarete in grado di interrogare come si desidera con i singoli tasti

Se avete bisogno di memorizzare più longitudini e latitudini diverse, è possibile memorizzare più post di meta con lo stesso nome. Basta utilizzare il terzo parametro di get_post_meta, e li restituisce come una matrice

Perché non puoi Query All'interno Serialized dati?

MySQL vede come solo una stringa, e non può rompere lo distingue in dati strutturati. Rompere lo distingue in dati strutturati è esattamente ciò che il codice di cui sopra fa

Si può essere in grado di interrogare per blocchi parziali di oggi, ma questo sarà super inaffidabile, costoso, lento e molto fragile, con un sacco di casi limite. dati serializzati non è destinato per le query SQL, e non è formattato in modo regolare e costante.

A parte i costi delle ricerche di stringhe parziali, meta query pubblicare sono lenti, e dati serializzati possono variare a seconda cose come la lunghezza dei contenuti, rendendo la ricerca incredibilmente costoso, se non impossibile, a seconda del valore che si sta cercando

Una nota sul salvataggio delle registrazioni / Enti / Oggetti come serializzato oggetti a Meta

Si potrebbe desiderare di memorizzare un record della transazione in meta dopo, o qualche altro tipo di struttura dati a Meta utente, quindi eseguire nel problema di cui sopra.

La soluzione qui non è quello di rompere fuori in singolo post meta, ma per rendersi conto che non dovrebbe mai essere meta per cominciare, ma un tipo di messaggio personalizzato. Ad esempio, un registro o di record può essere un tipo di messaggio personalizzato, con il post originale come un genitore, o uniti tramite un termine tassonomia

Sicurezza e serializzato oggetti

Memorizzazione serializzato oggetti PHP tramite la funzione serialize può essere pericoloso che è sfortunato come passaggio di un oggetto a WordPress significherà ottiene serializzato. Questo perché quando l'oggetto è de-serializzato, viene creato un oggetto, e tutta la sua sveglia metodi e costruttori eseguito. Questo potrebbe non sembrare un grosso problema finché un utente non riesce a sgattaiolare un ingresso con cura artigianale, che porta a esecuzione di codice remoto quando i dati vengono letti dal database e de-serializzato da WordPress.

Ciò può essere evitato utilizzando JSON, invece, che rende anche le query più facile, ma è molto più facile / più veloce per solo memorizzare i dati in modo corretto ed evitare di dati serializzati strutturati per cominciare.

Altri suggerimenti

Ho anche eseguito in questa situazione. Ecco quello che ho fatto:

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

Spero che questo aiuto

È davvero stanno andando a perdere la capacità di interrogare i dati in modo efficiente durante la serializzazione voci nel database WP.

Il risparmio prestazioni complessive e di ottenere pensi di raggiungere entro la serializzazione non sta per essere evidente in qualsiasi misura maggiore. Si potrebbe ottenere una dimensione del database leggermente più piccolo, ma il costo delle transazioni SQL sta per essere pesante se mai una query quei campi e cercare di confrontarli in alcun utile, modo significativo.

Al contrario, salvare la serializzazione per i dati che non si intende query in quella natura, ma invece sarebbe solo l'accesso in maniera passiva dal get_post_meta() WP diretta chiamata API - da quella funzione è possibile decomprimere una voce serializzato per accedere sua gamma proprietà troppo.

Infatti assegnato il valore true come;

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

restituirà i dati come una matrice, accessibile per voi per iterare come al solito.

È possibile concentrarsi su altre ottimizzazioni del database / sito, come il caching, CSS e JS minification e l'utilizzo di tali servizi come CDN se avete bisogno. Per citarne solo alcuni .... WordPress Codex è un buon punto di partenza per scoprire di più su questo argomento: QUI

Ho appena distribuiti con campi serializzato e li potrebbe interrogare. Non usando l'meta_query ma utilizzando una query SQL.

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' //add the type because the default will be 'post'
);

$posts = get_posts($args);

Le prime ricerche di query per post con il post_type corrispondente in modo che la quantità di record wp_postmeta sarà meno di filtro. Poi una ho aggiunto in cui dichiarazione per ridurre ulteriormente le righe filtrando il meta_key

Gli ID finire bene in un array come necessario per get_posts.

PS. MySQL v5.6 o superiore è necessario per la buona prestazione subquery

Questo esempio mi ha veramente aiutato. E 'specifico per S2Members Plugin (che serializza metadati utente). Ma permette di interrogare una porzione di una matrice di serializzato all'interno della meta_key.

Funziona utilizzando la funzione di MySQL REGEXP.

Qui è la fonte

Ecco il codice che interroga tutti gli utenti che vivono negli Stati Uniti. Ho facilmente modificato per interrogare uno dei miei campi di registrazione personalizzato e lo fece lavorare in pochissimo tempo.

  <?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 = /* Get full User object now. */ new WP_User ($user->ID);
                print_r($user); /* Get a full list of properties when/if debugging. */
            }
    }
?>

Penso che ci sono 2 soluzioni che possono cercare di risolvere il problema dei risultati vengono archiviati sia come stringa e interi. Tuttavia, è importante dire, come altri hanno sottolineato, che non è possibile garantire l'integrità dei risultati memorizzati come numero intero, perché come questi valori memorizzati come array serializzati, l'indice ed i valori sono memorizzati esattamente con lo stesso modello. Esempio:

array(37,87);

è memorizzato come array serializzato, come questo

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

Si noti la i:0 alla prima posizione della matrice e i:37 come primo valore. Il modello è lo stesso. Ma andiamo alle soluzioni


1) REGEXP Soluzione

Questa soluzione funziona per me, indipendentemente dal valore meta venga salvata come stringa o un numero / id. Tuttavia usa REGEXP, che non è così veloce come l'utilizzo LIKE

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

2) COME Soluzione

Io non sono sicuro circa la differenza di prestazioni, ma si tratta di una soluzione che utilizza LIKE e lavora anche per numero e stringhe

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

Dopo aver letto una serie di consigli per l'esecuzione di un WP_Query filtro per gli array serializzato, ecco come ho finalmente fatto: con la creazione di una serie di virgole valori utilizzando implode separati in combinazione con una query SQL $wpdb personalizzato utilizzando FIND_IN_SET per cercare il separati da virgola lista per il valore richiesto.

(questo è simile alla risposta di Tomas, ma è un po 'meno le prestazioni ad alta intensità per la query SQL)

1. In functions.php:

Nel file functions.php (o dovunque si sta impostando la casella meta) nell'uso funzione di yourname_save_post()

update_post_meta($post->ID, 'checkboxArray', implode(",", $checkboxArray)); //adding the implode

per creare la matrice contenente valori separati da virgola.

Si potrà anche cambiare la variabile di uscita nella funzione yourname_post_meta() amministratore meta scatola di costruzione per

$checkboxArray = explode(",", get_post_custom($post->ID)["checkboxArray"][0]); //adding the explode

2. Nel file di modello di PHP:

Prova: se si esegue un get_post_meta( $id ); si dovrebbe vedere checkboxArray come una matrice contenente il valori separati da virgola invece di un array serializzato

.

Ora, noi costruiamo la nostra query SQL personalizzata utilizzando $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) {
    //your post content here
}

Si noti la FIND_IN_SET, che è dove la magia accade.

Ora ... dal momento che sto usando SELECT * Ciò restituisce tutti i dati post e all'interno del foreach si può eco cosa si vuole da questo (fare un print_r($posts); se non si sa che cosa è incluso. esso non imposta "loop" per voi (io preferisco in questo modo), ma può essere facilmente modificato per impostare il ciclo se si preferisce (date un'occhiata al setup_postdata($post); nel codice, probabilmente necessità di cambiamento SELECT * per selezionare solo messaggio ID e $wpdb->get_results al tipo $wpdb corretto -. consultare il codice per $wpdb anche per informazioni su che soggetto)

Cucciolo, ci sono voluti un po 'di sforzo, ma dal momento che wp_query non supporta facendo 'compare' => 'IN' serializzato o valori separati da virgola questo spessore è la scelta migliore!

Spero che questo aiuta qualcuno.

Se si utilizza l'operatore di confronto like nella query meta, dovrebbe funzionare bene a guardare dentro una matrice di serializzato.

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

Risultati in:

[query_where] => WHERE 1=1 AND (
  ( wp_usermeta.meta_key = 'wp_capabilities' 
  AND CAST(wp_usermeta.meta_value AS CHAR) NOT LIKE '%subscriber%' )

Se la mia meta dati è di tipo array, io sono utilizzare questo metodo per query 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);

ho ottenuto curioso di sapere le risposte di cui sopra, in cui il meta_query mira la latitude chiave invece di _coordinates. Siamo dovuti andare e verificare se fosse possibile davvero nelle query meta di indirizzare un tasto specifico all'interno di una matrice di serializzato. :)

Questo, ovviamente, non era il caso.

Quindi, si noti che la chiave corretta per bersaglio è _coordinates invece di latitude.

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

NOTE:

  1. Questo approccio rende possibile solo per indirizzare corrispondenze esatte. Quindi le cose come tutte le latitudini superiori a 50 non sono possibili.

  2. Per includere corrispondenze sottostringa, si potrebbe usare 'value' => sprintf(':"%%%s%%";', $value),. (Non ho ancora testato)

Ho la stessa domanda. Forse avete bisogno il parametro 'tipo'? Check out questa domanda relativa: campo personalizzato Query - Meta Value è Array

Forse provare:

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

mi sono imbattuto in qualcosa di simile durante l'utilizzo del plugin di magia campi. Questo potrebbe fare il trucco

$values_serialized = serialize(array('50'));
$args = array(
    'post_type' => 'my-post-type',
    'meta_query' => array(
        array(
            'key' => 'latitude',
            'value' => $values_serialized,
            'compare' => '>'
        )
    )
);
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a wordpress.stackexchange
scroll top