Ich habe Tage über dieses Problem jetzt gewesen. Anfänglich ging es darum, wie die Follower-Daten eines Benutzers in einer Datenbank gespeichert werden, für die ich hier bei WordPress Answers einige nette Empfehlungen erhalten habe. Nach den Empfehlungen habe ich eine neue Tabelle wie diese hinzugefügt:
id leader_id follower_id
1 2 4
2 3 10
3 2 10
In der obigen Tabelle hat die erste Zeile einen Benutzer mit einer ID von 2, auf den ein Benutzer mit einer ID von 4 folgt. In der zweiten Zeile folgt einem Benutzer mit einer ID von 3 ein Benutzer mit einer ID Dieselbe Logik gilt für die dritte Reihe.
Jetzt möchte ich im Wesentlichen WP_Query erweitern, sodass ich nur die von den Vorgesetzten eines Benutzers abgerufenen Posts auf die von beschränken kann. Wenn ich also unter Berücksichtigung der obigen Tabelle die Benutzer-ID 10 an WP_Query übergebe, sollten die Ergebnisse nur Posts nach Benutzer-ID 2 und Benutzer-ID 3 enthalten.
Ich habe viel gesucht, um eine Antwort zu finden. Ich habe auch kein Tutorial gesehen, das mir helfen soll, die WP_Query-Klasse zu erweitern. Ich habe Mike Schinkels Antworten (Erweiterung von WP_Query) auf ähnliche Fragen gesehen, aber ich habe wirklich nicht verstanden, wie ich sie auf meine Bedürfnisse anwenden kann. Es wäre toll, wenn mir jemand dabei helfen könnte.
WP_Query
dient dazu, Beiträge zu erhalten, und ich verstehe nicht, wie dies mit Beiträgen zusammenhängt.Antworten:
Wenn Sie komplexe Verknüpfungen ausführen, können Sie nicht einfach den Filter posts_where verwenden, da Sie die Verknüpfung, die Auswahl und möglicherweise auch die Gruppierung nach oder die Reihenfolge nach Abschnitten der Abfrage ändern müssen.
Verwenden Sie am besten den Filter "posts_clauses". Dies ist ein äußerst nützlicher Filter (der nicht missbraucht werden sollte!), Mit dem Sie die verschiedenen Teile der SQL-Anweisung anhängen / ändern können, die von den vielen Codezeilen in WordPress Core automatisch generiert werden. Die Filterrückrufsignatur lautet:
function posts_clauses_filter_cb( $clauses, $query_object ){ }
und erwartet, dass Sie zurückkehren$clauses
.Die Klauseln
$clauses
ist ein Array, das die folgenden Schlüssel enthält; Jeder Schlüssel ist eine SQL-Zeichenfolge, die direkt in der endgültigen SQL-Anweisung verwendet wird, die an die Datenbank gesendet wird:Wenn Sie eine Tabelle in der Datenbank sind hinzugefügt (dies nur tun , wenn Sie absolut nicht Hebel post_meta, user_meta oder Taxonomien) Sie wahrscheinlich mehr als eine dieser Klauseln zum Beispiel die brauchen, zu berühren
fields
(die „SELECT“ Teil der SQL - Anweisung), diejoin
(alle Ihre Tabellen, außer der in Ihrer "FROM" - Klausel) und möglicherweise dieorderby
.Änderung der Klauseln
Am besten referenzieren Sie dazu den relevanten Schlüssel aus dem
$clauses
Array, das Sie vom Filter erhalten haben:Wenn Sie jetzt
$join
Änderungen$clauses['join']
vornehmen , werden Sie diese direkt ändern , sodass die Änderungen$clauses
bei der Rückgabe übernommen werden.Erhalt der ursprünglichen Klauseln
Wahrscheinlich möchten Sie (im Ernst, hören Sie zu) das vorhandene SQL, das WordPress für Sie generiert hat, beibehalten. Wenn nicht, sollten Sie sich
posts_request
stattdessen wahrscheinlich den Filter ansehen - das ist die vollständige mySQL-Abfrage, kurz bevor sie an die Datenbank gesendet wird. Warum willst du das tun? Sie wahrscheinlich nicht.Um die vorhandene SQL in den Klauseln beizubehalten, müssen Sie daran denken, an die Klauseln anzuhängen und sie nicht zuzuweisen (dh: Verwenden Sie
$join .= ' {NEW SQL STUFF}';
nicht$join = '{CLOBBER SQL STUFF}';
. Beachten Sie, dass jedes Element des$clauses
Arrays eine Zeichenfolge ist, wenn Sie daran anhängen möchten. Sie werden wahrscheinlich ein Leerzeichen vor anderen Zeichen-Token einfügen wollen, andernfalls werden Sie wahrscheinlich einen SQL-Syntaxfehler erzeugen.Sie können einfach davon ausgehen, dass in jeder Klausel immer etwas enthalten ist, und denken Sie daher daran, jede neue Zeichenfolge mit einem Leerzeichen wie in:
$join .= ' my_table
zu beginnen.Das ist mehr als alles andere eine stilistische Sache. Das Wichtigste, an das Sie sich erinnern sollten, ist: Lassen Sie immer ein Leerzeichen VOR Ihrer Zeichenfolge, wenn Sie an eine Klausel anhängen, in der bereits SQL enthalten ist!
Etwas zusammensetzen
Die erste Regel bei der Entwicklung von WordPress ist, so viele Kernfunktionen wie möglich zu verwenden. Dies ist der beste Weg, um Ihre Arbeit zukunftssicher zu machen. Angenommen, das Kernteam entscheidet, dass WordPress jetzt SQLite oder Oracle oder eine andere Datenbanksprache verwendet. Jedes handgeschriebene mySQL kann ungültig werden und Ihr Plugin oder Theme beschädigen! Es ist besser, WP so viel SQL wie möglich selbst generieren zu lassen und nur die benötigten Bits hinzuzufügen.
Die erste Geschäftsaufgabe besteht also
WP_Query
darin, so viel wie möglich von Ihrer Basisabfrage zu generieren. Die genaue Methode, mit der wir dies tun, hängt weitgehend davon ab, wo diese Liste der Beiträge erscheinen soll. Wenn es sich um einen Unterabschnitt der Seite handelt (nicht um Ihre Hauptabfrage), würden Sie verwendenget_posts()
. Wenn es sich um die Hauptabfrage handelt, können Sie sie vermutlich verwendenquery_posts()
und damit fertig werden. Die richtige Methode besteht jedoch darin, die Hauptabfrage abzufangen, bevor sie die Datenbank erreicht (und Serverzyklen beansprucht). Verwenden Sie daher denrequest
Filter.Okay, Sie haben Ihre Abfrage generiert und die SQL wird erstellt. Tatsächlich wurde es erstellt, aber nicht an die Datenbank gesendet. Mit dem
posts_clauses
Filter fügen Sie Ihre Mitarbeiterbeziehungstabelle in den Mix ein. Nennen wir diese Tabelle {$ wpdb-> Präfix}. 'user_relationship' und es ist eine Kreuzungstabelle. (Übrigens empfehle ich, diese Tabellenstruktur zu generieren und in eine richtige Schnittstellentabelle mit den folgenden Feldern umzuwandeln: 'relationship_id', 'user_id', 'related_user_id', 'relationship_type'; dies ist viel flexibler und leistungsfähiger. .. Aber ich schweife ab).Wenn ich verstehe, was Sie tun möchten, möchten Sie die ID eines Anführers übergeben und dann nur die Beiträge der Anhänger dieses Anführers anzeigen. Ich hoffe, ich habe das richtig verstanden. Wenn es nicht stimmt, müssen Sie das, was ich sage, nehmen und an Ihre Bedürfnisse anpassen. Ich bleibe bei deiner Tischstruktur: Wir haben ein
leader_id
und einfollower_id
. Daher ist JOIN{$wpdb->posts}.post_author
als Fremdschlüssel für die 'follower_id' in Ihrer 'user_relationship'-Tabelle aktiviert.quelle
Ich beantworte diese Frage sehr spät und entschuldige mich dafür. Ich war viel zu sehr mit Fristen beschäftigt, um mich darum zu kümmern.
Ein großes Dankeschön an @ m0r7if3r und @kaiser für die Bereitstellung der Basislösungen, die ich erweitern und in meine Anwendung implementieren konnte. Diese Antwort enthält Details zu meiner Anpassung der von @ m0r7if3r und @kaiser angebotenen Lösungen.
Lassen Sie mich zunächst erklären, warum diese Frage überhaupt gestellt wurde. Aus der Frage und den Kommentaren könnte man ersehen, dass ich versuche, WP_Query dazu zu bringen, Beiträge aller Benutzer (Leiter) abzurufen, denen ein bestimmter Benutzer (Anhänger) folgt. Die Beziehung zwischen dem Follower und dem Leader wird in einer benutzerdefinierten Tabelle gespeichert
follow
. Die häufigste Lösung für dieses Problem besteht darin, die Benutzer-IDs aller Leiter eines Followers aus der Folgetabelle zu ziehen und in einem Array abzulegen. Siehe unten:Sobald Sie das Array von Führungskräften haben, können Sie es als Argument an WP_Query übergeben. Siehe unten:
Die obige Lösung ist der einfachste Weg, um die gewünschten Ergebnisse zu erzielen. Es ist jedoch nicht skalierbar. In dem Moment, in dem Sie einen Follower haben, der Zehntausenden von Führern folgt, wird das resultierende Array von Führer-IDs extrem groß und zwingt Ihre WordPress-Site, 100 MB - 250 MB Speicher bei jedem Laden der Seite zu belegen und die Site schließlich zum Absturz zu bringen. Die Lösung des Problems besteht darin, eine SQL-Abfrage direkt in der Datenbank auszuführen und relevante Posts abzurufen. Zu diesem Zeitpunkt kam die Lösung von @ m0r7if3r zur Rettung. Auf Empfehlung von @ kaiser habe ich mich vorgenommen, beide Implementierungen zu testen. Ich habe ungefähr 47.000 Benutzer aus einer CSV-Datei importiert, um sie für eine neue Testinstallation von WordPress zu registrieren. Die Installation lief unter dem Thema Twenty Eleven. Anschließend habe ich eine for-Schleife ausgeführt, damit etwa 50 Benutzer jedem anderen Benutzer folgen. Der Unterschied in der Abfragezeit für die Lösung von @kaiser und @ m0r7if3r war atemberaubend. Die Lösung von @ kaiser benötigte normalerweise ca. 2 bis 5 Sekunden für jede Abfrage. Die von mir angenommene Variation tritt auf, wenn WordPress Abfragen für die spätere Verwendung zwischenspeichert. Andererseits zeigte die Lösung von @ m0r7if3r eine durchschnittliche Abfragezeit von 0,02 ms. Zum Testen beider Lösungen hatte ich die Indizierung für die Spalte leader_id auf ON gesetzt. Ohne Indexierung stieg die Abfragezeit drastisch an.
Die Speichernutzung bei Verwendung einer Array-basierten Lösung lag zwischen 100 und 150 MB und ging bei Ausführung von Direct SQL auf 20 MB zurück.
Ich habe mit der Lösung von @ m0r7if3r einen Fehler gemacht, als ich die Follower-ID an die Filterfunktion posts_where übergeben musste. Zumindest erlaubt WordPress meines Wissens keine Möglichkeit, eine Variable an Filer-Funktionen zu übergeben. Sie können zwar globale Variablen verwenden, aber ich wollte globale Variablen vermeiden. Am Ende habe ich WP_Query erweitert, um das Problem endlich zu beheben. Hier ist die endgültige Lösung, die ich implementiert habe (basierend auf der Lösung von @ m0r7if3r).
Hinweis: Ich habe die obige Lösung schließlich mit 1,2 Millionen Einträgen in der folgenden Tabelle ausprobiert. Die durchschnittliche Abfragezeit lag bei 0,060 ms.
quelle
Sie können dies mit einer vollständigen SQL-Lösung unter Verwendung des
posts_where
Filters tun . Hier ist ein Beispiel dafür:Ich denke, dass es einen Weg gibt, dies auch zu tun
JOIN
, aber ich kann nicht darauf kommen. Ich werde weiter damit spielen und die Antwort aktualisieren, wenn ich sie bekomme.Alternativ können Sie es, wie von @kaiser vorgeschlagen, in zwei Teile aufteilen: Abrufen der Leiter und Ausführen der Abfrage. Ich habe das Gefühl, dass dies weniger effizient ist, aber es ist sicherlich der verständlichere Weg. Sie müssten die Effizienz selbst testen, um festzustellen, welche Methode besser ist, da verschachtelte SQL-Abfragen sehr langsam werden können.
AUS DEN KOMMENTAREN:
Sie sollten die Funktion in Ihre einfügen
functions.php
und dasadd_filter()
Richtige tun, bevor diequery()
Methode vonWP_Query
aufgerufen wird. Im Anschluss daran sollten Sie sicherstellenremove_filter()
, dass die anderen Abfragen davon nicht betroffen sind.quelle
prepare()
. Hoffe du hast nichts gegen die Bearbeitung. Und ja: Leistung muss am OP gemessen werden. Sowieso: Ich denke immer noch, das sollte einfach usermeta sein und sonst nichts.functions.php
und dasadd_filter()
Richtige tun, bevor diequery()
Methode vonWP_Query
aufgerufen wird. Im Anschluss daran sollten Sie sicherstellenremove_filter()
, dass die anderen Abfragen davon nicht betroffen sind. Ich bin mir nicht sicher, wie das Problem mit dem Umschreiben vonposts_where
Vorlagen-Tag
Platzieren Sie einfach beide Funktionen in Ihrer
functions.php
Datei. Passen Sie dann die 1. Funktion an und fügen Sie Ihren benutzerdefinierten Tabellennamen hinzu. Dann benötigen Sie einen Versuch / Fehler, um die aktuelle Benutzer-ID innerhalb des resultierenden Arrays zu entfernen (siehe Kommentar).Innerhalb der Vorlage
Hier können Sie mit Ihren Ergebnissen machen, was Sie wollen.
quelle
JOIN
ist viel teurer. Plus: Wie bereits erwähnt, haben wir keine Testdaten. Bitte testen Sie beide Antworten und klären Sie uns mit Ihren Ergebnissen auf.Hier ist der OPs-Code aus den Kommentaren, um die erste Gruppe von Testbenutzern hinzuzufügen. Ich muss zu einem realen Beispiel modifiziert werden.
Meine Antwort auf diesen ↑ Test:
Ich muss auch feststellen, dass die ↑ obige Zeiterfassung nicht wirklich gemessen werden kann, da es auch Zeit kosten würde, die Schleife zusammen zu berechnen. Besser wäre es, den resultierenden Satz von IDs in einer zweiten Schleife zu durchlaufen.
hier weiter verarbeiten
quelle