WordPress - motywy, wtyczki, informacje, programowanie

Pat i Mat

20 największych błędów programistów używających WordPressa, część 1/2

WordPress jest napisany bardzo pragmatycznie i ścieżka uczenia się go nie jest stroma. Dlatego dla wielu osób stanowi początek drogi do programowania. Taka, niezbyt systematyczna nauka, metodą prób i błędów, ma swój urok, ale powoduje, że serwisy wordpressowe tworzą często programiści, którzy nie mieli skąd nabyć dobrych nawyków. Nie znają programistycznych „zasad BHP” – bo co prawda programista nie musi chodzić w kasku, ale przez swoją niefrasobliwość, może narazić siebie i innych na poważne kłopoty.

Niektóre błędy powodują dziury w bezpieczeństwie. Inne są niedojrzałym hakowaniem, w złym znaczeniu tego słowa. Może się ono sprawdzać na małą skalę w peryferyjnych, mało istotnych zadaniach, ale wyklucza efektywną pracę przy większym projekcie, czy pracę w zespole.

Co gorsze, w ten sposób budujemy złe nawyki, stajemy się programistami podobnymi do fachowców z programu „Usterka”, albo do bohaterów słynnego czeskiego filmu „Sąsiedzi”. Nie, nie uważam, że jest to film tylko dla dzieci. Zawsze uważałem, że powinien być używany jako materiał poglądowy do nauki dobrego programowania :-). W każdym odcinku Pat i Mat stosują dziesiątki naprawdę fantastycznych haków, ale zawsze mają problem z efektem końcowym.

Zebrałem w sumie 20 takich typowych błędów. Niektóre dotyczą tylko WordPressa, inne programowania w ogóle. Poukładałem je niekoniecznie w kolejności ważności, raczej tak, żeby nie było monotonnie. Ponieważ zrobił się z tego spory tekst, podzieliłem na dwie części. Staram się nie tylko wytykać złe praktyki, ale też tłumaczyć dlaczego są złe, podsuwać dobre rozwiązania i trochę przydatnych linków. Część poniższych punktów (od 6 do 10) zasługuje na osobne poradniki, które może kiedyś powstaną.

Myślę, że nawet dla bardziej doświadczonych programistów takie podsumowanie może być ciekawym rachunkiem sumienia.

1. Modyfikowanie kodu WordPressa

Ręczne dłubanie w kodzie WordPressa to największa zbrodnia wordpressowego programisty. Są dwa bardzo ważne powody, żeby tego nie robić.

Po pierwsze tracisz w ten sposób możliwość szybkiej aktualizacji kiedy wyjdzie nowa wersja, czy to ze względu na nowe funkcjonalności, czy ze względu na dziury w bezpieczeństwie. Próba połączenia Twoich zmian i nowej wersji zawsze będzie pracochłonna i ryzykowna. Nowe wersje WordPressa testują tysiące ludzi i wyłapują wszelkie możliwe niekompatybilności w tył – Twoich poprawek nie testowali.

Po drugie jeśli Ci się wydaje, że musisz zmieniać kod WordPressa, niemal na pewno robisz coś źle, wykraczasz poza logikę systemu i spowoduje to prędzej czy później jakieś problemy. WordPress jest naprawdę bardzo elastyczny i napisany pragmatycznie. Umiejętnie stosując haki (akcje, filtry), przysłanianie funkcji (Pluggable Functions) oraz wordpressowe wrzutki (WordPress Dropins) możesz zmienić co tylko dusza zapragnie. Jeśli to niemożliwe, to widocznie tak ma być.

NIGDY nie modyfikuj kodu WordPressa. Nigdy. Koniec, kropka.

Jeśli znalazłeś błąd w kodzie WordPressa, zgłoś go do Traca, najlepiej od razu proponując rozwiązanie lub dołączając łatkę.

2. Bezpośrednia modyfikacja kodu motywów

WordPress posiada bardzo przyzwoitą logikę tworzenia motywów potomnych. Jeśli kupiłaś lub ściągnęłaś skądś  gotowy motyw i chcesz w nim coś zmienić, powinnaś z tego mechanizmu skorzystać. Dłubanie w oryginalnym motywie pozbawia Cię możliwości aktualizacji, a w tym wypadku dość często są to aktualizacje związane z bezpieczeństwem.

Tutaj sprawa nie jest jednak tak jednoznaczna.  Jeśli zmiany, które chcesz nanieść nie są małe, nie są tylko tuningiem, ale de facto robisz własny, nowy motyw, startując z jakiegoś istniejącego, to zanika sens korzystania z mechanizmu motywów potomnych. I tak w końcu skopiujesz i zmienisz większość plików PHP.

Wtedy jednak powinnaś najpierw skopiować cały motyw i zmienić mu nazwę, w przeciwnym wypadku możesz kiedyś niechcący zaktualizować motyw startowy, tracąc wszystkie dokonane zmiany.

Z mojego doświadczenia wynika jednak, że ta druga sytuacja jest bardzo rzadka – najczęściej lepiej jest zrobić motyw potomny albo zacząć zupełnie od zera lub od jakiegoś startera, czyli jednego z motywów specjalnie zbudowanych jako punkt wyjścia do nowych motywów. Najbardziej znane to: Underscores, Roots i Reverie.

Zamiast modyfikować kod motywu, skorzystaj z mechanizmu motywów potomnych

3. Budowanie zamkniętych wtyczek

Napisaliśmy, że nie wolno modyfikować kodu WordPressa i motywów dlatego, że w obydwu przypadkach mamy bardzo dobre rozwiązania pozwalające tego uniknąć. WordPress i jego system motywów są otwarte. Niestety często nie można tego powiedzieć o wtyczkach. Bywa, że nie korzystają one z akcji i filtrów w takim zakresie jak mogłyby korzystać, przez co czasem nie pozostaje nam inne wyjście tylko dobranie się do ich kodu.

Przykładami wtyczek, które dobrze wykorzystują akcje i filtry są opisane przeze mnie jakiś czas temu Advanced Custom Fields i WordPress SEO by Yoast, fantastycznie jest to zrobione we wtyczce WooCommerce. Za to wtyczką, która ostatnio zaskoczyła mnie negatywnie pod tym względem jest Wisjia Newsletter. (pod każdym innym względem jest znakomita – łatwa w obsłudze nawet dla nietechnicznych redaktorów bloga, solidna, nie sprawiająca problemów).

Niestety próba zmodyfikowania tego co jest przez tę wtyczkę wysyłane (abstrahując od możliwości ręcznej edycji) nastręcza problemy. Dzieje się tak właśnie dlatego, że wtyczka nie wykorzystuje filtrów. Pobiera wskazane wpisy z bazy i umieszcza w newsletterze, a przecież mogłaby przepuścić każde z pól przez jakiś filtr, aby świadomy programista mógł coś dodać lub zmienić.

Cóż, niestety musiałem „dłubnąć” w jej kodzie i teraz mam dodatkową pracę przy każdej aktualizacji, na szczęście jest to bardzo niewielka zmiana – właśnie dodanie wywołanie filtra.

Właściwym podejściem w takiej sytuacji jest też przygotowanie kawałka kodu (patcha, albo po prostu ręcznie zrobionego wycinka) i wysłanie do autorów wtyczki z propozycją aby dodali nowa funkcjonalność do jednej z kolejnych wersji. Dzięki temu być może inni też będą mogli czerpać korzyści z naszych poprawek – dlatego tak właśnie zamierzam zrobić.

Tworząc własne wtyczki lub motywy, zwłaszcza takie, które mogą znaleźć wielu użytkowników, buduj rozwiązania otwarte, wykorzystując mechanizm filtrów i akcji.

4. Nieprawidłowe korzystanie z akcji i filtrów

Fakt, że mamy do dyspozycji rozwiązania otwarte nie oznacza, że możemy robić bałagan. Znakomity mechanizm akcji i filtrów w WordPressie powinniśmy także wykorzystywać właściwie.

Naczelną zasadą jest to, że kategorycznie nie wolno wykorzystywać filtrów do niczego innego poza modyfikacją danych, które zostały do nich podane. Filtr nie może modyfikować bazy, wypisywać niczego na wyjście (!), zmieniać opcji, itd. Krótko mówiąc, nie może robić nic „na boku” oprócz, albo zamiast tego do czego został stworzony. Jego wywołanie nie może mieć efektów ubocznych.

Do tych wszystkich rzeczy służą akcje.  Filtry służą do przekształcania danych. Taka była intencja twórców , tak to ma działać, takiego działania się spodziewają inni, którzy będą wykorzystywać dany filtr. Jeśli na przykład usunę filtry dla haka wp_title spodziewam się, że po prostu dostanę wyjściowy, nie przekształcony przez nic tytuł wpisu, a nie że przestanie mi działać coś w serwise, albo jakieś zapytania zaczną zwracać dziwne wyniki.

Nie wykorzystuj filtrów do modyfikacji bazy, pisania na wyjście lub modyfikowania stanów skryptu. Filtry zostały stworzone do modyfikowania tylko tych danych, które są do nich przekazywane.

5. Nie korzystanie z WP_DEBUG

Dość żenujące jest kiedy jakaś dość szeroko używana wtyczka po zainstalowaniu zaczyna sypać ostrzeżeniami o tym, że nie zostały zainicjowane jakieś zmienne, albo używana jest funkcja oznaczona jako deprecated. Tego typu ostrzeżenia nie muszą, ale mogą oznaczać coś złego –  na pewno oznaczają to, że autor wtyczki nie przyłożył się do pracy i na pewno nie kupuje w ten sposób mojego zaufania.

Zawsze sprawdzam jaki jest powód tych ostrzeżeń, zwłaszcza jeśli działanie wtyczki jest kluczowe dla funkcjonowania serwisu i zdarzało mi się znajdować całkiem poważne błędy. Mógł je zauważyć autor wtyczki, gdyby pracował z włączonym trybem diagnostycznym – ze stałą WP_DEBUG ustawiona na true.

Z drugiej strony mało profesjonalne jest kiedy działający serwis, napotkany w Internecie „wyświetla błędy, ostrzeżenia i informacje diagnostyczne użytkownikom – poza wszystkim, w ten sposób odsłania przed potencjalnymi włamywaczami swoje „miękkie podbrzusze”.

Zawsze pracuj z włączonym WP_DEBUG i dbaj o to, żeby nie pozostał włączony w wersji serwisu, którą widzą użytkownicy.

6. Modyfikacja tabel bazy WordPressa

Jeśli potrzebujesz coś zapisać w WordPressie, jakieś swoje, niestandardowe dane, masz do dyspozycji całą gamę możliwości (o różnej przydatności, w zależności od tego, co tak naprawdę potrzebujesz zapisać).

  • Możesz zapisać coś do tabeli opcji (funkcje add_option(), get_option(), update_option()). Niektóre wtyczki przechowują w niej spore bloki danych.
  • Możesz zapisać coś jako metadane do wpisu, lub użytkownika (post meta, user meta).
  • Możesz utworzyć specjalny prywatny typ wpisów (custom post type) niewidoczny w adminie i korzystać z niego.
  • Możesz utworzyć własne tabele bazodanowe w bazie WordPressa – dostajemy do tego wygodne narzędzia (klasę wpdb), nie musimy nic hakować.

Tak naprawdę jedyną rzeczą, której nie wolno robić, jest modyfikowanie tabel bazodanowych WordPressa, dodawanie do nich kolumn i przyjmowanie jakichś zależności między nimi.

To jest prawdziwe proszenie się o kłopoty – bardzo łatwo zderzyć się ze zmianami jakie robi w swoich tabelach sam WordPress w jednej z kolejnych wersji, albo z innym developerem o podobnie radosnym podejściu.

Nigdy nie modyfikuj tabel bazodanowych WordPressa

7. Elementy administracyjne dostępne po stronie frontowej

Interfejsy administracyjne wielu wtyczek są dość ciężkie. Ważniejsze jest to aby były  wygodne dla osoby, która z nich korzysta, wydajność ma zwykle nieco mniejsze znaczenie. Najczęściej korzysta z nich w danym momencie tylko jedna osoba, co generuje pojedyncze zapytania do serwera. Nawet jeśli dość poważnie obciążają bazę, ładują sporo danych i skryptów można z tym żyć, tak długo dopóki nie powoduje to błędów.

Niestety często autorzy wtyczek zapominają ograniczyć wykonywanie skryptów PHP albo ładowanie skryptów JS administracyjnych, tak aby nie były dołączane, wykonywane, czy przesyłane (w zależności od rodzaju skryptu i wtyczki) po stronie frontowej serwisu czyli na stronach, z których korzystają użytkownicy.

Jeśli serwis jest względnie popularny takich osób może być dużo, więc ładowanie i wykonywanie zbędnych skryptów obciąża serwer, wydłuża czas ładowania strony (co może mieć negatywny wpływ nawet na pozycję w wyszukiwarkach). W dodatku jest to dziura w bezpieczeństwie – nic złego nie musi się zdarzyć, ale rośnie prawdopodobieństwo problemów.

Zawsze ograniczaj wykonanie skryptów administracyjnych tylko do stron admina WordPressa sprawdzając to funkcją is_admin() i używając haka admin_enqueue_scripts.

8. Ładowanie wszystkich skryptów JS i arkuszy CSS na wszystkich stronach

Nawet jeśli skrypty JS administracyjne ładujemy, tak jak trzeba,  tylko w adminie, pozostaje problem, na której konkretnie stronie ładować dany skrypt.  Przecież najczęściej potrzebujemy go tylko na stronie ustawień naszego motywu czy wtyczki. Bardzo często jednak autorzy wtyczek korzystają z haka admin_enqueue_scripts bez żadnych dodatkowych warunków. To oznacza, że skrypt załaduje się na wszystkich stronach admina.

Jeśli używasz 20 wtyczek, a przy większym serwisie to nie jest wcale jakaś wyjątkowa liczba, i każda z tych wtyczek ładowałaby w ten sposób średnio 3 skrypty, to na każdej stronie admina będzie ładowane 60 skryptów, prawie wszystkie niepotrzebnie. Jeśli podobne podejście autorzy wtyczek będą mieć do kodu PHP, na każdej stronie będą się inicjalizować dziesiątki niepotrzebnych obiektów, ładować jakieś niepotrzebne zupełnie dane z bazy itd. Tak – dobrze myślisz – z tego właśnie powodu po zainstalowaniu kilkunastu wtyczek admin WordPressa jest bardzo często koszmarnie wolny. Oczywiście zależy jakich wtyczek używasz, bo niektóre są napisane porządnie.

Te same zasady mają zastosowanie po stronie frontowej. Jeśli, na przykład, używasz na stronie głównej slidera ze zdjęciami, nie musisz jego skryptu i dodatkowego arkusza stylów ładować na każdej stronie serwisu. Przecież potrzebny jest tylko na stronie głównej, prawda? Jeśli masz stronę /kontakt/ i na niej  formularz kontaktowy, to nie musisz skryptów do niego ładować na pozostałych stronach, bo tam go nie ma. I tak dalej.

Dołączaj tylko te skrypty JS i arkusze CSS, które są rzeczywiście potrzebne na danej stronie serwisu. Ograniczaj wykonanie kodu PHP tylko do stron, na których wyniki jego działania są potrzebne.

9. Sztywne kodowanie nazw katalogów i adresów URL.

Wszystkie dane i skrypty poza core WordPressa znajdują się w katalogu wp-content, wtyczki w podkatalogu plugins, motywy w podkatalogu themes, a wgrywane pliki (najczęściej obrazki) w podkatalogu uploads.

Prawda?

Nie, nie prawda!

Wszystkie te katalogi można zmienić, wystarczy kilka definicji w pliku wp-config.php i żaden z powyżej wymienionych katalogów nie będzie używany. Takie, inne konfiguracje możesz napotkać na specjalizowanych hostingach wordpressowych, inaczej te ścieżki mogą być poustawiane w instalacji WordPress multisite. Ponieważ można je zmienić, jest to przewidziane w systemie, każdy może to zrobić – dlatego nie wolno Ci kodować ich na sztywno.

Budując nazwy katalogów i adres URL plików w WordPressie zawsze korzystaj z funkcji w rodzaju content_url(), plugin_url(), wp_upload_dir(), g et_template_directory(), home_url() i podobnych oraz ewentualnie ze stałych w rodzaju WP_CONTENT_DIR, WP_CONTENT_URL, WP_PLUGIN_DIR, UPLOADS, itp.

Nigdy nie zapisuj w kodzie na sztywno nazw katalogów i adresów URL do elementów WordPressa, zainstalowanych plików, motywów i wgranych plików. Korzystaj z odpowiednich stałych i funkcji.

10. Zaniedbywanie sanityzacji danych na wejściu i nie escapowanie danych na wyjściu

Zacząłem tę część tekstu od największej zbrodni, a kończę drugą w kolejności. Ze zrozumieniem jednak przyjmę argumenty, że ta jest większa, bo dotyczy nie tylko WordPressa – jest to po prostu bardzo groźne zaniedbanie niezależnie od tego co i w czym programujemy.

W każdym programie dane podane przez użytkownika należy traktować jako „skażone” – potencjalnie groźne. W serwisie internetowym dane takie mogą pochodzić z formularza, ze zmiennych przekazanych w adresie URL (przesłane przez GET) albo przesłanych np. AJAXem przez POST. W każdym z tych przypadków nie tylko użytkownik może wpisać groźne dane, ale ktoś o złych intencjach może podmienić np. treść zapytania AJAXowego. Użycie tych danych bez sprawdzenia, bez przepuszczenia przez jakąś funkcję, która je oczyści z potencjalnych zagrożeń jest poważną i prawdopodobnie najczęściej wykorzystywana dziurą  w bezpieczeństwie. Znakomicie ilustruje to legendarna już historyjka z xkcd.

XKCD: exploits of a mom

Wszelkie dane, które wypisujemy na wyjściu powinniśmy escapować. Zapobiega to nie tylko rozsypywaniu się strony w wypadku gdy w wypisywanych danych znajdzie się coś, co zostanie zinterpretowane jako HTML, ale także przypadkowemu wykonaniu skryptów, które podsunęła nam jakaś dłoń o złych intencjach.

O wiele danych WordPress dba za nas. Jeśli na przykład poprawnie korzystamy z funkcji bazodanowych WordPressa możemy w tym obszarze czuć się bezpieczni. We wszystkich innych wypadkach mamy do dyspozycji spory zestaw funkcji zarówno w samym PHP jak i w WordPressie, które powinniśmy stosować. Polecam lekturę artykułu na ten temat w kodeksie WordPressa.

Zawsze sprawdzaj i „odkażaj” dane pochodzące z formularzy, ze zmiennych w URL strony oraz z zapytań AJAXowych. Zawsze escapuj dane wypisywane na wyjście.
Zapraszamy do lektury drugiej części poradnika.