web-dev-qa-db-fra.com

Comment interroger les publications par clé méta partielle?

J'ai une fonction qui stocke le statut "J'aime" pour un post en tant que méta de post. Je veux associer ce "like" à l'utilisateur qui l'a aimé. J'ai donc configuré un champ personnalisé appelé "like_status_ {user_id}" (où {user_id} est l'identifiant de l'utilisateur actuellement connecté) que je stocke en tant que 0 ou 1. Ainsi, pour un article contenant plusieurs "j'aime", il y aurait plusieurs méta-valeurs dans la base de données 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 "j'aime" sur un poste spécifique Comment pourrais-je lancer une requête qui montrait si quelqu'un d'autre aimait aussi cette publication?

Je pensais à quelque chose comme ça:

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

J'essaie d'envoyer une notification à tous ceux qui ont aimé un message quand quelqu'un d'autre l'a aimé ... quelque chose du genre "Hé, quelqu'un d'autre a aimé ce message que tu as aimé. Tu devrais aller voir ça!" Mais il me faut un moyen de savoir si quelqu'un d'autre a aimé ce message et, dans l'affirmative, 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 maintenant l'efficacité de la mise à jour rapide du statut similaire d'un utilisateur unique sur une publication?

8
codescribblr

Malheureusement, vous ne pouvez pas effectuer un meta_query à l'aide d'une comparaison LIKE sur la valeur meta_key lorsque vous utilisez WP_Query. J'ai été sur cette route ...

Au lieu de cela, vous avez deux autres options si vous souhaitez conserver des relations de statut telles que les méta-publications et non les méta-utilisateurs et/ou les méta dans un tableau personnalisé.

Option 1

  • ne nécessite aucune modification de votre méta-schéma
  • utilise la classe wpdb 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 en tant que méta valeur
  • vous permet d'utiliser WP_Query avec meta_query

L'option 2 requiert que vous changiez votre clé méta de like_status_{user_id} en quelque chose d'universel tel que like_status ou liked_by_user_id où, au lieu de stocker la valeur de 1 contre la clé, vous stockez à la place l'id de l'utilisateur en tant que 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);

        }

    });

});
6
userabuser

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

Les méta-clés sont comparées et correspondent parfaitement. WP_Query n'a aucun moyen de régler ce comportement avec un paramètre simple, mais nous pouvons toujours en introduire un nous-mêmes, puis ajuster la clause posts_where pour effectuer une comparaison LIKE sur des clés méta.

LE FILTRE

Ceci est juste un filtre de base, ajustez-le si nécessaire.

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 constater, le filtre est activé uniquement lorsque nous définissons notre nouveau paramètre personnalisé, wildcard_on_key, à true. Lorsque ceci est vérifié, nous changeons simplement le comparateur = en le comparateur LIKE

Juste une note à ce sujet, les comparaisons LIKE sont par nature plus coûteuses à exécuter que les autres comparaisons

LA REQUÊTE

Vous pouvez simplement interroger vos publications comme suit pour obtenir toutes les publications 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 post à ce sujet ici . Je suis toutefois troublé par le fait que vous dites que chaque publication peut avoir des centaines, voire des milliers de "j'aime". Cela peut vous affecter les performances en obtenant et en mettant en cache une telle quantité de données de champ personnalisées. Cela peut également encombrer votre base de données avec une quantité énorme de données de champ personnalisées inutiles, ce qui rend la maintenance très difficile.

Je ne suis pas un grand amateur de stockage de données sérialisées dans des champs personnalisés, car il est impossible de rechercher ou de commander des données sérialisées. Je suggérerais cependant de stocker tous les identifiants d’utilisateur dans un tableau sous un seul 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 passer en boucle sur le tableau d'identifiants et effectuer quelque chose avec les identifiants sont faciles. Il suffit de jeter un oeil à get_post_meta()

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

Si vous devez envoyer des courriels ou des notifications Push lorsqu'un champ personnalisé est mis à jour, vous avez les points d'ancrage suivants à votre disposition. ( Voir update_metadata() pour le contexte )

CONCLUSION

Juste avant de poster ceci, encore une fois, avant de vous lancer dans la route sérialisée, assurez-vous que vous n'auriez pas besoin de trier les données triées ni de rechercher des données particulières dans les données sérialisées.

10
Pieter Goosen

Si, par la suite, vous souhaitez étendre cette fonctionnalité, avec des statistiques plus détaillées, des fonctionnalités, etc., une autre alternative pourrait être: table (s) personnalisée (s)

  • pros : Adapté à vos besoins et peut être indexé pour de meilleures performances.

  • cons : Plus de travail

Une solution de contournement utilisant une taxonomie personnalisée pourrait également permettre d'améliorer les performances des requêtes par rapport aux méta-requêtes, en raison de l'indexation des tables principales.

J'essaie d'envoyer une notification à tous ceux qui ont aimé un message quand quelqu'un d'autre l'a aimé ... quelque chose du genre "Hé, quelqu'un d'autre a aimé ce message que tu as aimé. Tu devrais aller voir ça!" Mais il me faut un moyen de savoir si quelqu'un d'autre a aimé ce message et, dans l'affirmative, qui il serait afin que je puisse le notifier.

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

Exemple : Un utilisateur qui aime ~ 1 000 messages et chaque message obtient environ 1 000 "j'aime", puis il y a 1 million de notifications dans les canaux, uniquement pour cet utilisateur! S'il s'agit de notifications par courrier électronique, le fournisseur de l'hôte risque de ne pas être heureux et l'utilisateur deviendrait fou. Cela pourrait aussi être coûteux avec un service de messagerie tiers.

2
birgire

Depuis wordpress 5.1, il est maintenant possible d’utiliser une méta-requête comme: enter image description here

1
K. Tromp

Selon la documentation WP_Meta_Query , vous pouvez utiliser l’argument compare dans l’argument meta_query de WP_Query. Cependant, vous ne pouvez comparer que sur la variable value et non pas sur la variable key. Vous voudrez peut-être repenser votre structure.

Un argument like ressemblerait à ceci:

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

$query = new WP_Query($arguments);

Etant donné que vous ne pouvez pas faire de recherche 'LIKE' sur la key, je vous suggère d’ajouter les messages que vous aimez dans la méta de l’utilisateur et de faire un WP_User_Query rechercher 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);
0
LonnyLot