Question

Je travaille sur un projet dans lequel je crée un ensemble de données de type de poste personnalisé et personnalisés entrées via des boîtes méta associées à mon type de poste personnalisé. Pour une raison quelconque, j'ai décidé de coder les boîtes de méta de telle sorte que les entrées de chaque METABOX font partie d'un tableau. Par exemple, je suis le stockage longitude et la latitude:

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

Pour une raison quelconque, je l'ai aimé l'idée d'avoir une entrée de postmeta singulier pour chaque METABOX. Sur le crochet save_post, je sauvegarde les données comme ceci:

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

Je l'ai fait parce que j'ai trois Metaboxes et j'aime juste avoir 3 valeurs postmeta pour chaque poste; cependant, j'ai maintenant réalisé un problème potentiel avec cela. Je voudrais peut-être utiliser WP_Query seulement tirer certains postes sur la base de ces valeurs de méta. Par exemple, je veux obtenir tous les messages qui ont des valeurs de latitude au-dessus de 50. Si j'avais ces données dans la base de données individuellement, en utilisant peut-être la clé latitude, je ferais quelque chose comme:

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

Depuis que j'ai la latitude dans le cadre du postmeta de _coordinates, cela ne fonctionnerait pas.

Alors, ma question est, est-il un moyen d'utiliser meta_query pour interroger un tableau sérialisé comme je l'ai dans ce scénario?

Était-ce utile?

La solution

Non, il est impossible, et pourrait même être dangereux.

Je recommande fortement unserialize vos données et de modifier votre sauvegarde de routine. Quelque chose de semblable à ce qui devrait convertir vos données au nouveau format:

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

Ensuite, vous serez en mesure de requête que vous voulez avec les touches individuelles

Si vous avez besoin de stocker plusieurs longitudes et latitudes multiples, vous pouvez stocker plusieurs méta post avec le même nom. Il suffit d'utiliser le troisième paramètre de get_post_meta, et il les renvoyer tout comme un tableau

Pourquoi ne peut pas vous requête à l'intérieur sérialisé données?

MySQL considère comme juste une chaîne, et ne peut pas le briser en données structurées. Décomposant en données structurées est exactement ce que le code ci-dessus fait

Vous pouvez être en mesure d'interroger des morceaux partiels de la date, mais ce sera super peu fiables, coûteux, lent et très fragile, avec beaucoup de cas de pointe. les données sérialisé ne sont pas destinées à des requêtes SQL, et ne sont pas formatés de façon régulière et constante.

Mis à part les coûts de recherche de chaînes partielles, les requêtes post méta sont lentes, et les données sérialisées peuvent changer en fonction des choses telles que la longueur du contenu, ce qui rend la recherche incroyablement cher, sinon impossible en fonction de la valeur que vous recherchez

Une note sur le stockage Records / entités / objets comme des objets sérialisé dans Meta

Vous pouvez stocker un enregistrement de transaction dans la méta poste, ou un autre type de structure de données dans l'utilisateur méta, puis exécutez le problème ci-dessus.

La solution est de ne pas casser ici dehors dans la méta post individuel, mais pour se rendre compte qu'il ne doit jamais avoir été méta pour commencer, mais un type de poste personnalisé. Par exemple, un journal ou un enregistrement peut être un type de poste personnalisé, avec le message original en tant que parent, ou rejoint par un terme de taxonomie

Sécurité et objets sérialisé

Stockage sérialisé objets PHP via la fonction serialize peut être dangereux , ce qui est regrettable que le passage d'un objet à WordPress signifie qu'il se sérialisé. En effet, lorsque l'objet est de sérialisés, un objet est créé, et tout son sillage des méthodes et des constructeurs s'exécuter. Cela pourrait ne pas sembler une grosse affaire jusqu'à ce qu'un utilisateur parvient à se faufiler une entrée conçu avec soin, conduisant à l'exécution de code à distance lorsque les données sont lues à partir de la base de données et de sérialisés par WordPress.

Ceci peut être évité en utilisant JSON à la place, ce qui rend également les requêtes plus facile, mais il est beaucoup plus facile / plus rapide juste stocker les données correctement et éviter des données sérialisées structurées pour commencer.

Autres conseils

J'ai aussi courir dans cette situation. Voici ce que je l'ai fait:

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

Hope this help

Vous allez vraiment perdre la possibilité d'interroger vos données d'une manière efficace lors de la sérialisation entrées dans la base de données de WP.

L'économie de la performance globale et gagnez-vous que vous atteignez par sérialisation ne va pas être perceptible à une grande mesure. Vous pouvez obtenir une taille de base de données un peu plus petit, mais le coût des transactions SQL va être lourd si jamais vous interrogez ces champs et essayer de les comparer en toute utile, de manière significative.

Au lieu de cela, sauvegarde sérialisation pour les données que vous ne l'intention de requête dans cette nature, mais ne ferait que l'accès de façon passive par le get_post_meta() d'appel API WP directe - de cette fonction, vous pouvez décompresser une entrée sérialisé pour accéder à sa gamme propriétés aussi.

En fait attribué la valeur de true comme dans;

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

Est-ce que renvoyer les données dans un tableau, accessible pour vous itérer plus selon la normale.

Vous pouvez vous concentrer sur d'autres optimisations base de données / site telles que la mise en cache, CSS et JS minification et l'utilisation de ces services en tant que CDN si vous avez besoin. Pour ne citer que quelques-uns .... WordPress Codex est un bon point de départ pour découvrir plus sur ce sujet: ICI

Je viens Dealed avec des champs sérialisés et pourrait les interroger. Ne pas utiliser la meta_query mais en utilisant une requête 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);

La requête recherche d'abord pour le poste avec post_type correspondant de sorte que le nombre d'enregistrements wp_postmeta sera moins à filtrer. Ensuite, je l'ai ajouté une déclaration où pour réduire les lignes plus loin en filtrant sur meta_key

Les ID finissent bien dans un tableau comme nécessaire pour get_posts.

PS. MySQL v5.6 ou est nécessaire pour une bonne performance plus élevé de sous-requête

Cet exemple m'a vraiment aidé. Il est spécifiquement pour le plugin S2Members (qui sérialise métadonnées utilisateur). Mais il vous permet d'interroger une partie d'un tableau sérialisé dans le meta_key.

Il fonctionne en utilisant la fonction MySQL REGEXP.

est la source

Voici le code qui interroge tous les utilisateurs vivant aux Etats-Unis. Je facilement modifié pour interroger un de mes champs d'enregistrement personnalisé et avait fonctionner en peu de temps.

  <?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. */
            }
    }
?>

Je pense qu'il ya 2 solutions qui peuvent tenter de résoudre le problème des résultats étant stockés à la fois comme chaîne et Entiers. Cependant, il est important de dire, comme d'autres l'ont souligné, qu'il est impossible de garantir l'intégrité des résultats enregistrés en entier, parce que ces valeurs stockées sous forme de tableaux sérialisés, l'index et les valeurs sont stockées exactement avec le même motif. Exemple:

array(37,87);

est stockée sous forme de tableau sérialisé, comme ceci

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

Notez la i:0 que la première position de la matrice et i:37 que la première valeur. Le schéma est le même. Mais allons-y aux solutions


1) REGEXP Solution

Cette solution fonctionne pour moi quelle que soit la valeur de méta étant enregistrée sous forme de chaîne ou / numéro d'identification. Cependant, il utilise REGEXP, ce qui est si rapide que l'utilisation LIKE

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

2) Solution comme

Je ne suis pas sûr de la différence de performance, mais cela est une solution qui utilise LIKE et travaille aussi pour nombre et chaînes

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

Après avoir lu un tas de conseils pour l'exécution d'un WP_Query filtrage par des tableaux sérialisés, voici comment je finalement fait: en créant un tableau séparés par des virgules valeurs à l'aide imploser en conjonction avec une coutume $wpdb requête SQL en utilisant FIND_IN_SET pour rechercher la séparés par des virgules liste pour la valeur demandée.

(ce qui est similaire à la réponse de Tomas, mais son un peu moins de performance intensive pour la requête SQL)

1. En functions.php:

Dans votre fichier functions.php (ou chaque fois que vous configurez la boîte de méta) dans l'utilisation de la fonction yourname_save_post()

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

pour créer la matrice contenant des valeurs séparées par des virgules.

Vous devrez également modifier votre variable de sortie dans la fonction de construction de la boîte yourname_post_meta() admin meta à

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

2. Dans le fichier PHP modèle:

Test: si vous exécutez un get_post_meta( $id ); vous devriez voir checkboxArray comme un tableau contenant votre valeurs séparées par des virgules au lieu d'un tableau sérialisé

.

Maintenant, nous construisons notre requête SQL personnalisée à l'aide $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
}

Notez que le FIND_IN_SET, qui est où la magie se produit.

... depuis que je suis en utilisant ce SELECT * retourne toutes les données post et dans le foreach vous pouvez faire écho à ce que vous voulez que (faire un print_r($posts); si vous ne savez pas ce qui est inclus. il n'a pas mis en place « la boucle » pour vous (je préfère cette façon), mais il peut facilement être modifié pour mettre en place la boucle si vous préférez (jetez un oeil à setup_postdata($post); dans le codex, vous aurez probablement besoin de changer SELECT * de ne sélectionner que ce poste ID et $wpdb->get_results au type de $wpdb correct -. voir le codex pour $wpdb également des informations sur que sujet)

dragonnet, il a fallu un peu d'effort, mais étant donné que wp_query ne supporte pas les faire 'compare' => 'IN' valeurs séparées par des virgules ou sérialisé cette cale est votre meilleure option!

Espérons que cela aide quelqu'un.

Si vous utilisez l'opérateur de comparaison de like dans votre méta requête, il devrait fonctionner correctement regarder à l'intérieur d'un tableau sérialisé.

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

résultats dans:

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

Si mes données méta est de type tableau, je suis utiliser cette méthode pour la requête par 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);

je me suis curieux de connaître les réponses ci-dessus, où le meta_query ciblé la latitude clé au lieu de _coordinates. Nous avons dû aller et tester si elle était vraiment possible dans les requêtes méta pour cibler une clé spécifique à l'intérieur d'un tableau sérialisé. :)

Ce n'était évidemment pas le cas.

Alors, notez que la bonne clé pour cible est _coordinates au lieu de latitude.

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

NOTES:

  1. Cette approche permet seulement de cibler les correspondances exactes. Donc, des choses comme toutes les latitudes supérieures à 50 ne sont pas possibles.

  2. Pour inclure des correspondances de sous, on pourrait utiliser 'value' => sprintf(':"%%%s%%";', $value),. (N'ont pas testé)

J'ai la même question. Peut-être que vous avez besoin du paramètre « type »? Consultez cette question connexe: champ personnalisé requête - Meta valeur est un tableau

Peut-être essayer:

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

je suis tombé sur quelque chose de similaire en utilisant le plugin Fields magique. Cela pourrait faire l'affaire

$values_serialized = serialize(array('50'));
$args = array(
    'post_type' => 'my-post-type',
    'meta_query' => array(
        array(
            'key' => 'latitude',
            'value' => $values_serialized,
            'compare' => '>'
        )
    )
);
Licencié sous: CC-BY-SA avec attribution
Non affilié à wordpress.stackexchange
scroll top