Cela fait maintenant des jours que je me penche sur cette question. Au départ, c'était comment stocker les données des suiveurs d'un utilisateur dans la base de données, pour laquelle j'ai reçu quelques bonnes recommandations ici sur WordPress Answers. Après, en suivant les recommandations, j'ai ajouté un nouveau tableau comme celui-ci:
id leader_id follower_id
1 2 4
2 3 10
3 2 10
Dans le tableau ci-dessus, la première ligne a un utilisateur avec un ID de 2 qui est suivi par un utilisateur avec un ID de 4. Dans la deuxième ligne, un utilisateur avec un ID de 3 est suivi par un utilisateur avec un ID de 10. La même logique s'applique pour la troisième ligne.
Maintenant, je veux essentiellement étendre WP_Query afin de pouvoir limiter les messages récupérés à celui de, uniquement par le (s) leader (s) d'un utilisateur. Donc, en tenant compte du tableau ci-dessus, si je passais l'ID utilisateur 10 à WP_Query, les résultats ne devraient contenir que des publications par ID utilisateur 2 et ID utilisateur 3.
J'ai beaucoup cherché en essayant de trouver une réponse. De plus, je n'ai vu aucun tutoriel pour m'aider à comprendre comment étendre la classe WP_Query. J'ai vu les réponses de Mike Schinkel (étendant WP_Query) à des questions similaires, mais je n'ai vraiment pas compris comment l'appliquer à mes besoins. Ce serait formidable si quelqu'un pouvait m'aider avec ça.
Liens vers les réponses de Mike comme demandé: Lien 1 , Lien 2
WP_Query
est pour obtenir des messages, et je n'arrive pas à comprendre comment cela se lie aux messages.Réponses:
Si vous effectuez des jointures complexes, vous ne pouvez pas simplement utiliser le filtre posts_where, car vous devrez également modifier les sections de la jointure, de la sélection et éventuellement du groupe par ou de l'ordre de la requête.
Le mieux est d'utiliser le filtre 'posts_clauses'. Il s'agit d'un filtre très utile (à ne pas abuser!) Qui vous permet d'ajouter / modifier les différentes parties du SQL généré automatiquement par les nombreuses lignes de code dans le noyau WordPress. La signature de rappel du filtre est:
function posts_clauses_filter_cb( $clauses, $query_object ){ }
et il attend que vous reveniez$clauses
.Les clauses
$clauses
est un tableau qui contient les clés suivantes; chaque clé est une chaîne SQL qui sera directement utilisée dans la dernière instruction SQL envoyée à la base de données:Si vous ajoutez une table à la base de données (ne faites cela que si vous ne pouvez absolument pas tirer parti de post_meta, user_meta ou taxonomies), vous devrez probablement toucher plusieurs de ces clauses, par exemple, le
fields
(le "SELECT" partie de l'instruction SQL), lajoin
(toutes vos tables, à l'exception de celle de votre clause "FROM"), et peut-être laorderby
.Modification des clauses
La meilleure façon de le faire est de sous-référencer la clé appropriée du
$clauses
tableau que vous avez obtenue du filtre:Maintenant, si vous modifiez
$join
, vous serez en fait en train de modifier directement$clauses['join']
afin que les modifications soient apportées$clauses
lorsque vous le retournerez.Préserver les clauses originales
Il y a de fortes chances (non, sérieusement, écoutez) que vous souhaitiez conserver le SQL existant que WordPress a généré pour vous. Sinon, vous devriez probablement regarder le
posts_request
filtre à la place - c'est la requête complète mySQL juste avant qu'elle ne soit envoyée à la base de données, afin que vous puissiez la remplir complètement avec la vôtre. Pourquoi voudriez-vous faire ça? Vous ne le faites probablement pas.Donc, afin de préserver le SQL existant dans les clauses, n'oubliez pas d'ajouter aux clauses, pas de les affecter (c'est-à-dire:
$join .= ' {NEW SQL STUFF}';
ne pas utiliser$join = '{CLOBBER SQL STUFF}';
. Notez que parce que chaque élément du$clauses
tableau est une chaîne, si vous souhaitez y ajouter, vous voudrez probablement insérer un espace avant tout autre jeton de caractère, sinon vous créerez probablement une erreur de syntaxe SQL.Vous pouvez simplement supposer qu'il y aura toujours quelque chose dans chacune des clauses, et n'oubliez donc pas de commencer chaque nouvelle chaîne avec un espace, comme dans:,
$join .= ' my_table
ou, vous pouvez toujours ajouter une petite ligne qui n'ajoute un espace que si vous devez:C'est une chose stylistique plus que toute autre chose. Le point important à retenir est: toujours laisser un espace AVANT votre chaîne si vous ajoutez à une clause qui contient déjà du SQL!
Mettre ensemble
La première règle de développement de WordPress est d' essayer d'utiliser autant de fonctionnalités de base que possible. C'est le meilleur moyen de pérenniser votre travail. Supposons que l'équipe principale décide que WordPress utilisera désormais SQLite ou Oracle ou un autre langage de base de données. Tout mySQL manuscrit peut devenir invalide et casser votre plugin ou votre thème! Mieux vaut laisser WP générer autant de SQL que possible, et ajouter simplement les bits dont vous avez besoin.
Donc, le premier ordre du jour consiste à tirer parti
WP_Query
de générer autant de votre requête de base que possible. La méthode exacte que nous utilisons pour ce faire dépend en grande partie de l' endroit où cette liste de messages est censée apparaître. Si c'est une sous-section de la page (pas votre requête principale) que vous utiliseriezget_posts()
; si c'est la requête principale, je suppose que vous pouvez l'utiliserquery_posts()
et en finir, mais la bonne façon de le faire est d'intercepter la requête principale avant qu'elle ne frappe la base de données (et consomme des cycles de serveur), utilisez donc lerequest
filtre.D'accord, vous avez donc généré votre requête et le SQL est sur le point d'être créé. Eh bien, en fait, il a été créé, mais pas envoyé à la base de données. En utilisant le
posts_clauses
filtre, vous allez ajouter votre table de relations avec les employés dans le mix. Appelons cette table {$ wpdb-> prefix}. 'user_relationship', et c'est une table d'intersection. (Soit dit en passant, je vous recommande de généraliser cette structure de table et de la transformer en une table d'intersection appropriée avec les champs suivants: 'relation_id', 'user_id', 'related_user_id', 'relation_type'; c'est beaucoup plus flexible et puissant. .. mais je m'égare).Si je comprends ce que vous voulez faire, vous voulez transmettre un ID de leader et ne voir que les publications de ses suiveurs. J'espère avoir bien compris. Si ce n'est pas bien, vous devrez prendre ce que je dis et l'adapter à vos besoins. Je m'en tiendrai à la structure de votre table: nous avons un
leader_id
et unfollower_id
. Ainsi, le JOIN sera{$wpdb->posts}.post_author
activé en tant que clé étrangère du 'follower_id' sur votre table 'user_relationship'.la source
Je réponds à cette question extrêmement tard et je m'en excuse. J'avais été bien trop occupé par les délais pour m'occuper de cela.
Un grand merci à @ m0r7if3r et @kaiser pour avoir fourni les solutions de base que j'ai pu étendre et implémenter dans mon application. Cette réponse détaille mon adaptation des solutions proposées par @ m0r7if3r et @kaiser.
Tout d'abord, permettez-moi d'expliquer pourquoi cette question a été posée en premier lieu. D'après la question et les commentaires de celle-ci, on pourrait comprendre que j'essaie d'obtenir WP_Query pour extraire les messages de tous les utilisateurs (leaders) qu'un utilisateur donné (suiveur) suit. La relation entre le suiveur et le leader est stockée dans une table personnalisée
follow
. La solution la plus courante à ce problème consiste à extraire les ID utilisateur de tous les leaders d'un suiveur du tableau suivant et à les placer dans un tableau. Voir ci-dessous:Une fois que vous avez le tableau des leaders, vous pouvez le passer comme argument à WP_Query. Voir ci-dessous:
La solution ci-dessus est le moyen le plus simple d'obtenir les résultats souhaités. Cependant, il n'est pas évolutif. Au moment où un suiveur suit des dizaines et des milliers de leaders, le tableau d'ID de leader résultant deviendrait extrêmement volumineux et forcerait votre site WordPress à utiliser 100 Mo à 250 Mo de mémoire à chaque chargement de page et finirait par planter le site. La solution au problème consiste à exécuter une requête SQL directement sur la base de données et à récupérer les publications pertinentes. C'est à ce moment que la solution de @ m0r7if3r est venue à la rescousse. Suite à la recommandation de @ kaiser, j'ai décidé de tester les deux implémentations. J'ai importé environ 47K utilisateurs à partir d'un fichier CSV pour les enregistrer sur une nouvelle installation de test de WordPress. L'installation exécutait le thème Twenty Eleven. Après cela, j'ai exécuté une boucle for pour faire environ 50 utilisateurs suivre tous les autres utilisateurs. La différence de temps de requête pour la solution @kaiser et @ m0r7if3r était stupéfiante. La solution de @ kaiser prenait normalement environ 2 à 5 secondes pour chaque requête. La variation que je suppose se produit lorsque WordPress met en cache les requêtes pour une utilisation ultérieure. D'autre part, la solution de @ m0r7if3r a démontré un temps de requête de 0,02 ms en moyenne. Pour tester les deux solutions, j'avais l'indexation ON pour la colonne leader_id. Sans indexation, le temps de requête a considérablement augmenté.
L'utilisation de la mémoire lors de l'utilisation d'une solution basée sur une baie se situait autour de 100-150 Mo et est tombée à 20 Mo lors de l'exécution d'un SQL direct.
J'ai heurté une bosse avec la solution de @ m0r7if3r lorsque j'ai eu besoin de passer l'ID de suiveur à la fonction de filtre posts_where. Au moins, à ma connaissance, WordPress ne permet aucun moyen de transmettre une variable aux fonctions de filer. Vous pouvez cependant utiliser des variables globales, mais je voulais éviter les globales. J'ai fini par étendre WP_Query pour enfin résoudre le problème. Voici donc la solution finale que j'ai implémentée (basée sur la solution de @ m0r7if3r).
Remarque: j'ai finalement essayé la solution ci-dessus avec 1,2 million d'entrées dans le tableau suivant. Le temps de requête moyen était d'environ 0,060 ms.
la source
Vous pouvez le faire avec une solution entièrement SQL à l'aide du
posts_where
filtre. Voici un exemple de cela:Je pense qu'il peut y avoir un moyen de le faire
JOIN
aussi, mais je ne peux pas le trouver. Je continuerai à jouer avec et à mettre à jour la réponse si je l'obtiens.Alternativement, comme l' a suggéré @kaiser , vous pouvez le diviser en deux parties: obtenir les leaders et faire la requête. J'ai le sentiment que cela pourrait être moins efficace, mais c'est certainement la voie la plus compréhensible. Vous devrez tester l'efficacité par vous-même pour déterminer la meilleure méthode, car les requêtes SQL imbriquées peuvent devenir assez lentes.
DES COMMENTAIRES:
Vous devez mettre la fonction dans votre
functions.php
et faire leadd_filter()
bon avantquery()
d'WP_Query
appeler la méthode de . Immédiatement après cela, vous devezremove_filter()
pour que cela n'affecte pas les autres requêtes.la source
prepare()
. J'espère que cela ne vous dérange pas la modification. Et oui: la performance doit être mesurée par OP. Quoi qu'il en soit: je pense toujours que cela devrait être simplement usermeta et rien d'autre.functions.php
et faire leadd_filter()
bon avantquery()
d'WP_Query
appeler la méthode de . Immédiatement après cela, vous devezremove_filter()
pour que cela n'affecte pas les autres requêtes. Je ne sais pas quel serait le problème avec la réécriture d'URL, je l'ai utiliséposts_where
à plusieurs reprises et je n'ai jamais vu cela ...Balise de modèle
Placez simplement les deux fonctions dans votre
functions.php
fichier. Ajustez ensuite la 1ère fonction et ajoutez votre nom de table personnalisé. Ensuite, vous avez besoin d'un essai / erreur pour vous débarrasser de l'ID utilisateur actuel dans le tableau résultant (voir le commentaire).À l'intérieur du modèle
Ici, vous pouvez faire ce que vous voulez avec vos résultats.
la source
JOIN
est beaucoup plus cher. Plus: Comme je l'ai mentionné, nous n'avons pas de données de test, veuillez donc tester les deux réponses et nous éclairer avec vos résultats.Voici le code OPs des commentaires, pour ajouter le premier ensemble d'utilisateurs de test. Je dois être modifié pour un exemple du monde réel.
Ma réponse à ce ↑ test:
Je dois également déclarer que le ↑ suivi du temps ci-dessus ne peut pas être vraiment mesuré, car il faudrait également du temps pour calculer la boucle ensemble. Il serait préférable de parcourir l'ensemble d'ID résultant dans une deuxième boucle.
processus supplémentaire ici
la source