- Czym są hooki w Drupal i jak działają
- Pojęcie hooka i ogólna idea
- Cykl życia żądania a uruchamianie hooków
- Różnica między hookami a eventami (Drupal 8+)
- Konwencje nazewnicze i pliki modułu
- Podstawowe hooki związane z menu, ścieżkami i blokami
- Definiowanie linków i menu: hook_menu_local_tasks_alter i powiązane
- Hooki związane z trasami: hook_route_alter
- Tworzenie i modyfikowanie bloków: hook_block_info i hook_block_view_alter
- Przykład prostego hooka modyfikującego tytuły stron
- Hooki formularzy – walidacja, modyfikacja i obsługa
- Podstawy: hook_form_alter i hook_form_FORM_ID_alter
- Walidacja formularza: hook_form_validate i dedykowane callbacki
- Modyfikacja obsługi wysyłki: hook_form_submit i logika biznesowa
- Praktyczne wskazówki dotyczące modyfikacji formularzy
- Hooki encji i węzłów – reagowanie na tworzenie, zapis i usuwanie
- Podstawowe hooki encji: tworzenie, zapis, usuwanie
- Przykłady użycia hook_node_insert i hook_node_update
- Hooki ładowania i wyświetlania encji: hook_entity_view i hook_entity_view_alter
- Bezpieczeństwo i wydajność przy hookach encji
- Hooki tematyczne i preprocess – kontrola nad warstwą prezentacji
- Hook_theme – rejestrowanie elementów tematycznych
- Hooki preprocess – modyfikacja zmiennych dla szablonów
- Hook_page_attachments i hook_page_top – dodawanie zasobów
- Łączenie hooków tematycznych z logiką biznesową
System hooków w Drupal to jeden z najważniejszych mechanizmów, który pozwala programistom ingerować w działanie rdzenia i modułów bez modyfikowania ich kodu. Dzięki nim można elastycznie rozszerzać funkcjonalność, reagować na konkretne zdarzenia w cyklu życia strony i tworzyć własne logiki biznesowe. Zrozumienie, jak działają hooki, jest kluczowe dla efektywnego tworzenia i utrzymywania modułów w praktycznie każdym projekcie opartym na Drupal.
Czym są hooki w Drupal i jak działają
Pojęcie hooka i ogólna idea
Hook w Drupal to funkcja w module, której nazwa jest zbudowana według ściśle określonego wzorca. Rdzeń Drupala lub inny moduł wywołuje te funkcje w określonych momentach – na przykład podczas zapisywania węzła, renderowania strony czy generowania formularza. Dzięki temu możemy wstrzyknąć własny kod dokładnie tam, gdzie jest on potrzebny.
Ogólny wzorzec nazewnictwa hooka wygląda tak: mymodule_hook_name(), gdzie:
- mymodule – to nazwa naszego modułu (dokładnie taka, jak w pliku .info.yml),
- hook_name – to nazwa konkretnego hooka zdefiniowana przez rdzeń lub inny moduł.
Hooki nie wymagają rejestracji w żadnym dodatkowym miejscu – Drupal wyszukuje je automatycznie po nazwach funkcji w załadowanych plikach modułów. Jest to **fundament** mechanizmu rozszerzeń w tym systemie.
Cykl życia żądania a uruchamianie hooków
Drupal podczas przetwarzania każdego żądania HTTP przechodzi przez szereg etapów: od rozpoznania ścieżki, poprzez ładowanie encji, budowę struktury renderowania, aż do wysłania odpowiedzi. Na każdym z tych etapów mogą być wywoływane różne hooki. Pozwala to bardzo **precyzyjnie** dopasować moment ingerencji w przetwarzanie.
Przykładowo:
- podczas ładowania encji (np. węzła) uruchamiane są hooki dotyczące encji,
- podczas budowy menu wywoływane są hooki odpowiedzialne za linki i ścieżki,
- w momencie generowania formularza aktywowane są hooki związane z formularzami.
Takie podejście zapewnia **modularność** i wysoki poziom **elastyczności**, ponieważ każdy moduł może wprowadzać swoje modyfikacje bez wiedzy o implementacji pozostałych elementów systemu.
Różnica między hookami a eventami (Drupal 8+)
Od Drupala 8 wprowadzono system zdarzeń oparty na Symfony Event Dispatcher, który współistnieje z klasycznym systemem hooków. W praktyce wiele operacji można zrealizować zarówno przez hooki, jak i przez eventy. Jednak wciąż znaczna część API rdzenia korzysta z hooków, dlatego ich znajomość pozostaje **kluczowa**.
Najważniejsze różnice:
- hooki są funkcjami proceduralnymi,
- eventy są obsługiwane przez klasy (subskrybenci zdarzeń),
- hooki są bardzo silnie zakorzenione w starszych częściach API,
- eventy lepiej wpisują się w nowoczesny, obiektowy styl programowania.
W tym artykule skupiamy się na hookach, ponieważ stanowią one podstawę pracy z wieloma istniejącymi modułami i są nadal powszechnie wykorzystywane w codziennej **implementacji**.
Konwencje nazewnicze i pliki modułu
W module Drupal (8/9/10) większość hooków implementuje się w pliku mymodule.module. Funkcje hooków znajdujące się w tym pliku są automatycznie ładowane przez autoloader Drupala, co zapewnia ich dostępność wtedy, gdy są potrzebne.
Przykładowa struktura prostego modułu:
- mymodule.info.yml – metadane modułu,
- mymodule.module – funkcje hooków i kod proceduralny,
- src/ – katalog z klasami PHP (kontrolery, serwisy, pluginy itp.),
- mymodule.routing.yml – definicje ścieżek, jeśli moduł je dodaje,
- mymodule.services.yml – definicje serwisów kontenera DI.
Choć hooki są funkcjami proceduralnymi, w ich wnętrzu można wykorzystywać serwisy, encje czy inne obiektowe elementy Drupala, uzyskując połączenie prostoty hooków z **nowoczesną** architekturą systemu.
Podstawowe hooki związane z menu, ścieżkami i blokami
Definiowanie linków i menu: hook_menu_local_tasks_alter i powiązane
W starszych wersjach Drupala (do 7 włącznie) istniał jeden dominujący hook do definiowania menu – hook_menu. W Drupal 8+ jego rolę rozbito na kilka różnych plików konfiguracyjnych YAML i dedykowanych hooków. Jednym z częstych zadań jest modyfikowanie lokalnych zadań (tzw. tabs), czyli zakładek widocznych nad treścią.
Przykład zastosowania hook_menu_local_tasks_alter:
- zmiana kolejności zakładek,
- ukrywanie wybranych zakładek dla określonych ról,
- dodawanie własnych zakładek powiązanych z istniejącą ścieżką.
Tego typu hook pozwala dopasować interfejs nawigacji do specyficznych potrzeb projektu, bez konieczności modyfikowania modułów odpowiedzialnych za oryginalne linki.
Hooki związane z trasami: hook_route_alter
Od Drupala 8 routing jest konfigurowany w plikach YAML, ale istnieje możliwość modyfikowania tras w locie za pomocą hook_route_alter. Ten hook pozwala zmieniać parametry trasy już po jej wczytaniu z definicji, co daje duże możliwości dostosowywania zachowania strony.
Typowe zastosowania hook_route_alter:
- podmiana kontrolera odpowiedzialnego za obsługę danej ścieżki,
- modyfikacja wymagań dostępu (np. dodanie warunku uprawnienia),
- aktualizacja parametrów cache,
- zmiana tytułu strony generowanego przez konkretną trasę.
Dzięki temu można rozszerzać lub nadpisywać **domyślne** zachowanie rdzenia i modułów, zachowując jednocześnie spójność z mechanizmem routingu opartym na Symfony.
Tworzenie i modyfikowanie bloków: hook_block_info i hook_block_view_alter
W Drupal 7 bloki definiowano głównie poprzez hook_block_info oraz hook_block_view. W Drupal 8+ standardem stały się pluginy Block, jednak nadal istnieje hook_block_view_alter, który umożliwia modyfikację danych renderujących dowolny blok, również taki, którego nie stworzył nasz moduł.
Przykładowe zastosowania hook_block_view_alter:
- dodanie klas CSS do wybranych bloków,
- modyfikacja tytułów bloków przed ich wyrenderowaniem,
- dołączenie dodatkowych elementów (np. komunikatów, linków CTA) do zawartości bloku.
Mechanizm bloków jest często wykorzystywany przy tworzeniu layoutów, dlatego możliwość ingerowania w ich zawartość to istotne narzędzie dla front-end i back-end developerów pracujących nad **personalizacją** wyglądu strony.
Przykład prostego hooka modyfikującego tytuły stron
Częstą potrzebą jest globalna modyfikacja tytułów stron, na przykład dodanie nazwy serwisu lub prefiksu w zależności od typu zawartości. Do tego celu można wykorzystać hook_page_attachments czy hook_preprocess_page, ale równie dobrze da się ominąć warstwę szablonów i operować wcześniej na strukturze renderującej.
W praktyce w hooku:
- sprawdza się aktualną trasę,
- pobiera się tytuł generowany przez rdzeń,
- modyfikuje się go zgodnie z regułami biznesowymi,
- zapisuje się nową wartość do użycia przy renderowaniu.
Takie rozwiązania, oparte na hookach, pozwalają utrzymać **spójność** całego serwisu bez rozpraszania logiki modyfikacji po wielu osobnych szablonach.
Hooki formularzy – walidacja, modyfikacja i obsługa
Podstawy: hook_form_alter i hook_form_FORM_ID_alter
Jednym z najczęściej używanych hooków w codziennej pracy z Drupalem jest hook_form_alter oraz jego bardziej szczegółowy wariant hook_form_FORM_ID_alter. Umożliwiają one modyfikowanie istniejących formularzy tworzonych przez rdzeń lub inne moduły bez ingerencji w ich kod źródłowy.
Zastosowania:
- dodawanie nowych pól do formularza,
- zmiana etykiet i opisów istniejących pól,
- modyfikacja typów elementów (np. z pola tekstowego na select),
- dostosowanie struktury formularza do wymagań UI/UX.
W wielu projektach hook_form_alter staje się centralnym miejscem zarządzania **logiką** interfejsu administracyjnego i części formularzowej front-endu, ponieważ pozwala implementować zmiany w jednym, łatwym do kontrolowania punkcie.
Walidacja formularza: hook_form_validate i dedykowane callbacki
Drupal umożliwia dodawanie niestandardowych funkcji walidujących zarówno przez hooki, jak i przez pola formularza. Hooki odgrywają tu ważną rolę, gdy chcemy rozszerzyć istniejący formularz o dodatkowe reguły walidacji lub zmienić sposób, w jaki jest przetwarzany.
Typowe scenariusze:
- sprawdzenie unikalności danych wpisanych przez użytkownika,
- walidacja powiązań między polami (np. porównanie dat),
- blokowanie wysłania formularza przy niespełnieniu określonych kryteriów biznesowych,
- wstrzyknięcie komunikatów o błędach, które informują użytkownika, co należy poprawić.
W połączeniu z hook_form_alter, niestandardowe callbacki walidujące dają pełną **kontrolę** nad sposobem działania kluczowych formularzy, np. rejestracji czy edycji profilu użytkownika.
Modyfikacja obsługi wysyłki: hook_form_submit i logika biznesowa
Wiele akcji biznesowych jest uruchamianych w momencie wysłania formularza – zapis danych, wysyłka e-maili, integracje z zewnętrznymi API. Hooki pozwalają dopiąć się do tego momentu i rozszerzyć istniejące operacje lub je nadpisać.
Przykłady:
- dodatkowy zapis danych w zewnętrznej bazie lub systemie CRM,
- logowanie specyficznych zdarzeń (np. zmiana ważnych pól profilu),
- generowanie plików (np. PDF) po zatwierdzeniu formularza.
Korzyść z wykorzystania hooków jest taka, że cała niestandardowa logika pozostaje odseparowana od rdzenia i oryginalnych modułów, co zwiększa **utrzymywalność** i ułatwia przyszłe aktualizacje.
Praktyczne wskazówki dotyczące modyfikacji formularzy
Podczas pracy z hookami formularzy warto stosować kilka dobrych praktyk:
- wykorzystywać hook_form_FORM_ID_alter zamiast globalnego hook_form_alter tam, gdzie to możliwe – poprawia to czytelność,
- grupować powiązane zmiany w osobnych funkcjach pomocniczych, jeśli logika staje się rozbudowana,
- unikać logiki biznesowej bezpośrednio w hookach – lepiej wywoływać serwisy lub metody klas,
- dbać o konsekwentne nazywanie callbacków walidujących i submitujących, aby szybko je odnajdywać.
Takie podejście sprawia, że kod oparty na hookach staje się bardziej **czytelny**, odporny na błędy i łatwiejszy do rozwijania przez większy zespół programistów.
Hooki encji i węzłów – reagowanie na tworzenie, zapis i usuwanie
Podstawowe hooki encji: tworzenie, zapis, usuwanie
Drupal opiera wiele elementów na systemie encji – od węzłów (node), przez użytkowników, aż po taksonomie. Hooki encji umożliwiają reagowanie na całe spektrum operacji wykonywanych na tych obiektach, co jest fundamentem wielu zaawansowanych rozwiązań biznesowych.
Do kluczowych hooków należą:
- hook_entity_insert – reaguje po utworzeniu encji,
- hook_entity_update – wywoływany po aktualizacji,
- hook_entity_delete – uruchamiany przed usunięciem encji,
- odpowiedniki specyficzne dla typu, np. hook_node_insert, hook_user_update.
W tych hookach można:
- modyfikować powiązane dane w innych encjach,
- aktualizować zewnętrzne systemy,
- wykonywać zaawansowane operacje obliczeniowe na podstawie pól encji.
Takie wykorzystanie hooków pozwala tworzyć **złożone** zależności pomiędzy różnymi obiektami w aplikacji.
Przykłady użycia hook_node_insert i hook_node_update
W kontekście węzłów typowe scenariusze obejmują:
- automatyczne ustawianie dodatkowych wartości pól po zapisaniu węzła,
- generowanie skrótów, aliasów URL lub metadanych SEO,
- powiadamianie administratorów lub redaktorów o zmianach w kluczowych typach treści.
Na przykład w hook_node_insert można:
- sprawdzić typ zawartości,
- wykonać obliczenia na podstawie wprowadzonych pól,
- zapisać wyniki w dodatkowym polu lub osobnej encji pomocniczej.
W hook_node_update podobna logika może uwzględniać różnice między poprzednim a aktualnym stanem węzła, co przydaje się przy implementacji systemów wersjonowania lub audytu.
Hooki ładowania i wyświetlania encji: hook_entity_view i hook_entity_view_alter
Poza reagowaniem na zapis i usuwanie, równie ważne jest wpływanie na sposób, w jaki encje są prezentowane użytkownikowi. W tym celu używa się takich hooków jak hook_entity_view czy hook_entity_view_alter, które działają na strukturze renderującej, zanim zostanie przekształcona w HTML.
Możliwości:
- dodanie nowych elementów do widoku encji (np. przyciski, informacje pomocnicze),
- modyfikacja kolejności pól,
- wstrzyknięcie dodatkowych atrybutów HTML (np. klas CSS warunkowych),
- usunięcie wybranych elementów z widoku dla konkretnego kontekstu.
Działając na poziomie struktury renderującej, zachowuje się **separację** między logiką a warstwą szablonów, co ułatwia współpracę między programistami back-end a front-end i zmniejsza liczbę modyfikacji w plikach twig.
Bezpieczeństwo i wydajność przy hookach encji
Hooki encji uruchamiane są bardzo często – przy każdym zapisie, aktualizacji czy usunięciu. Dlatego należy zwrócić szczególną uwagę na:
- minimalizowanie liczby zapytań do bazy wewnątrz hooków,
- unikanie ciężkich operacji (np. długich wywołań zewnętrznych API) bez mechanizmu kolejkowania,
- walidację danych wejściowych, jeśli hook przetwarza informacje pochodzące od użytkowników,
- zachowanie czytelności i rozdzielenie logiki na mniejsze, testowalne elementy (np. serwisy).
Odpowiedzialne korzystanie z hooków encji ma bezpośredni wpływ na **wydajność** całej instalacji Drupala, ponieważ to właśnie operacje na encjach stanowią trzon wielu krytycznych funkcji serwisu.
Hooki tematyczne i preprocess – kontrola nad warstwą prezentacji
Hook_theme – rejestrowanie elementów tematycznych
System tematyczny Drupala pozwala deklarować własne typy wyjścia HTML (tzw. theme hooks), które następnie mogą być renderowane przez odpowiednie szablony twig lub funkcje tematyzujące. Rejestracja odbywa się za pomocą hook_theme, który zwraca tablicę definicji elementów tematycznych.
W definicjach można określić:
- nazwę elementu tematycznego,
- argumenty, jakie przyjmuje (np. dane do wyświetlenia),
- domyślny szablon twig,
- opcje cache i inne parametry.
Dzięki hook_theme możliwe jest zbudowanie spójnego systemu prezentacji danych, w którym wiele modułów korzysta z tych samych, wielokrotnie używalnych komponentów **wizualnych**.
Hooki preprocess – modyfikacja zmiennych dla szablonów
Hooki preprocess to specjalny rodzaj hooków, których nazwy są powiązane z nazwami elementów tematycznych. Pozwalają one modyfikować lub dodawać zmienne przekazywane do szablonów twig tuż przed renderowaniem. Przykładami są:
- hook_preprocess_page,
- hook_preprocess_node,
- hook_preprocess_block,
- hook_preprocess_html.
Za ich pomocą można:
- dodawać nowe klasy CSS w zależności od kontekstu,
- przygotowywać zmienne agregujące dane z wielu źródeł,
- tworzyć flagi warunkowe wykorzystywane w szablonach (np. czy użytkownik jest zalogowany).
Mechanizm preprocess sprawia, że szablony twig pozostają relatywnie proste, a cała **logika** przygotowania danych znajduje się po stronie PHP, gdzie łatwiej ją testować i utrzymywać.
Hook_page_attachments i hook_page_top – dodawanie zasobów
Do zarządzania zasobami front-end (CSS, JavaScript, biblioteki) Drupal oferuje system attachments oraz hooki, które pozwalają wstrzykiwać zasoby w różnych miejscach renderowania strony. Przykładem jest hook_page_attachments, który umożliwia dodawanie bibliotek do całej strony lub konkretnych elementów.
Najczęstsze zastosowania:
- dołączanie własnych bibliotek JavaScript do wybranych tras,
- warunkowe ładowanie arkuszy CSS dla określonych typów treści,
- wstrzykiwanie metatagów do sekcji head.
Z kolei hook_page_top i pokrewne pozwalają dodawać elementy na samej górze struktury strony, np. globalne komunikaty, paski informacyjne czy kontenery potrzebne do działania frameworków front-endowych. To wszystko umożliwia pełną **kontrolę** nad prezentacją bez konieczności hackowania szablonów rdzenia.
Łączenie hooków tematycznych z logiką biznesową
Choć hooki tematyczne są ściśle związane z warstwą prezentacji, nic nie stoi na przeszkodzie, by w ich implementacji wykorzystywać serwisy czy logikę biznesową. W praktyce warto jednak zachować równowagę:
- ciężką logikę, szczególnie tę związaną z danymi, utrzymywać w serwisach,
- w hookach preprocess i hook_theme jedynie przygotowywać dane do wyświetlenia,
- unikać bezpośrednich zapytań do bazy w kodzie prezentacji.
Takie rozdzielenie ułatwia testowanie i zapewnia większą **skalowalność** projektu, gdy rośnie liczba szablonów, motywów i modułów zależnych od warstwy front-end.