¿Cómo consulto publicaciones por metaclave parcial?

9

Tengo una función que almacena el estado "Me gusta" de una publicación como meta meta. Quiero asociar ese "me gusta" con el usuario que le gustó, así que configuré un campo personalizado llamado "like_status_ {user_id}" (donde {user_id} es la identificación del usuario actualmente conectado) que almaceno como 0 o 1. Entonces, para una publicación con varios "me gusta", habría varios meta valores en la base de datos configurados de esta manera:

'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í.

Hay potencialmente miles de Me gusta en una publicación específica. ¿Cómo ejecutaría una consulta que se muestra si a alguien más también le gustó esa publicación?

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 les ha gustado una publicación cuando a alguien más le gusta esa publicación ... algo así como: "Oye, a alguien más le gustó esa publicación que te gustó. ¡Deberías ir a verla!" Pero necesito una forma de averiguar si a alguien más le ha gustado esa publicación y, de ser así, quiénes serían para poder notificárselo.

Si no es posible, ¿podría sugerir una mejor manera de almacenar estos datos como post_meta mientras mantiene la eficiencia de actualizar rápidamente el estado de un solo usuario en una publicación?

codescribblr
fuente

Respuestas:

6

Desafortunadamente, no puede realizar un meta_queryuso LIKEcomparando el meta_keyvalor cuando lo usa WP_Query. He estado por este camino ...

En cambio, tiene un par de otras opciones si desea mantener relaciones de estado similares como meta meta y no meta usuario o meta en una tabla personalizada.

Opción 1

  • no requiere modificación de su meta esquema
  • usa la wpdbclase para realizar una consulta personalizada

Ejemplo:

//when a user likes a post...
$current_user_id = get_current_user_id();
add_post_meta($current_user_id, "like_status_{$current_user_id}", 1, false);

//later in the request...
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){

    //apply to all users except the user who just liked the post
    if ( $notify_user_id !== $current_user_id ) {
        //notify logic here...           
    }

});

Nota: la lógica podría simplificarse aún más si lo desea.

opcion 2

  • requiere que cambies tu meta esquema
  • requiere que almacene la identificación de usuario como el metavalor
  • le permite usar WP_Queryjunto conmeta_query

La opción 2 requiere que cambie su meta clave de like_status_{user_id}algo universal, como like_statuso liked_by_user_iddonde, a su vez, en lugar de almacenar el valor de 1contra la clave, en su lugar almacene la identificación del usuario como el valor.

//when a user likes a post...
$current_user_id = get_current_user_id();
add_post_meta($current_user_id, "liked_by_user_id", $current_user_id, false);

//later in the request
$args = array(
    'post_type'  => 'post', //or a post type of your choosing
    '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){

        //notify all users except the user who just like the post
        if ( $notify_user_id !== $current_user_id ) {

            //notify logic here...
            //get user e.g. $user = get_user_by('id', $notify_user_id);

        }

    });

});
Adán
fuente
1
Ahora es desde 5.1 eche un vistazo a mi respuesta a continuación
K. Tromp
@ K.Tromp Huzzah!
Adam
10

Es bastante difícil responder concretamente a su pregunta. Sin embargo, la primera parte es fácil. Hace poco hice algo similar en stackoverflow

Las teclas meta se comparan y coinciden exactamente. WP_Queryno tenemos medios para ajustar este comportamiento con un parámetro simple, pero siempre podemos presentar uno nosotros mismos y luego ajustar la posts_wherecláusula para hacer unLIKE comparación en las teclas meta.

EL FILTRO

Este es solo un filtro básico, ajústelo según sea necesario.

add_filter( 'posts_where', function ( $where, \WP_Query $q )
{ 
    // Check for our custom query var
    if ( true !== $q->get( 'wildcard_on_key' ) )
        return $where;

    // Lets filter the clause
    $where = str_replace( 'meta_key =', 'meta_key LIKE', $where );

    return $where;
}, 10, 2 );

Como puede ver, el filtro solo se activa cuando configuramos nuestro nuevo parámetro personalizado, wildcard_on_keya true. Cuando esto se verifica, simplemente cambiamos el= comparador al LIKEcomparador

Solo una nota sobre esto, LIKE comparaciones son inherentemente más caras de ejecutar que otras comparaciones

LA CONSULTA

Simplemente puede consultar sus 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, puede 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 afectar su rendimiento al obtener y almacenar en caché una cantidad tan grande de datos de campo personalizados. También puede obstruir su base de datos con una gran cantidad de datos de campo personalizados innecesarios, lo que hace que sea bastante difícil de mantener.

No soy un gran fanático del almacenamiento de datos serializados en campos personalizados, ya que uno no puede buscar u ordenar por datos serializados. Sin embargo, sugeriría almacenar todas las ID de usuario en una matriz en un campo personalizado. Simplemente puede actualizar la matriz con la ID de usuario cuando a un usuario le gusta una publicación. Obtener los datos de campo personalizados y recorrer la matriz de ID y hacer algo con los ID es fácil. Solo echa un vistazo aget_post_meta()

Actualizar un campo personalizado también es fácil. Para eso, tendrá que investigar update_post_meta(), no sé cómo crear sus campos personalizados, pero update_post_meta()definitivamente es algo que querría usar.

Si necesita enviar correos electrónicos o notificaciones push cuando se actualiza un campo personalizado, tiene los siguientes enlaces disponibles para trabajar. ( Ver update_metadata()para contexto )

CONCLUSIÓN

Justo antes de publicar esto, nuevamente, antes de ir a la ruta serializada, asegúrese de que no necesite ordenar por los datos ordenados o buscar datos particulares dentro de los datos serializados.

Pieter Goosen
fuente
1
¡Gracias por su explicación sobre el rendimiento post_meta! Súper útil
codescribblr
Esta debería ser la respuesta aceptada, siempre es mejor usar filtros en lugar de usar consultas personalizadas. Además, tenga en cuenta que si está usando get_posts en lugar de WP_Query, debe pasar por suppress_filters => false o no activará el filtro. Para realizar el LIKE en la meta clave, también debe colocar% delante y detrás de la clave en la matriz, según el tipo de búsqueda similar que desee hacer.
Earle Davies
¿Y cómo lo filtraría si desea consultar publicaciones pero EXCLUIR todas las publicaciones que tengan una metaclave de publicación por prefijo? (por ejemplo, excluir todas las publicaciones que tengan una meta meta de la publicación como 'my_prefix_'?
gordie
5

Desde wordpress 5.1 ahora es posible usar metaconsulta como: ingrese la descripción de la imagen aquí

K. Tromp
fuente
El escape de guiones bajos parece ser un problema con este método, pero por lo demás, se ve bastante bien. Gracias destacando.
Jake el
2

Si más adelante desea ampliar esto, con estadísticas más detalladas, características, etc., entonces otra alternativa podría ser: tablas personalizadas

  • Pros : adaptados a sus necesidades y pueden indexarse para un mejor rendimiento.

  • contras : más trabajo

También puede haber una solución alternativa utilizando una taxonomía personalizada, que podría proporcionar un mejor rendimiento de consulta que las meta meta consultas, debido a cómo se indexan las tablas principales.

Estoy tratando de enviar una notificación a todos los que les ha gustado una publicación cuando a alguien más le gusta esa publicación ... algo así como: "Oye, a alguien más le gustó esa publicación que te gustó. ¡Deberías ir a verla!" Pero necesito una forma de averiguar si a alguien más le ha gustado esa publicación y, de ser así, quiénes serían para poder notificárselo.

No estoy seguro de qué tipo de notificaciones quiere decir aquí, pero esto puede volverse voluminoso rápidamente.

Ejemplo : un usuario al que le gustan ~ 1000 publicaciones y cada publicación obtiene ~ 1000 Me gusta, entonces hay 1 millón de notificaciones en las canalizaciones, ¡solo para ese usuario! Si se trata de notificaciones por correo electrónico, el proveedor de host podría no estar contento y el usuario se volvería loco. Eso también podría ser costoso con un servicio de correo electrónico de terceros.

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

Según la documentación de WP_Meta_Query , puede usar el compareargumento en el meta_queryargumento de WP_Query. Sin embargo, solo puede comparar en valuey no el, keypor lo que es posible que desee volver a pensar cómo estructurar esto.

Un likeargumento se vería así:

$arguments = array(
    'meta_query' => array(
        array(
            'key' => 'foo',
            'value' => 'ba',
            'compare' => 'LIKE'
        )
    )
);

$query = new WP_Query($arguments);

Dado que no puede hacer una búsqueda 'ME GUSTA' en el key, le sugiero que agregue las publicaciones que le gustaron en el meta del usuario y realice una búsqueda WP_User_Query para los usuarios a quienes les haya gustado esa publicación:

$arguments = array(
    'meta_query' => array(
        array(
            'key' => 'liked_post',
            'value' => '<post_id>'
        )
    )
);

$users = new WP_User_Query($arguments);
LonnyLot
fuente