Filtry WordPress
Filtry WordPress – ale o co chodzi? Kiedy nie wiadomo o co chodzi… To się to wyjaśnia. WordPress posługuje się dużą ilością treści. Również przesyła sobie wiele danych. Czasami chcielibyśmy mieć na te dane wpływ. Jeżeli szablon lub wtyczka są dobrze napisane, to pozwalają nam na to, aby w newralgicznych miejscach coś sobie pozmieniać. Na przykład jakaś wtyczka pobiera listę postów z danej kategorii. A my byśmy bardzo chcieli, aby pobierała z innej kategorii, poza tym – ma działać bez zmian. Co robimy? Nic prostszego! Bierzemy się za kod wtyczki i podmieniamy odpowiednią wartość… NIE. Tak się nie robi. Jest to stanowczo odradzane i wytykane palcami, bo wiadomo, zabronić się nie da.
Ale właściwie dlaczego nie ingerować w kod jakiejś wtyczki czy szablonu? Autorzy często poprawiają swoje dzieła, czasami dodają jakieś funkcje, czasami usuwają luki bezpieczeństwa (co przecież ważniejsze). Gdy coś takiego nastąpi, nasz WordPress (lub my, ręcznie) aktualizuje wtyczkę, szablon czy też siebie. Co się wówczas dzieje? Tracimy wszystko to, co napisaliśmy. Ot tak, po prostu. Bez pytania kogokolwiek o zdanie.
Jak tego uniknąć? Otóż, jeżeli jest to coś, co twórca wtyczki przewidział, zazwyczaj pozwoli nam na podmianę kategorii. Czasami pozwoli na to w menu, dodając wyświetlanie odpowiednich opcji a czasami – poprzez filtry.
Filtr – krótko i na temat
Wyobraź sobie, że filtr WordPress to taka czarna skrzynka, która dostaje wartość, może nią manipulować (choć wcale nie musi!) a następnie ją zwraca. Powtórzę się, bo pisałem o tym przy pierwszym szablonie wtyczek – tylko tyle i aż tyle.
Dostępne funkcje
WordPress oczywiście daje nam zbiór funkcji, które pozwalają na manipulowanie filtrami. Są to add_filter, apply_filters, has_filter, current_filter, remove_filter i remove_all_filters. Kiedyś istniała jeszcze funkcja merge_filters, ale została usunięta, więc nie będziemy się nią zajmować. Tak naprawdę tych funkcji jest odrobinę więcej, ale nie mają oczywistych zastosowań z naszego punktu widzenia. Są za to stosowane przez kod WordPress.
add_filter
Tej funkcji używamy, gdy chcemy zmodyfikować sobie jakąś wartość. Oczywiście musimy wcześniej znać nazwę takiego filtra. Użycie jest niezwykle proste.
Na początek, definiujemy nazwę filtra, który będziemy wykorzystywać. Potem dajemy nazwę funkcji (lub tablicę klasa, metoda – sposoby dodawania haków WordPress), która będzie modyfikowała wartość. Następnie – priorytet filtra. Domyślnie wartość równa dziesięć. Im wyższa liczba, tym mniejszy priorytet. Można to sobie wyobrazić, jako miejsce w kolejce. Ci z pierwszego miejsca będą obsłużeni pierwsi, ci z tysięcznego… wiadomo. Jeżeli dwa (lub więcej) wywołań będą miały taki sam priorytet, zostaną wywołane w kolejności dodawania się do kolejki wywołań (co z kolei zależy od tego, gdzie my sobie taką funkcję wywołamy). Ostatni parametr to ilość argumentów. Domyślnie jest jeden, czyli wartość, którą będziemy modyfikowali. Czasami bywa, że przekazywane jest więcej parametrów, np. identyfikator (numer ID) postu, którego tyczy filtrowanie i tym podobne.
Rozważmy sobie przykład (wynik w obrazku, który już zapewne obejrzałeś). Spróbujmy tak zmodyfikować wyświetlany tytuł wpisu, aby – gdy wpis nie został przypisany żadnej kategorii – było to widoczne w tytule. W tym celu, musimy dodać filtr o nazwie „the_title”. Skąd to wiemy? Akurat to dosyć powszechna informacja (wśród programistów WordPress!). Dość dużą listę dostępnych filtrów możemy znaleźć na odpowiednich stronach WordPress. Nie jest to lista pełna, ale dość duża. Za priorytet ustawimy sobie sto, bo nigdzie nam się z tą modyfikacją nie spieszy. Listę argumentów ustawiamy na dwa, ponieważ ten filtr używa samej treści tytułu, jak i ID wpisu, którego ten tytuł dotyczy.
Kod wygląda tak:
1 2 3 4 5 6 7 8 |
function add_uncategorized_to_title( $title, $post_id ) { if ( in_category('uncategorized', $post_id ) ) { $title.= ' [Bez kategorii]'; } return $title; } add_filter( 'the_title', 'add_uncategorized_to_title', 100, 2 ); |
Co stanie się w następstwie działania tego kodu w WordPress? Ano, każdy post, który jest przypisany do kategorii „Uncategorized” (czyli do żadnej) będzie miał dodane ” [Bez kategorii]” w tytule. Jak we wcześniejszym obrazku.
Uwaga: warto to zapamiętać, nasza funkcja może zmodyfikować tylko pierwszy parametr – w powyższym wypdaku będzie to $title
. Modyfikujemy go nie poprzez referencję a poprzez zwracanie, dlatego każda funkcja modyfikująca filtr, musi zwrócić jakąś, najlepiej sensowną, wartość. Nie ma możliwości (w każdym razie – wprost) modyfikacji innych parametrów.
apply_filters
Ta funkcja służy, tak jakby, jako druga strona monety pod tytułem add_filter. To właśnie w ten sposób „wydajemy na żer” nasze dane innym filtrom. Czasami naszym. Najważniejsze są dwa pierwsze parametry. Nazwa filtra oraz dane, które będą modyfikowane. Możemy dodać więcej parametrów (na przykład ID aktualnego postu), ale nie jest to obowiązkowe. W gestii osoby wykorzystującej filtr leży wiedza na temat tego, co przekazujemy. Oczywiście winniśmy to odpowiednio zmodyfikować. Weźmy sobie taki przykład:
1 2 3 4 5 6 |
function download_data() { $url = 'https://jakies-dane.pl/rest/results.php'; $data = file_get_contents( $url ); return json_decode( $data, TRUE ); } |
Jest to funkcja więcej niż naiwna, ale gdyby serwer obsługiwał wywołania HTTP poprzez file_get_contents
a pod adresem https://jakies-dane.pl/rest/results.php
kryłyby się jakieś dane, to nawet by to zadziałało.
Wszystko będzie działało do momentu, kiedy nagle zmieni się adres serwera na https://nowy-super-serwer/get.php
a programista wtyczki właśnie wybrał się na Madagaskar fotografować straszliwe Fossy. Należałoby ingerować w jego kod a przecież Fossy mogłyby go nie zjeść, wróciłby, zrobił aktualizację (ale inną, a co tam!) i nasz kod, niestety, nie ostałby się. A gdyby taki programista użył apply_filters… O tak:
1 2 3 4 5 6 |
function download_data() { $url = apply_filters('nasz_plugin-url_do_danych', 'https://jakies-dane.pl/rest/results.php'); ; $data = file_get_contents( $url ); return json_decode( $data, TRUE ); } |
…to co musielibyśmy zrobić? Ależ oczywiście:
1 2 3 4 5 |
function nasz_plugin_zmiana_url( $url ) { return 'https://nowy-super-serwer/get.php'; } add_filter( 'nasz_plugin-url_do_danych', 'nasz_plugin_zmiana_url' ); |
Zwróćcie proszę uwagę na to, że nawet nie musimy przetwarzać zmiennej $url
, po prostu odsyłamy nową, poprawną wartość. I to całkowicie wystarczy, oczywiście pod warunkiem, że zarejestrujemy swój filtr zanim zostanie wywołany.
has_filter
Ta funkcja sprawdza, czy do danego filtra jest przypisana jakaś, lub konkretna, funkcja. Może przyjąć jeden parametr lub dwa. Pierwszy, obowiązkowy, to nazwa filtra. Drugi, opcjonalny, to nazwa funkcji, którą chcemy sprawdzić. Zobaczmy, jak możemy tę funkcję wywołać:
1 2 3 4 5 6 7 8 9 |
add_filter( 'the_title', 'nasz_plugin_zmiana_tytulu', 100, 2 ); function nasz_plugin_zmiana_tytulu( $title, $post_id ) { return $title; } $filtr_1 = has_filter( 'the_title' ); $filtr_2 = has_filter( 'the_title', 'nasz_plugin_zmiana_tytulu' ); $filtr_3 = has_filter( 'the_title', 'funkcja_ktorej_nie_ma' ); |
Co otrzymamy? Każde wywołanie dotyczy filtra the_title
, jak widać. Pierwsze wywołanie sprawdza, czy w ogóle jakaś funkcja została pod ten filtr podpięta. Drugie wywołanie sprawdza, czy została podpięta funkcja nasz_plugin_zmiana_tytulu
a trzecie wywołanie, czy została podpięta funkcja funkcja_ktorej_nie_ma
. W odpowiedzi otrzymamy:
– jeżeli nie wskazaliśmy funkcji, dostaniemy wartość logiczną true, jeżeli cokolwiek zostało podpięte lub false, jeżeli nic,
– jeżeli wskazaliśmy funkcję, dostaniemy wartość logiczną false, jeżeli taka funkcja nie została podpięta, lub wartość liczbową (priorytet) wskazanej funkcji.
W powyższym przykładzie otrzymalibyśmy: true, 100, false.
current_filter
Jedna z mniej przydatnych funkcji, choć są przypadki, gdy się przydaje. Funkcja po prostu zwraca nazwę filtra, który wywołał daną funkcję. Mogłoby się to wydawać nawet komiczne:
1 2 3 4 5 6 |
add_filter( 'the_title', 'nasz_plugin_zmiana_tytulu', 100, 2 ); function nasz_plugin_zmiana_tytulu( $title, $post_id ) { echo 'Current filter: ' . current_filter(); return $title; } |
Jasnym jest, że funkcja wyświetli „Current filter: the_title”. Ale… jeżeli przypiszemy jednej funkcji dwa filtry? Na przykład:
1 2 3 4 5 6 7 |
add_filter( 'the_title', 'nasz_plugin_zmiana' ); add_filter( 'the_content', 'nasz_plugin_zmiana' ); function nasz_plugin_zmiana( $string ) { echo 'Current filter: ' . current_filter(); return $string; } |
I teraz, dzięki current_filter
wiemy, który filtr wywołał naszą funkcję. Oczywiście w tym wypadku nie ma to znaczenia, ale gdybyśmy musieli wykonać wiele operacji na tekście z jakąś jedną drobną zmianą w zależności od filtra – to mamy, jak znalazł.
remove_filter
Ta funkcja służy do usuwania funkcji przypisanych do filtra, jak sama nazwa wskazuje. Nie jest jednak tak oczywista, jak się wydaje, za sprawą drugiego i trzeciego parametru.
Pierwszy parametr to nazwa filtra, tutaj nie ma niespodzianek.
Drugi parametr to nazwa funkcji, przypisanej do filtra.
Trzeci parametr to priorytet (nie jest to parametr obowiązkowy, w razie braku, przyjmuje domyślną wartość – dziesięć).
I co tu nie jest takie oczywiste?
Otóż kiedy usuwamy filtr, musi zgadzać się wszystko. Nazwa, nazwa funkcji i priorytet.
Weźmy nasz przykład:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
add_filter( 'the_title', 'nasz_plugin_zmiana_tytulu', 100, 2 ); function nasz_plugin_zmiana_tytulu( $title, $post_id ) { return $title; } remove_filter( 'the_title', 'nasz_plugin_zmiana_tytulu' ); $filtr_1 = has_filter( 'the_title', 'nasz_plugin_zmiana_tytulu' ); remove_filter( 'the_title', 'nasz_plugin_zmiana_tytulu', 100 ); $filtr_2 = has_filter( 'the_title', 'funkcja_ktorej_nie_ma' ); |
Pierwsze wywołanie remove_filter
nie usunie naszego filtra, gdyż zmieniliśmy domyślny parametr i teraz jest równy sto. W związku z czym, $filtr_1
przyjmie właśnie wartość sto.
Dopiero drugie wywołanie, ponieważ zgadza się priorytet, odniesie skutek – i otrzymamy false
w $filtr_2
.
Właśnie z powodu tej dokładności, nie da się za pomocą remove_filter
usunąć filtra używającego funkcji anonimowej. Po prostu – nie mamy jej nazwy. Warto o tym pamiętać i od używania funkcji anonimowych, w przypadku filtrów (i akcji!) się powstrzymać.
remove_all_filters
Wreszcie jakaś trywialna funkcja! Może przyjmować dwa parametry – nazwa filtra i ewentualny priorytet. Jeżeli dodamy priorytet, to zostaną usunięte wszystkie przypisania o określonym priorytecie. Jeżeli pominiemy priorytet lub podamy wartość domyślną (false), wówczas zostaną usunięte wszystkie przypisania filtrów.