¿Cómo consultar posts por clave meta parcial?
Tengo una función que almacena el estado "like" de una entrada como meta post. Quiero asociar ese "like" con el usuario que lo dio, así que configuré un campo personalizado llamado "like_status_{user_id}" (donde {user_id} es el id del usuario actualmente conectado) que almaceno como 0 o 1. Así que para una entrada con varios "likes" habría varios valores meta en la base de datos configurados así:
'meta_key' = 'like_status_0'
'meta_value' = 1
'meta_key' = 'like_status_2'
'meta_value' = 1
'meta_key' = 'like_status_34'
'meta_value' = 1
...y así sucesivamente.
Potencialmente hay miles de likes en una entrada específica. ¿Cómo ejecutaría una consulta que mostrara si alguien más también le dio like a esa entrada?
Estaba pensando en algo como esto:
$query = new WP_Query(array(
'meta_key' => 'like_status_{user_id}',
'meta_value' => 1,
));
Estoy tratando de enviar una notificación a todos los que han dado like a una entrada cuando alguien más le da like... algo como: "¡Hey, alguien más le dio like a esa entrada que te gustó. ¡Deberías ir a verla!" Pero necesito una manera de averiguar si alguien más le ha dado like a esa entrada y si es así, quiénes serían para poder notificarles.
Si no es posible, ¿podrías sugerir una mejor manera de almacenar estos datos como post_meta mientras se mantiene la eficiencia de actualizar rápidamente el estado de like de un solo usuario en una entrada?

Es bastante difícil responder concretamente a tu pregunta. La primera parte es fácil, sin embargo. Recientemente hice algo similar en stackoverflow.
Las meta claves se comparan y coinciden exactamente. WP_Query
no tiene forma de ajustar este comportamiento con un parámetro simple, pero siempre podemos introducir uno nosotros mismos y luego ajustar la cláusula posts_where
para hacer una comparación LIKE
en las meta claves.
EL FILTRO
Este es solo un filtro básico, ajústalo según sea necesario.
add_filter( 'posts_where', function ( $where, \WP_Query $q )
{
// Verifica nuestra variable de consulta personalizada
if ( true !== $q->get( 'wildcard_on_key' ) )
return $where;
// Filtramos la cláusula
$where = str_replace( 'meta_key =', 'meta_key LIKE', $where );
return $where;
}, 10, 2 );
Como puedes ver, el filtro solo se activa cuando establecemos nuestro nuevo parámetro personalizado, wildcard_on_key
en true
. Cuando esto se cumple, simplemente cambiamos el comparador =
por el comparador LIKE
.
Solo una nota sobre esto, las comparaciones LIKE
son inherentemente más costosas de ejecutar que otras comparaciones.
LA CONSULTA
Puedes consultar tus publicaciones de la siguiente manera para obtener todas las publicaciones con meta claves like_status_{user_id}
.
$args = [
'wildcard_on_key' => true,
'meta_query' => [
[
'key' => 'like_status_',
'value' => 1,
]
]
];
$query = new WP_Query( $args );
OTRA PREGUNTA
Los campos personalizados no tienen impacto en el rendimiento, puedes leer mi publicación sobre este tema aquí. Sin embargo, me preocupa que digas que cada publicación puede tener cientos o miles de "me gusta". Esto puede afectarte en el rendimiento al obtener y almacenar en caché una gran cantidad de datos de campos personalizados. También puede saturar tu base de datos con una gran cantidad de datos de campos personalizados innecesarios, lo que dificulta su mantenimiento.
No soy un gran fanático de almacenar datos serializados en campos personalizados, ya que no se pueden buscar ni ordenar por datos serializados. Sin embargo, sugeriría almacenar todos los ID de usuario en un array bajo un solo campo personalizado. Puedes simplemente actualizar el array con el ID del usuario cuando a un usuario le guste una publicación. Obtener los datos del campo personalizado y recorrer el array de ID's para hacer algo con ellos es fácil. Solo echa un vistazo a get_post_meta()
.
Actualizar un campo personalizado también es fácil. Para eso, deberás consultar update_post_meta()
, no sé cómo creas tus campos personalizados, pero update_post_meta()
es definitivamente algo que querrás usar.
Si necesitas enviar correos electrónicos o notificaciones push cuando se actualiza un campo personalizado, tienes los siguientes hooks disponibles para trabajar. (Consulta update_metadata()
para contexto)
CONCLUSIÓN
Antes de publicar esto, nuevamente, antes de que tomes la ruta de serialización, asegúrate de que no necesitarás ordenar por los datos serializados o buscar datos particulares dentro de los datos serializados.

¡Gracias por tu explicación sobre el rendimiento de post_meta! Muy útil.

Esta debería ser la respuesta aceptada, siempre es mejor usar filtros en lugar de consultas personalizadas. También, ten en cuenta que si estás usando get_posts en lugar de WP_Query, necesitas pasar suppress_filters => false o no activará el filtro. Para realizar el LIKE en la clave meta, también necesitas poner % delante y detrás de la clave en el array dependiendo del tipo de búsqueda LIKE que quieras hacer.

Desafortunadamente no puedes realizar un meta_query
usando una comparación LIKE
en el valor de meta_key
cuando usas WP_Query
. Ya he pasado por esto...
En su lugar, tienes un par de opciones si deseas mantener las relaciones de "like" como meta del post y no como meta del usuario o meta en una tabla personalizada.
Opción 1
- no requiere modificación de tu esquema de meta
- usa la clase
wpdb
para realizar una consulta personalizada
Ejemplo:
//cuando un usuario da like a un post...
$current_user_id = get_current_user_id();
add_post_meta($current_user_id, "like_status_{$current_user_id}", 1, false);
//más tarde en la solicitud...
global $wpdb;
$results = $wpdb->get_results(
"
SELECT meta_key
FROM {$wpdb->prefix}postmeta
WHERE meta_key
LIKE 'like_status_%'
",
ARRAY_N
);
$results = array_map(function($value){
return (int) str_replace('like_status_', '', $value[0]);
}, $results);
array_walk($results, function($notify_user_id, $key){
//aplicar a todos los usuarios excepto al que dio like al post
if ( $notify_user_id !== $current_user_id ) {
//lógica de notificación aquí...
}
});
Nota: la lógica podría simplificarse aún más si lo deseas.
Opción 2
- requiere que cambies tu esquema de meta
- requiere que almacenes el ID del usuario como valor meta
- te permite usar
WP_Query
junto conmeta_query
La Opción 2 requiere que cambies tu clave meta de like_status_{user_id}
a algo universal como like_status
o liked_by_user_id
, donde en lugar de almacenar el valor 1
contra la clave, almacenes el ID del usuario como valor.
//cuando un usuario da like a un post...
$current_user_id = get_current_user_id();
add_post_meta($current_user_id, "liked_by_user_id", $current_user_id, false);
//más tarde en la solicitud
$args = array(
'post_type' => 'post', //o un tipo de post de tu elección
'posts_per_page' => -1,
'meta_query' => array(
array(
'key' => 'liked_by_user_id',
'value' => 0,
'type' => 'numeric'
'compare' => '>'
)
)
);
$query = new WP_Query($args);
array_walk($query->posts, function($post, $key){
$user_ids = get_post_meta($post->ID, 'liked_by_user_id');
array_walk($user_ids, function($notify_user_id, $key){
//notificar a todos los usuarios excepto al que dio like al post
if ( $notify_user_id !== $current_user_id ) {
//lógica de notificación aquí...
//obtener usuario ej. $user = get_user_by('id', $notify_user_id);
}
});
});

Por favor actualiza la respuesta aceptada para reflejar las últimas capacidades de WP o marca la respuesta de @K.Tromp como la más actualizada

Si más adelante deseas extender esto, con estadísticas más detalladas, características, etc., entonces otra alternativa podría ser: tabla(s) personalizada(s)
ventajas: Adaptadas a tus necesidades y pueden ser indexadas para un mejor rendimiento.
desventajas: Más trabajo
También podría haber una solución alternativa utilizando una taxonomía personalizada, que podría ofrecer un mejor rendimiento en las consultas que las consultas de metadatos de entradas, debido a cómo están indexadas las tablas principales.
Estoy intentando enviar una notificación a todos los que han dado "me gusta" a una entrada cuando alguien más da "me gusta" a esa entrada... algo como: "¡Oye, a alguien más le gustó esa entrada que te gustó. Deberías ir a verla!" Pero necesito una manera de averiguar si alguien más ha dado "me gusta" a esa entrada y, de ser así, quiénes serían para poder notificarlos.
No estoy seguro de qué tipo de notificaciones te refieres aquí, pero esto puede volverse rápidamente engorroso.
Ejemplo: Un usuario que da "me gusta" a ~ 1000 entradas y cada entrada recibe ~ 1000 "me gusta", entonces hay 1M de notificaciones en proceso, ¡solo para ese usuario! Si estas son notificaciones por correo electrónico, es posible que el proveedor de hosting no esté contento y el usuario se volvería loco. Eso también podría ser costoso con un servicio de correo electrónico de terceros.

En realidad solo envío las notificaciones una vez por persona por publicación. Así que es menos de lo que parece, aunque sigue siendo mucho. La razón por la que estoy intentando usar tablas integradas es porque me gustaría poder usar la API REST estándar de WP en el futuro en una aplicación real con estos datos.

Según la documentación de WP_Meta_Query, puedes usar el argumento compare
dentro del argumento meta_query
de WP_Query. Sin embargo, solo puedes comparar con el value
y no con el key
, por lo que quizás quieras reconsiderar cómo estructuras esto.
Un argumento like
se vería así:
$arguments = array(
'meta_query' => array(
array(
'key' => 'foo',
'value' => 'ba',
'compare' => 'LIKE'
)
)
);
$query = new WP_Query($arguments);
Dado que no puedes hacer una búsqueda 'LIKE' en el key
, te sugiero que añadas los posts que gustan en el meta del usuario y hagas una búsqueda con WP_User_Query para encontrar usuarios que les haya gustado ese post:
$arguments = array(
'meta_query' => array(
array(
'key' => 'liked_post',
'value' => '<post_id>'
)
)
);
$users = new WP_User_Query($arguments);
