meta_query con valores meta como arrays serializados
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?

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
- Por qué
- 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
conLIKE
también coincidirá contest
,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.

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

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

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

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',
),
),

@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

@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

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.

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

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

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

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

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Í

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

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/ :-)

@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

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á :-)

@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

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

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

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

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.

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%' )

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

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:
Este enfoque solo permite apuntar a coincidencias exactas. Así que cosas como todas las latitudes mayores que 50 no son posibles.
Para incluir coincidencias de substrings, se podría usar
'value' => sprintf(':"%%%s%%";', $value),
. (no lo he probado)

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

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.

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.

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

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

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'

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

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.
