Miałem już kilka dni nad tym problemem. Początkowo było to, jak przechowywać dane obserwujących użytkownika w bazie danych, dla których dostałem kilka fajnych rekomendacji tutaj w WordPress Answers. Następnie, zgodnie z zaleceniami, dodałem nową tabelę:
id leader_id follower_id
1 2 4
2 3 10
3 2 10
W powyższej tabeli pierwszy wiersz ma użytkownika o identyfikatorze 2, po którym następuje użytkownik o identyfikatorze 4. W drugim wierszu za użytkownikiem o identyfikatorze 3 znajduje się użytkownik o identyfikatorze z 10. Ta sama logika dotyczy trzeciego rzędu.
Teraz zasadniczo chcę rozszerzyć WP_Query, aby móc ograniczać posty pobierane do tego tylko przez lidera (liderów) użytkownika. Tak więc, biorąc pod uwagę powyższą tabelę, gdybym przekazał identyfikator użytkownika 10 do WP_Query, wyniki powinny zawierać tylko posty według identyfikatora użytkownika 2 i identyfikatora użytkownika 3.
Dużo szukałem, próbując znaleźć odpowiedź. Nie widziałem też żadnego samouczka, który pomógłby mi zrozumieć, jak rozszerzyć klasę WP_Query. Widziałem odpowiedzi Mike'a Schinkela (rozszerzenie WP_Query) na podobne pytania, ale tak naprawdę nie rozumiem, jak zastosować je do moich potrzeb. Byłoby wspaniale, gdyby ktoś mógł mi w tym pomóc.
Linki do odpowiedzi Mike'a zgodnie z prośbą: Link 1 , Link 2
WP_Query
służy do otrzymywania postów i nie rozumiem, w jaki sposób wiąże się to z postami.Odpowiedzi:
Jeśli wykonujesz złożone sprzężenia, nie możesz po prostu użyć filtra posts_where, ponieważ musisz zmodyfikować sprzężenie, zaznaczenie i ewentualnie grupę według lub uporządkować według sekcji zapytania.
Najlepiej jest użyć filtra „posts_clauses”. Jest to bardzo przydatny filtr (który nie powinien być nadużywany!), Który pozwala dodawać / modyfikować różne części SQL generowane automatycznie przez wiele wierszy kodu w rdzeniu WordPress. Sygnatura oddzwaniania filtra to:
function posts_clauses_filter_cb( $clauses, $query_object ){ }
i oczekuje na powrót$clauses
.Klauzule
$clauses
jest tablicą zawierającą następujące klucze; każdy klucz jest ciągiem SQL, który zostanie bezpośrednio użyty w końcowej instrukcji SQL wysłanej do bazy danych:Jeśli dodajesz tabelę do bazy danych (rób to tylko wtedy, gdy absolutnie nie możesz wykorzystać post_meta, user_meta lub taksonomii) prawdopodobnie będziesz musiał dotknąć więcej niż jednej z tych klauzul, na przykład
fields
(„WYBIERZ” część instrukcji SQL),join
(wszystkie tabele, inne niż w klauzuli „FROM”) i być możeorderby
.Modyfikowanie klauzul
Najlepszym sposobem na to jest odjęcie odpowiedniego klucza z
$clauses
tablicy uzyskanej z filtra:Teraz, jeśli zmodyfikujesz
$join
, będziesz modyfikować bezpośrednio,$clauses['join']
więc zmiany zostaną wprowadzone$clauses
po jego zwróceniu.Zachowanie oryginalnych klauzul
Możliwe, że (nie, poważnie, słuchaj) będziesz chciał zachować istniejący SQL wygenerowany dla Ciebie przez WordPress. Jeśli nie, prawdopodobnie powinieneś
posts_request
zamiast tego spojrzeć na filtr - jest to kompletne zapytanie mySQL tuż przed wysłaniem go do bazy danych, abyś mógł całkowicie zablokować go własnym. Dlaczego chcesz to zrobić? Prawdopodobnie nie.Aby zachować istniejący kod SQL w klauzulach, pamiętaj o dołączeniu do klauzul, a nie przypisaniu do nich (tj.:
$join .= ' {NEW SQL STUFF}';
Nie używaj$join = '{CLOBBER SQL STUFF}';
. Zauważ, że ponieważ każdy element$clauses
tablicy jest łańcuchem, jeśli chcesz do niego dołączyć, prawdopodobnie będziesz chciał wstawić spację przed innymi tokenami znaków, w przeciwnym razie prawdopodobnie utworzysz jakiś błąd składni SQL.Możesz po prostu założyć, że zawsze będzie coś w każdej z klauzul, więc pamiętaj, aby rozpocząć każdy nowy ciąg spacją, jak w:,
$join .= ' my_table
lub zawsze możesz dodać małą linię, która dodaje spację tylko wtedy, gdy potrzebujesz:To stylistyczna rzecz bardziej niż cokolwiek innego. Ważną rzeczą do zapamiętania jest: zawsze zostawiaj spację PRZED łańcuchem, jeśli dołączasz do klauzuli, która zawiera już trochę SQL!
Składając to razem
Pierwszą zasadą rozwoju WordPressa jest próba użycia jak największej liczby podstawowych funkcji. To najlepszy sposób, aby w przyszłości sprawdzić swoją pracę. Załóżmy, że główny zespół zdecyduje, że WordPress będzie teraz używać SQLite, Oracle lub innego języka baz danych. Każdy ręcznie napisany mySQL może stać się nieważny i uszkodzić wtyczkę lub motyw! Lepiej pozwolić WP generować tak dużo SQL, jak to możliwe, i po prostu dodać potrzebne bity.
Tak więc pierwsze zamówienie firmy wykorzystuje
WP_Query
do wygenerowania jak największej liczby zapytań podstawowych. Dokładna metoda, której używamy, zależy w dużej mierze od tego, gdzie ta lista postów ma się pojawić. Jeśli jest to podsekcja strony (nie twoje główne zapytanie), skorzystaszget_posts()
; jeśli jest to główne zapytanie, myślę, że można go użyćquery_posts()
i gotowe, ale właściwym sposobem na to jest przechwycenie głównego zapytania, zanim trafi ono do bazy danych (i zużyje cykle serwera), więc użyjrequest
filtru.OK, więc wygenerowałeś zapytanie i SQL zostanie wkrótce stworzony. Cóż, w rzeczywistości został stworzony, po prostu nie wysłany do bazy danych. Korzystając z
posts_clauses
filtra, dodasz tabelę relacji pracowniczych do miksu. Nazwijmy tę tabelę {$ wpdb-> prefix}. „user_relationship” i jest to tabela skrzyżowań. (Nawiasem mówiąc, zalecam uogólnienie tej struktury tabeli i przekształcenie jej w odpowiednią tabelę przecięcia z następującymi polami: „id_użytkownika”, „id_użytkownika”, „id_użytkownika_użytkownika”, „typ_użytkownika”; jest to o wiele bardziej elastyczne i wydajne. .. ale dygresję).Jeśli rozumiem, co chcesz zrobić, chcesz przekazać identyfikator lidera, a następnie zobaczyć tylko posty obserwujących tego lidera. Mam nadzieję, że dobrze to zrozumiałem. Jeśli to nie w porządku, musisz wziąć to, co mówię i dostosować to do swoich potrzeb. Pozostanę przy twojej strukturze stołu: mamy a
leader_id
i afollower_id
. Tak więc JOIN będzie włączony{$wpdb->posts}.post_author
jako klucz obcy do „follower_id” w tabeli „user_relationship”.źródło
Odpowiadam na to pytanie bardzo późno i przepraszam za to samo. Byłem zbyt zajęty terminami, aby dotrzymać tego terminu.
Ogromne podziękowania dla @ m0r7if3r i @kaiser w zapewnieniu podstawowych rozwiązań, które mogłem rozszerzyć i wdrożyć w mojej aplikacji. Ta odpowiedź zawiera szczegółowe informacje na temat mojej adaptacji rozwiązań oferowanych przez @ m0r7if3r i @kaiser.
Najpierw wyjaśnię, dlaczego pytanie to zostało zadane w pierwszej kolejności. Z pytania i jego komentarzy można wywnioskować, że staram się, aby WP_Query ściągał posty wszystkich użytkowników (liderów), za którymi podąża dany użytkownik (obserwujący). Relacje między obserwującym a liderem są przechowywane w niestandardowej tabeli
follow
. Najczęstszym rozwiązaniem tego problemu jest pobranie identyfikatorów użytkowników wszystkich liderów obserwujących z tabeli śledzenia i umieszczenie ich w tablicy. Patrz poniżej:Gdy masz już tablicę liderów, możesz przekazać ją jako argument do WP_Query. Patrz poniżej:
Powyższe rozwiązanie jest najprostszym sposobem na osiągnięcie moich pożądanych rezultatów. Jest jednak nieskalowalny. W momencie, gdy obserwujesz obserwujących dziesiątki i tysiące liderów, wynikowa tablica identyfikatorów liderów byłaby bardzo duża i zmusiłaby twoją witrynę WordPress do użycia 100 MB - 250 MB pamięci przy każdym ładowaniu strony i ostatecznie zawiesiłaby stronę. Rozwiązaniem problemu jest uruchomienie zapytania SQL bezpośrednio w bazie danych i pobranie odpowiednich postów. Właśnie wtedy rozwiązanie @ m0r7if3r przyszło na ratunek. Zgodnie z zaleceniem @ kaiser postanowiłem przetestować obie implementacje. Zaimportowałem około 47 000 użytkowników z pliku CSV, aby zarejestrować ich podczas nowej instalacji testowej WordPress. W instalacji działał motyw Twenty Eleven. Następnie uruchomiłem pętlę for, aby około 50 użytkowników śledziło każdego innego użytkownika. Różnica w czasie zapytania dla rozwiązania @kaiser i @ m0r7if3r była oszałamiająca. Rozwiązanie @ kaiser zwykle zajęło około 2 do 5 sekund dla każdego zapytania. Odmiana, którą zakładam, dzieje się, gdy WordPress buforuje zapytania do późniejszego wykorzystania. Z drugiej strony rozwiązanie @ m0r7if3r wykazało czas zapytania średnio 0,02 ms. Do testowania obu rozwiązań miałem indeksowanie WŁĄCZONE w kolumnie lider_id. Bez indeksowania nastąpił gwałtowny wzrost czasu zapytania.
Zużycie pamięci podczas korzystania z rozwiązania opartego na macierzy wynosiło około 100-150 MB i spadło do 20 MB podczas uruchamiania bezpośredniego SQL.
Wystąpił problem z rozwiązaniem @ m0r7if3r, gdy potrzebowałem przekazać identyfikator obserwującego do funkcji filtrowania posts_where. Co najmniej, zgodnie z moją wiedzą, WordPress nie zezwala na przekazywanie zmiennych do funkcji filtrowania. Możesz jednak użyć zmiennych globalnych, ale chciałem uniknąć globalnych. Ostatecznie rozszerzyłem WP_Query, aby w końcu rozwiązać ten problem. Oto ostatnie rozwiązanie, które wdrożyłem (oparte na rozwiązaniu @ m0r7if3r).
Uwaga: ostatecznie wypróbowałem powyższe rozwiązanie z 1,2 milionem wpisów w poniższej tabeli. Średni czas zapytania wynosił około 0,060 ms.
źródło
Możesz to zrobić za pomocą rozwiązania całkowicie SQL przy użyciu
posts_where
filtra. Oto przykład:Myślę, że może to być również sposób
JOIN
, ale nie mogę tego wymyślić. Będę się z nią bawił i zaktualizuję odpowiedź, jeśli ją otrzymam.Alternatywnie, jak sugerował @kaiser , możesz podzielić go na dwie części: uzyskanie liderów i wykonanie zapytania. Mam wrażenie, że może to być mniej wydajne, ale z pewnością jest to bardziej zrozumiała droga. Będziesz musiał sam przetestować wydajność, aby określić, która metoda jest lepsza, ponieważ zagnieżdżone zapytania SQL mogą działać dość wolno.
KOMENTARZE:
Powinieneś umieścić tę funkcję w swoim
functions.php
i zrobić toadd_filter()
dobrze przed wywołaniemquery()
metodyWP_Query
Natychmiast po tym powinieneś,remove_filter()
aby nie wpłynęło to na inne zapytania.źródło
prepare()
. Mam nadzieję, że nie przeszkadza ci edycja. I tak: wydajność musi być mierzona przez OP. W każdym razie: nadal uważam, że powinna to być po prostu usermeta i nic więcej.functions.php
i zrobić toadd_filter()
dobrze przed wywołaniemquery()
metodyWP_Query
Natychmiast po tym powinieneś,remove_filter()
aby nie wpłynęło to na inne zapytania. Nie jestem pewien, jaki byłby problem z przepisywaniem adresów URL, wielokrotnie korzystałemposts_where
i nigdy tego nie widziałem ...Tag szablonu
Po prostu umieść obie funkcje w swoim
functions.php
pliku. Następnie dostosuj pierwszą funkcję i dodaj niestandardową nazwę tabeli. Następnie potrzebujesz metody try / error, aby pozbyć się bieżącego ID użytkownika w wynikowej tablicy (patrz komentarz).Wewnątrz szablonu
Tutaj możesz robić, co chcesz z wynikami.
źródło
JOIN
jest znacznie droższy. Plus: jak wspomniałem, nie mamy danych testowych, więc proszę przetestuj obie odpowiedzi i oświeć nas swoimi wynikami.Oto kod OP z komentarzy, aby dodać pierwszy zestaw użytkowników testowych. Muszę zostać zmodyfikowany na przykład z prawdziwego świata.
Moja odpowiedź na ten test ↑:
Muszę też stwierdzić, że śledzenia nad czasem ↑ nie da się tak naprawdę zmierzyć, ponieważ zajęłoby to również czas na obliczenie pętli razem. Lepiej byłoby zapętlić wynikowy zestaw identyfikatorów w drugiej pętli.
dalszy proces tutaj
źródło