Comment rechercher des publications par méta-clé partielle?

9

J'ai une fonction qui stocke le statut "like" pour un post en tant que meta post. Je veux associer ce "j'aime" à l'utilisateur qui l'a aimé, j'ai donc configuré un champ personnalisé appelé "like_status_ {user_id}" (où {user_id} est l'ID de l'utilisateur actuellement connecté) que je stocke en tant que 0 ou 1. Donc, pour un article avec plusieurs "j'aime", il y aurait plusieurs méta-valeurs dans la base de données qui sont configurées comme ceci:

'meta_key' = 'like_status_0'
'meta_value' = 1
'meta_key' = 'like_status_2'
'meta_value' = 1
'meta_key' = 'like_status_34'
'meta_value' = 1

....etc.

Il y a potentiellement des milliers de likes sur un post spécifique. Comment pourrais-je exécuter une requête qui montre si quelqu'un d'autre a également aimé ce message?

Je pensais à quelque chose comme ça:

$query = new WP_Query(array(
    'meta_key' => 'like_status_{user_id}',
    'meta_value' => 1,
));

J'essaie de pousser une notification à tous ceux qui ont aimé un post quand quelqu'un d'autre aime ce post ... quelque chose comme, "Hé, quelqu'un d'autre a aimé ce post que vous avez aimé. Vous devriez aller le vérifier!" Mais j'ai besoin d'un moyen de savoir si quelqu'un d'autre a aimé ce message et si oui, qui il serait afin que je puisse le notifier.

Si ce n'est pas possible, pourriez-vous suggérer un meilleur moyen de stocker ces données en tant que post_meta tout en conservant l'efficacité de la mise à jour rapide du statut similaire d'un utilisateur unique sur un message?

codescribblr
la source

Réponses:

6

Malheureusement , vous ne pouvez pas effectuer une en meta_queryutilisant une LIKEcomparaison sur la meta_keyvaleur lors de l' utilisation WP_Query. Je suis allé sur cette route ...

Au lieu de cela, vous avez quelques autres options si vous souhaitez conserver des relations de statut similaires en tant que méta post et non méta utilisateur et ou méta dans un tableau personnalisé.

Option 1

  • ne nécessite aucune modification de votre méta-schéma
  • utilise la wpdbclasse pour effectuer une requête personnalisée

Exemple:

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

});

Remarque: la logique pourrait être simplifiée davantage si vous le souhaitez.

Option 2

  • vous oblige à changer votre méta-schéma
  • nécessite que vous stockiez l'ID utilisateur comme valeur méta
  • vous permet d'utiliser WP_Queryavecmeta_query

L'option 2 nécessite que vous changiez votre méta-clé de like_status_{user_id}quelque chose d'universel tel que like_statusou liked_by_user_idoù à son tour au lieu de stocker la valeur de 1contre la clé, vous stockez à la place l'ID de l'utilisateur comme valeur.

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

        }

    });

});
Adam
la source
1
C'est maintenant depuis 5.1 jetez un oeil à ma réponse ci
K. Tromp
@ K.Tromp Huzzah!
Adam
10

Il est assez difficile de répondre concrètement à votre question. La première partie est cependant facile. J'ai récemment fait quelque chose de similaire sur stackoverflow

Les méta-clés sont comparées et correspondent exactement. WP_Queryn'avons aucun moyen d'ajuster ce comportement avec un paramètre simple, mais nous pouvons toujours en introduire un nous-mêmes puis ajuster la posts_whereclause pour faire une LIKEcomparaison sur les méta-clés.

LE FILTRE

Ce n'est qu'un filtre de base, ajustez-le selon vos besoins.

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

Comme vous pouvez le voir, le filtre n'est déclenché que lorsque nous définissons notre nouveau paramètre personnalisé, wildcard_on_keysur true. Lorsque cela vérifie, nous changeons simplement le =comparateur en LIKEcomparateur

Juste une note à ce sujet, les LIKEcomparaisons sont intrinsèquement plus coûteuses à exécuter que les autres comparaisons

LA REQUÊTE

Vous pouvez simplement interroger vos messages comme suit pour obtenir tous les messages avec des méta-clés like_status_{user_id}

$args = [
    'wildcard_on_key' => true,
    'meta_query'      => [
        [
            'key'   => 'like_status_',
            'value' => 1,
        ]
    ]
];
$query = new WP_Query( $args );

AUTRE QUESTION

Les champs personnalisés n'ont pas d'impact sur les performances, vous pouvez lire mon article sur ce sujet ici . Je suis cependant troublé par le fait que vous dites que chaque message peut avoir des centaines ou des milliers de likes. Cela peut vous nuire à l'obtention et à la mise en cache de performances d'une telle quantité de données de champ personnalisé. Il peut également obstruer votre base de données avec une énorme quantité de données de champ personnalisées inutiles, ce qui le rend assez difficile à maintenir.

Je ne suis pas un grand fan du stockage de données sérialisées dans des champs personnalisés car on ne peut pas rechercher ou commander par des données sérialisées. Je suggérerais cependant de stocker tous les ID utilisateur dans un tableau sous un champ personnalisé. Vous pouvez simplement mettre à jour le tableau avec l'ID utilisateur lorsqu'un utilisateur aime un message. Obtenir les données de champ personnalisées et boucler sur le tableau des ID et faire quelque chose avec les ID est facile. Jetez un œil àget_post_meta()

La mise à jour d'un champ personnalisé est également facile. Pour cela, vous devrez vous pencher sur update_post_meta(), je ne sais pas comment vous créez vos champs personnalisés, mais update_post_meta()c'est certainement quelque chose que vous voudriez utiliser.

Si vous devez envoyer des e-mails ou des notifications push lorsqu'un champ personnalisé est mis à jour, vous disposez des crochets suivants pour travailler. ( Voir update_metadata()pour le contexte )

CONCLUSION

Juste avant de poster ceci, encore une fois, avant de suivre la route sérialisée, assurez-vous que vous n'auriez pas besoin de trier par les données triées ou de rechercher des données particulières à l'intérieur des données sérialisées.

Pieter Goosen
la source
1
Merci pour votre explication sur les performances post_meta! Super utile.
codescribblr
Cela devrait être la réponse acceptée, il est toujours préférable d'utiliser des filtres plutôt que d'utiliser des requêtes personnalisées. Notez également que si vous utilisez get_posts plutôt que WP_Query, vous devez passer par suppress_filters => false ou cela ne déclenchera pas le filtre. Pour effectuer le LIKE sur la méta-clé, vous devez également mettre% devant et derrière la clé dans le tableau en fonction du type de recherche similaire que vous souhaitez effectuer.
Earle Davies
Et comment le filtreriez-vous si vous souhaitez interroger des publications mais EXCLURE toutes les publications ayant une méta-clé de publication par préfixe? (par exemple, exclure tous les messages ayant une méta-message COMME 'my_prefix_'?
gordie
5

Depuis wordpress 5.1, il est maintenant possible d'utiliser une méta-requête comme: entrez la description de l'image ici

K. Tromp
la source
L'échappement des traits de soulignement semble être un problème avec cette méthode, mais sinon, cela semble assez bon. Merci de souligner.
Jake
2

Si plus tard vous souhaitez étendre cela, avec des statistiques plus détaillées, des fonctionnalités, etc., alors une autre alternative pourrait être: des tables personnalisées

  • Avantages : Adapté à vos besoins et indexable pour de meilleures performances.

  • inconvénients : Plus de travail

Il peut également y avoir une solution de contournement utilisant une taxonomie personnalisée, qui pourrait donner de meilleures performances de requête que post-méta-requêtes, en raison de la façon dont les tables principales sont indexées.

J'essaie de pousser une notification à tous ceux qui ont aimé un post quand quelqu'un d'autre aime ce post ... quelque chose comme, "Hé, quelqu'un d'autre a aimé ce post que vous avez aimé. Vous devriez aller le vérifier!" Mais j'ai besoin d'un moyen de savoir si quelqu'un d'autre a aimé ce message et si oui, qui il serait afin que je puisse le notifier.

Vous ne savez pas de quel type de notifications vous parlez ici, mais cela peut rapidement devenir volumineux.

Exemple : Un utilisateur qui aime ~ 1000 publications et chaque publication obtient ~ 1000 likes, alors il y a 1M de notifications dans les tuyaux, uniquement pour cet utilisateur! S'il s'agit de notifications par e-mail, le fournisseur d'hébergement pourrait ne pas être satisfait et l'utilisateur deviendrait fou. Cela peut également coûter cher avec un service de messagerie tiers.

Birgire
la source
En fait, je n'envoie les notifications qu'une seule fois par personne et par message. C'est donc moins qu'il n'y paraît - bien que toujours beaucoup. La raison pour laquelle j'essaie d'utiliser des tableaux intégrés est que j'aimerais pouvoir utiliser l'API WP REST standard plus tard dans une application réelle avec ces données.
codescribblr
-1

Selon la documentation WP_Meta_Query , vous pouvez utiliser l' compareargument dans l' meta_queryargument de WP_Query. Cependant, vous ne pouvez comparer que sur le valueet non sur le, keydonc vous voudrez peut-être repenser la façon dont vous structurez cela.

Un likeargument ressemblerait à ceci:

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

$query = new WP_Query($arguments);

Étant donné que vous ne pouvez pas faire de recherche "LIKE" sur le, keyje vous suggère d'ajouter les messages aimés dans la méta utilisateur et de faire une recherche WP_User_Query pour les utilisateurs qui ont aimé ce message:

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

$users = new WP_User_Query($arguments);
LonnyLot
la source