meta_query con valores meta como arrays serializados

9 may 2011, 05:06:35
Vistas: 81.7K
Votos: 51

Estoy trabajando en un proyecto en el que estoy creando un tipo de entrada personalizada y datos personalizados ingresados a través de meta boxes asociados con mi tipo de entrada personalizada. Por alguna razón, decidí programar los meta boxes de tal manera que las entradas en cada metabox son parte de un array. Por ejemplo, estoy almacenando longitud y latitud:

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

Por alguna razón, me gustó la idea de tener una única entrada postmeta para cada metabox. En el hook save_post, guardo los datos así:

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

Hice esto porque tengo tres metaboxes y me gusta tener solo 3 valores postmeta para cada entrada; sin embargo, ahora me he dado cuenta de un posible problema. Puede que quiera usar WP_Query para extraer solo ciertas entradas basadas en estos valores meta. Por ejemplo, puede que quiera obtener todas las entradas que tengan valores de latitud superiores a 50. Si tuviera estos datos en la base de datos individualmente, tal vez usando la clave latitude, lo haría así:

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

Como tengo la latitud como parte del postmeta _coordinates, esto no funcionaría.

Entonces, mi pregunta es, ¿hay alguna manera de utilizar meta_query para consultar un array serializado como el que tengo en este escenario?

0
Todas las respuestas a la pregunta 14
6
52

No, no es posible, e incluso podría ser peligroso.

No hay una forma confiable de hacer esto sin encontrarse con trampas y problemas como que una búsqueda de 10 coincida con 100 o 210, o que coincida con un subvalor incorrecto, etc. Estas soluciones no son confiables y tienen problemas de rendimiento y seguridad.

Los datos serializados son un vector de ataque y un problema importante de rendimiento.

Cubriré:

  • Corregirlo y hacerlo consultable
  • ¿Por qué no puedes consultar dentro de datos serializados?
    • Por qué LIKE no es una solución
  • Una nota sobre almacenar registros/entidades/objetos como objetos serializados en meta
  • Seguridad y objetos serializados
  • ¿Qué hacer si tengo una lista de IDs?
  • ¿Qué hacer si tengo un array de elementos con nombre?
  • Evitar el problema por completo
  • Conclusión

¿Pero qué pasa con LIKE?

Puede que veas algunas preguntas bien intencionadas que sugieren usar LIKE para lograr esto. ¿Esto no resuelve el problema? Esta no es la solución, es un espejismo.

Hay varios problemas importantes:

  • coincidencias falsas, buscar test con LIKE también coincidirá con test, testing, untested y otros valores
  • no hay forma de restringir esto a subclaves para arrays con claves u objetos
  • no es posible hacer ordenación
  • es extremadamente lento y costoso

LIKE solo funcionará para situaciones específicas y limitadas que no son realistas, y conlleva una fuerte penalización de rendimiento.

Corrigiendo el problema y haciéndolo consultable

Recomiendo encarecidamente que deserialices tus datos y modifiques tu rutina de guardado. Algo similar a esto debería convertir tus datos al nuevo formato:

$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();
        // obtener los datos
        $c = get_post_meta( $post->ID, '_coordinates', true );

        // guardarlos en el nuevo formato, meta de post separada, término de taxonomía, etc
        add_post_meta( $post->ID, '_longitude', $c['longitude'] );
        add_post_meta( $post->ID, '_latitude', $c['latitude'] );

        // Opcional: limpiar el meta antiguo
        delete_post_meta( $post->ID, '_coordinates', $c );
    }
    wp_reset_postdata();
}

Luego podrás consultar como desees con claves individuales.

Si necesitas almacenar múltiples longitudes y latitudes, puedes almacenar múltiples metas de post con el mismo nombre. Simplemente usa el tercer parámetro de get_post_meta, y devolverá todas como un array.

¿Por qué no puedes consultar dentro de datos serializados?

MySQL lo ve solo como una cadena, y no puede separarlo en datos estructurados. Separarlo en datos estructurados es exactamente lo que hace el código anterior.

Puede que puedas consultar por fragmentos parciales de datos, pero esto será muy poco confiable, costoso, lento y muy frágil, con muchos casos extremos. Los datos serializados no están destinados a consultas SQL, y no están formateados de una manera regular y constante.

Además de los costos de las búsquedas parciales de cadenas, las consultas de meta de post son lentas, y los datos serializados pueden cambiar dependiendo de cosas como la longitud de los contenidos, haciendo que la búsqueda sea increíblemente costosa, si no imposible dependiendo del valor que estés buscando.

Una nota sobre almacenar registros/entidades/objetos como objetos serializados en meta

Puede que quieras almacenar un registro de transacción en meta de post, o alguna otra estructura de datos en meta de usuario, y luego toparte con el problema anterior.

La solución aquí no es separarlo en metas de post individuales, sino darse cuenta de que nunca debería haber sido meta para empezar, sino un tipo de post personalizado. Por ejemplo, un registro o historial puede ser un tipo de post personalizado, con el post original como padre, o unido mediante un término de taxonomía.

Seguridad y objetos serializados

Almacenar objetos PHP serializados mediante la función serialize puede ser peligroso, lo cual es desafortunado ya que pasar un objeto a WordPress hará que se serialice. Esto se debe a que cuando el objeto se deserializa, se crea un objeto, y todos sus métodos de despertar y constructores se ejecutan. Esto puede no parecer gran cosa hasta que un usuario logra colar una entrada cuidadosamente diseñada, llevando a la ejecución remota de código cuando los datos se leen de la base de datos y se deserializan por WordPress.

Esto puede evitarse usando JSON en su lugar, lo que también facilita las consultas, pero es mucho más fácil/rápido simplemente almacenar los datos correctamente y evitar los datos estructurados serializados desde el principio.

¿Qué hacer si tengo una lista de IDs?

Puedes sentirte tentado a darle a WP un array, o convertirlo en una lista separada por comas, ¡pero no tienes que hacerlo!

Las claves de meta de post no son únicas, puedes almacenar la misma clave múltiples veces, por ejemplo:


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

¿Pero cómo recupero los datos? ¿Alguna vez has notado que las llamadas a get_post_meta tienen un tercer parámetro que siempre está en true? Ponlo en false:

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

¿Qué hacer si tengo un array de elementos con nombre?

¿Qué pasa si quiero almacenar esta estructura de datos de una manera que me permita consultar los campos?

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

Es fácil, divídelo con prefijos:

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

Y si necesitas iterar sobre algunos de esos valores, usa get_post_meta( $id ); para obtener todas las metas de post e iterar sobre las claves, por ejemplo:

$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; // no coincide, ¡saltar!
    }
    echo '<p>' . $key . ' = ' . $value . '</p>';
}

Lo que daría como resultado:

<p>tomsdata_parent_child = value</p>

Recuerda, cuando WP recupera un post, también recupera todas sus metas de post al mismo tiempo, por lo que las llamadas a get_post_meta son muy económicas y no generan consultas adicionales a la base de datos.

Evitar el problema por completo

Si sabes que vas a necesitar buscar/consultar/filtrar un subvalor, ¿por qué no almacenar una meta de post adicional con ese valor para poder buscarlo?

Conclusión

Así que no necesitas almacenar datos estructurados como una cadena en la base de datos, y no deberías hacerlo si planeas buscar/consultar/filtrar esos valores.

Puede que sea posible usar una expresión regular y un LIKE, pero esto es extremadamente poco confiable, no funciona para la mayoría de los tipos de datos, y es muy, muy lento y pesado para la base de datos. Tampoco puedes realizar operaciones matemáticas con los resultados como podrías si fueran valores separados.

20 ago 2012 18:19:49
Comentarios

Para las personas que pasan por aquí, no dejen de leer: hay respuestas más útiles (y recientes) más abajo

Erenor Paz Erenor Paz
13 abr 2017 13:07:01

¿Qué pasa si tengo un array de IDs para guardar - y no representan cada uno una clave diferente bajo la cual podría guardarlos como 'latitude' etc., es solo una clave para todos (como al guardar relaciones, etc.). ¿Qué hacer entonces? ¿La solución de @rabni?

trainoasis trainoasis
16 jun 2017 10:52:59

Puedes almacenar una clave más de una vez, los pares clave-valor no son únicos. En cuanto a las relaciones, para eso están las taxonomías, si estás usando meta para mapear múltiples cosas en algo, colócalas en un término de taxonomía en su lugar

Tom J Nowell Tom J Nowell
19 jun 2017 20:31:41

Por supuesto que es posible. Sí, necesitas asegurarte de tener valores únicos, que es la naturaleza misma de este tipo de postmeta. Normalmente, estos valores serializados provienen de checkboxes que son arrays. Cada checkbox del conjunto debería tener un valor único. Y si no, se aseguran de que su opción (en php: la clave del array) sea única, para que puedas encontrarlo.

Posteriormente, la consulta es tarea sencilla comparada con tu solución presentada: 'meta_query' => array( array( 'key' => 'thekey', 'value' => 'thevalue', 'compare' => 'LIKE', 'type' => 'CHAR', ), ),

User User
17 feb 2023 09:42:18

@BedaSchmid eso no hace lo que crees que hace, si hubieras leído mi respuesta verías que abordé la cláusula LIKE y señalé fallos importantes en ella que impiden que sea confiable y causan errores. Mira la parte titulada "¿Qué pasa con LIKE?". He editado mi respuesta para moverla más arriba para las personas que no leen toda la respuesta, ya que ha habido varios casos a lo largo de los años

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

@TomJNowell - de esas 4 razones, solo una es un problema serio y como mencioné en mi comentario es evitable. ¿Lento? Sí. Cada consulta meta es lenta. ¿Ordenar por? Ok. Supongo que si realmente necesitas consultar por ese campo podrías pasar por alto ordenar por él. Es un poco raro ordenar por un array donde se pueden seleccionar múltiples opciones. Sí es posible consultar por esos valores y no devuelve resultados inexactos, siempre que el array serializado tenga valores únicos, como menciono en mi comentario

User User
18 feb 2023 12:50:12
Mostrar los 1 comentarios restantes
6
41

También me encontré en esta situación. Esto es lo que hice:

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

Espero que esto ayude

16 abr 2015 15:38:57
Comentarios

Realmente me gustó esta solución. Lamentablemente, esto no es aplicable cuando el $value también es un ID. En ese caso, sugiero crear dos funciones: una para añadir un carácter a cada elemento del array antes de guardar los datos y otra para eliminar ese carácter antes de usar los datos. De esta manera, el índice serializado i:2 no se confundirá con el i:D2 de los datos "reales". El parámetro de la meta consulta debería entonces ser 'value' => sprintf(':"D%s";', $value), y mantendrás la funcionalidad correcta de esta maravillosa respuesta.

Erenor Paz Erenor Paz
13 abr 2017 12:30:09

Esta solución me está funcionando

Rakhi Rakhi
12 ene 2018 11:32:02

Esto también funcionó perfectamente para mí. Aunque tuve un mini susto cuando vi la solución aceptada

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

@Erenor Paz, acabo de publicar una solución que funciona bien tanto con ID como con cadenas: https://wordpress.stackexchange.com/a/299325/25264

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

usar LIKE es una forma genial y rápida de tumbar tu servidor (sin mencionar los falsos positivos) mejor ten un buen sistema de caché.

Mark Kaplun Mark Kaplun
2 abr 2018 08:23:41

Ten en cuenta que con esta solución, coincidirá con cualquier subvalor que tenga ese valor. Así que si buscas una latitud de 5, también coincidirá con longitudes de 5. Esto es menos problemático en este caso de uso particular, pero es algo a tener en cuenta. Además, es imposible ordenar los resultados, y no se puede realizar ninguna lógica/matemática como recuperar todos los valores que estén por encima o por debajo de un número

Tom J Nowell Tom J Nowell
29 may 2020 12:29:37
Mostrar los 1 comentarios restantes
0
11

Realmente vas a perder la capacidad de consultar tus datos de manera eficiente cuando serialices entradas en la base de datos de WordPress.

El ahorro y la mejora de rendimiento general que crees estar logrando con la serialización no será notable en gran medida. Podrías obtener una base de datos ligeramente más pequeña, pero el costo de las transacciones SQL será alto si alguna vez consultas esos campos e intentas compararlos de manera útil y significativa.

En su lugar, reserva la serialización para datos que no pretendas consultar de esa manera, sino que solo accederías de forma pasiva mediante la llamada directa a la API de WordPress get_post_meta() - desde esa función, también puedes desempacar una entrada serializada para acceder a sus propiedades de array.

De hecho, asignar el valor true como en:

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

Devolverá los datos como un array, accesible para que puedas iterar sobre él como de costumbre.

Puedes enfocarte en otras optimizaciones de base de datos/sitio, como el almacenamiento en caché, la minificación de CSS y JS, y el uso de servicios como una CDN si lo requieres. Por mencionar algunos... El Codex de WordPress es un buen punto de partida para descubrir más sobre ese tema: AQUÍ

20 ago 2012 17:36:42
5

Creo que hay 2 soluciones que pueden intentar resolver el problema de los resultados almacenados como String y Enteros. Sin embargo, es importante mencionar, como otros han señalado, que no es posible garantizar la integridad de los resultados almacenados como Entero, ya que estos valores se guardan como arrays serializados, el índice y los valores se almacenan exactamente con el mismo patrón. Ejemplo:

array(37,87);

se almacena como un array serializado, así:

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

Observa el i:0 como la primera posición del array y i:37 como el primer valor. El patrón es el mismo. Pero vayamos a las soluciones


1) Solución con REGEXP

Esta solución funciona para mí independientemente de que el valor meta se guarde como string o número/id. Sin embargo, utiliza REGEXP, que no es tan rápido como usar LIKE

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

2) Solución con LIKE

No estoy seguro de la diferencia en rendimiento, pero esta es una solución que usa LIKE y también funciona tanto para números como strings

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

REGEXP es útil en ciertas situaciones, pero si puedes usar LIKE, creo que es el método preferible. Un enlace antiguo, pero aún bastante útil, en mi opinión: https://thingsilearn.wordpress.com/2008/02/28/mysql-query-speed-regexp-vs-like/ :-)

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

@ErenorPaz Tienes razón. LIKE es más rápido. Pero esta es una solución que funciona tanto para cadenas como para números

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

Sí... así que, la respuesta es (como siempre): dependiendo de la situación, si puedes usar "LIKE"; es preferible, de lo contrario REGEXP también funcionará :-)

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

@ErenorPaz, edité mi respuesta agregando una nueva solución que usa LIKE pero funciona tanto para números como para cadenas. No estoy seguro del rendimiento porque tiene que comparar los resultados usando OR

Pablo S G Pacheco Pablo S G Pacheco
1 abr 2018 22:41:09

¡Exactamente! Lo que necesito es obtener un resultado como este...

¡¡¡Gracias hombre!!!

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

Acabo de trabajar con campos serializados y pude consultarlos. No usando meta_query sino usando una consulta 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' //agrego el tipo porque por defecto será 'post'
);

$posts = get_posts($args);

La consulta primero busca posts con el post_type coincidente para que la cantidad de registros en wp_postmeta sea menor al filtrar. Luego agregué una condición WHERE para reducir aún más las filas filtrando por meta_key

Los IDs terminan ordenados en un array como se necesita para get_posts.

PD: Se necesita MySQL v5.6 o superior para un buen rendimiento de las subconsultas

22 ago 2013 12:41:49
2

Un truco sencillo para esta situación es usar la comparación LIKE con el formato serializado (longitud con tipo y el valor en sí) como se muestra a continuación:

$id = 123; // ID que se verificará en los datos serializados.
//(asumiendo que los números se almacenan como cadena. En mi caso así fue.)

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

Si es una taxonomía personalizada para buscar:

$id = 123; // ID que se verificará en los datos serializados.
//(asumiendo que los números se almacenan como cadena. En mi caso así fue.)

$args = array(
    'hide_empty' => false, // también recupera términos que aún no se han usado
    '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 may 2022 16:22:19
Comentarios

Diría que este ejemplo responde directamente a la pregunta y es exactamente lo que estaba buscando.

Sharpey Sharpey
18 may 2023 01:25:34

Esto resuelve exactamente el problema, ¡la mejor respuesta aquí!

rank rank
20 feb 2024 19:55:03
1

Este ejemplo realmente me ayudó. Es específicamente para el plugin S2Members (que serializa los metadatos de usuario). Pero te permite consultar una porción de un arreglo serializado dentro de la meta_key.

Funciona utilizando la función REGEXP de MySQL.

Aquí está la fuente

Aquí está el código que consulta todos los usuarios que viven en EE.UU. Lo modifiqué fácilmente para consultar uno de mis campos de registro personalizados y lo tuve funcionando en poco tiempo.

  <?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 = /* Obtener el objeto de Usuario completo ahora. */ new WP_User ($user->ID);
                print_r($user); /* Obtener una lista completa de propiedades al depurar. */
            }
    }
?>
12 dic 2012 20:43:48
Comentarios

Gracias. Esto fue lo único que funcionó cuando intentaba obtener datos serializados de un plugin de terceros.

adamalexanderw adamalexanderw
25 abr 2023 12:40:45
0

Después de leer varios consejos sobre cómo ejecutar una consulta WP_Query filtrando por arrays serializados, aquí está cómo finalmente lo resolví: creando un array de valores separados por comas usando implode junto con una consulta SQL personalizada utilizando $wpdb y la función FIND_IN_SET para buscar en la lista separada por comas el valor solicitado.

(esto es similar a la respuesta de Tomás, pero es un poco menos intensivo en rendimiento para la consulta SQL)

1. En functions.php:

En tu archivo functions.php (o donde estés configurando el meta box) dentro de la función yourname_save_post() usa:

update_post_meta($post->ID, 'checkboxArray', implode(",", $checkboxArray)); //añadiendo el implode

para crear el array conteniendo los valores separados por comas.

También querrás cambiar tu variable de salida en la función de construcción del meta box administrativo yourname_post_meta() a:

$checkboxArray = explode(",", get_post_custom($post->ID)["checkboxArray"][0]); //añadiendo el explode

2. En el archivo PHP de la plantilla:

Prueba: si ejecutas un get_post_meta( $id ); deberías ver checkboxArray como un array conteniendo tus valores separados por comas en lugar de un array serializado.

Ahora, construimos nuestra consulta SQL personalizada usando $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) {
    //tu contenido del post aquí
}

Observa el FIND_IN_SET, ahí es donde ocurre la magia.

Ahora... dado que estoy usando SELECT * esto devuelve todos los datos del post y dentro del foreach puedes mostrar lo que quieras de eso (haz un print_r($posts); si no sabes qué está incluido. No configura "el loop" por ti (prefiero que sea así), pero puede modificarse fácilmente para configurar el loop si lo prefieres (echa un vistazo a setup_postdata($post); en el codex, probablemente necesitarás cambiar SELECT * para seleccionar solo IDs de posts y $wpdb->get_results al tipo correcto de $wpdb -- consulta el codex sobre $wpdb también para información sobre ese tema).

Bueno, requirió un poco de esfuerzo, pero dado que wp_query no soporta hacer 'compare' => 'IN' con valores serializados o separados por comas, ¡esta solución es tu mejor opción!

Espero que esto ayude a alguien.

23 ene 2015 00:10:32
0

Si utilizas el operador de comparación like en tu consulta meta, debería funcionar correctamente para buscar dentro de un array serializado.

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

resulta en:

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

Si mis metadatos son de tipo array, uso este método para consultar por 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 jul 2016 09:50:49
Comentarios

Esto podría generar resultados no deseados cuando el ID de una publicación tiene el mismo valor que el ID de la cadena serializada

Erenor Paz Erenor Paz
13 abr 2017 13:05:22
0

Me llamó la atención las respuestas anteriores donde el meta_query apuntaba a la clave latitude en lugar de _coordinates. Tuve que ir y probar si realmente era posible en las meta queries apuntar a una clave específica dentro de un array serializado. :)

Obviamente ese no era el caso.

Así que, ten en cuenta que la clave correcta a la que apuntar es _coordinates en lugar de latitude.

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

NOTAS:

  1. Este enfoque solo permite apuntar a coincidencias exactas. Así que cosas como todas las latitudes mayores que 50 no son posibles.

  2. Para incluir coincidencias de substrings, se podría usar 'value' => sprintf(':"%%%s%%";', $value),. (no lo he probado)

6 jul 2017 14:57:01
0

Puedes encerrar el valor con % para consultar el valor serializado:

$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

Tengo la misma pregunta. ¿Quizás necesites el parámetro 'type'? Echa un vistazo a esta pregunta relacionada: Consulta de Campos Personalizados - Meta Valor es un Array

Tal vez prueba con:


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

Gracias por la sugerencia, pero esto no es exactamente lo que estoy buscando. El problema es que el valor que intento coincidir es parte de un array que está serializado dentro de la base de datos.

tollmanz tollmanz
13 may 2011 06:10:57

Sí, tienes razón. Intenté esto esta mañana y tampoco funcionó para mí.

Tengo el mismo problema. Almacenar un valor de una meta clave como un array. Estoy empezando a pensar que esto no se puede hacer y que en su lugar tendré que almacenarlos como campos meta separados con el mismo nombre... y simplemente gestionar la eliminación/actualización de ellos correctamente.

user4356 user4356
13 may 2011 18:05:58

@user4356... eso es exactamente lo que voy a hacer. Esperaba reducir el número de filas que insertaría para cada publicación, pero supongo que no es posible.

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

Me encontré con algo similar mientras usaba el plugin Magic Fields. Esto podría funcionar:

$values_serialized = serialize(array('50'));
$args = array(
    'post_type' => 'my-post-type',
    'meta_query' => array(
        array(
            'key' => 'latitude', // Clave del campo personalizado
            'value' => $values_serialized, // Valor serializado para comparar
            'compare' => '>' // Operador de comparación (mayor que)
        )
    )
);
13 may 2011 00:10:32
Comentarios

¡Gracias por la sugerencia! Creo que esto es lo más cercano que se puede conseguir, pero en realidad no funcionará porque comparar un array serializado con otro array serializado no tiene sentido a menos que estuviera buscando una coincidencia exacta.

tollmanz tollmanz
13 may 2011 06:08:22

Entonces esto no debería marcarse como la respuesta correcta y es irresponsable de tu parte hacerlo. La respuesta correcta por lo tanto sería 'No, no es posible'

Tom J Nowell Tom J Nowell
20 ago 2012 18:14:28

De acuerdo, además WP maneja la serialización por ti, serialize() no es necesario en este caso...

Adam Adam
20 ago 2012 19:11:31

En realidad, la respuesta de @seth-stevenson es excelente cuando se hace exactamente lo que él dijo, usando el plugin "Magic Fields". Como ese plugin serializa ciertos tipos de datos por defecto, esta es la mejor manera de hacer una coincidencia EXACTA.

zmonteca zmonteca
9 ene 2013 07:02:53

@TomJNowell ¡Listo! Solo me tomó 5 meses ;)

tollmanz tollmanz
18 ene 2013 00:15:31