Module scope and important limitations w PrestaShop to konkretne pytanie projektowe: czy da się to zrobić modułem, czy trzeba sięgnąć po override, a może zmienić architekturę. Zasięg modułu wyznaczają hooki, kontrolery front i back, szablony .tpl, własne tabele z prefiksem sklepu oraz konfiguracja Configuration — wszystko poza tą listą wymaga decyzji, która ma swoją cenę. Poniżej znajdziesz mapę zasięgu dla PrestaShop 1.7 i 8, twarde ograniczenia architektoniczne i wydajnościowe oraz sposoby ich sprawdzenia. Punktem odniesienia jest oficjalna dokumentacja dla deweloperów PrestaShop, a nie marketingowe obietnice dostawców modułów. Zaczynamy od rozróżnienia pojęć, bo większość sporów w projektach bierze się z mylenia zasięgu z uprawnieniami.
W praktyce „module scope” to odpowiedź na jedno pytanie: do jakich warstw sklepu moduł ma dostęp i kiedy ten dostęp faktycznie działa. Pod tym terminem kryją się dwie różne rzeczy i warto je rozdzielić.
Zasięg w PHP obejmuje: klasę modułu dziedziczącą po Module, metody hooków, kontrolery front w controllers/front/, kontrolery back w controllers/admin/, pliki w katalogu override/, szablony .tpl w views/templates/, własne tabele z prefiksem _DB_PREFIX_, wpisy w tabeli konfiguracji oraz cache (kompilacja Smarty, Cache::store).
Zasięg w JS to coś innego: skrypt frontendowy działa albo jako ES module ładowany własnym bundlerem, albo jako plik wrzucony do globalnego window. W drugim wariancie dwie zmienne o tej samej nazwie z dwóch modułów potrafią wyłączyć cały blok JavaScript, a błąd wychodzi dopiero po zmianie kolejności skryptów w hooku.
Różnica w zasięgu wykonania jest równie istotna. Ten sam kod w displayHeader (dziś częściej actionFrontControllerSetMedia) odpala się przy każdym renderze strony. W katalogu z 2000 produktów to 2000 dodatkowych wykonań, nawet jeśli nic nie zwraca. Ten sam kod w displayOrderConfirmation odpala się raz, po złożeniu zamówienia.
I rzecz, która myli najczęściej: zasięg to nie uprawnienia. Moduł nie działa w żadnym sandboxie — wykonuje się z uprawnieniami procesu PHP i ma dostęp do plików oraz bazy tak samo jak core. Granice są więc techniczne (hooki, API, konwencje), a nie formalne. Jeśli moduł zapisze dane w złej tabeli albo nadpisze plik, który nie powinien, nikt go w tym nie powstrzyma.
Zasięg zaczepienia modułu sprowadza się do trzech rodzin hooków, dwóch typów kontrolerów i jednego katalogu override.
displayHome, displayHeader, displayShoppingCartFooter, displayProductAdditionalInfo. Nadają się do wstawek w widoku, nie do logiki biznesowej.actionCartSave, actionValidateOrder, actionPaymentConfirmation, actionProductUpdate. Tu zapisujesz dane, wysyłasz e-mail, wołasz API zewnętrzne.filterCmsContent, filterProductContent, filterHtmlContent. Zmieniasz treść bez zapisu do bazy.Kontrolery: moduł może mieć własny front controller (adres /module/nazwa/kontroler) oraz własny admin controller z zakładką w panelu (klasa Tab plus uprawnienia ACL). Widoki nadpisujesz szablonami z views/templates/front/ lub views/templates/hook/. Najszerszy zasięg daje override/ — i to on generuje najwięcej problemów przy aktualizacji sklepu.
Dane: tabele tworzone w install() przez Db::getInstance()->execute() z prefiksem _DB_PREFIX_, dalej ObjectModel i DbQuery. Konfiguracja przez Configuration::updateValue() z parametrami $idShopGroup i $idShop zapisuje się dla konkretnego sklepu, a updateGlobalValue() dla całej instalacji. W multistore to najczęstsze źródło pytania „czemu ustawienie zniknęło na drugim sklepie”.
Czego moduł nie dostanie za darmo: danych, których w danym hooku jeszcze nie ma. W actionCartSave koszyk istnieje, ale zamówienie jeszcze nie — nie ma czego dopisać do tabeli zamówień. W displayOrderConfirmation zamówienie jest, ale koszyk bywa już wyczyszczony. Jeśli potrzebujesz obu, użyj actionValidateOrder, który w jednym miejscu dostaje $order, $cart, $customer i $currency.
Pełną listę hooków i ich parametrów trzymaj z dokumentacji dla deweloperów PrestaShop. A jeśli startujesz od zera, zamiast ręcznie klepać rejestrację hooków w klasie, generator szkieletu modułu PrestaShop tworzy katalog, klasę i podstawową rejestrację hooków.
| Warstwa | Jak moduł się do niej dostaje | Gdzie jest granica |
|---|---|---|
| Hooki | registerHook() + metoda hookDisplayX / hookActionX | Brak gwarancji kolejności, nie każdy hook ma pełny kontekst danych |
| Kontrolery | controllers/front/ i controllers/admin/ + zakładka Tab | Routing i uprawnienia ACL trzeba skonfigurować samodzielnie |
| Szablony .tpl | views/templates/hook/ i views/templates/front/ | Edycja pliku .tpl z core ginie przy aktualizacji |
| Baza danych | Własne tabele z _DB_PREFIX_ tworzone w install() | Migracje i upgrade własnych tabel piszesz sam |
| Konfiguracja | Configuration::updateValue() / updateGlobalValue() | Zakres per shop — w multistore łatwo zgubić wartość |
| Cache | Cache::store, kompilacja Smarty | Po zmianie .tpl trzeba wyczyścić cache, inaczej widzisz stary widok |
Granice, przy których trzeba wybierać między modułem, override'em i przebudową, są w PrestaShop dość twarde. Cztery najważniejsze:
1. Plików core nie ruszamy. Edycja classes/Cart.php czy controllers/front/ProductController.php działa do pierwszej aktualizacji. 1-Click Upgrade nadpisuje pliki core i zmiana znika. Debugowanie takiej zmiany po pół roku kosztuje więcej niż ponowne wdrożenie, bo nikt już nie pamięta, co dokładnie było zmienione.
2. Konflikt override'ów. Dwa moduły nadpisujące tę samą metodę tej samej klasy — wygrywa ten, który zapisał plik później. Objawy: fatal error PHP, komunikat o brakującej metodzie albo cicha utrata funkcji (rabat przestaje się naliczać, dokumenty wychodzą bez numeru). Wykryjesz to tak: find override -name "*.php" na serwerze, porównanie plików z listą zainstalowanych modułów, potem wyłączanie modułów po jednym i sprawdzenie, czy problem wraca. W BO → Zaawansowane → Wydajność jest dodatkowo globalny przełącznik wyłączający wszystkie override'y.
3. Kolejność wykonania hooków. registerHook() wrzuca moduł domyślnie na koniec listy. Kolejność zmienia się w BO → Design → Pozycje. Moduł nie gwarantuje jej sam z siebie — jeśli Twój JavaScript zależy od skryptu innego modułu, bez kontroli pozycji dostaniesz błąd „undefined is not a function”.
4. Ograniczony kontekst w części hooków. displayHeader nie ma jeszcze danych zamówienia, actionProductUpdate nie ma koszyka. Obejście kosztuje dodatkowe zapytanie albo przejście na hook, który ma pełny kontekst.
Kiedy override jest jedynym wyjściem? Gdy trzeba zmienić logikę metody core, do której nie ma hooka — na przykład sposób liczenia ceny w Product::getPrice(). Wtedy: jedna metoda, minimum kodu, komentarz z wersją PrestaShop i test po każdej aktualizacji. W pozostałych przypadkach taniej dopisać własne zdarzenie action* w swoim module i rozszerzać je z innych modułów.
| Objaw | Najczęstsza przyczyna | Co sprawdzić w pierwszej kolejności |
|---|---|---|
| Fatal error po instalacji modułu | Konflikt override na tej samej klasie/metodzie | Lista plików w override/ i kolejność instalacji modułów |
| Funkcja działa po aktualizacji, potem znika | Zmiana w pliku core nadpisana przez upgrade | Porównanie plików core z wersją z repozytorium |
| Skrypt JS nie startuje | Zła pozycja modułu w hooku | BO → Design → Pozycje, kolejność na hoście skryptu |
Każdy hook, do którego moduł się podłącza, to dodatkowe wywołanie metody przy renderze strony. Brzmi niegroźnie, dopóki nie policzysz tego w skali: 35 aktywnych modułów, z czego 8 rejestruje po kilkanaście hooków, i nagle jedno wejście na kartę produktu generuje kilkaset wywołań. Nie każde jest kosztowne, ale każde, które sięga do bazy, do pliku albo do zewnętrznego API, dokłada się do TTFB.
Najczęstszy efekt złego zasięgu to N+1 queries. Moduł w hooku listy produktów pobiera produkty, a potem w pętli odpyta bazę o oceny, stany magazynowe albo zdjęcia każdego z nich osobno. Przy 24 produktach na stronie masz 25 zapytań tam, gdzie wystarczyłoby jedno z JOIN. Objaw widać w profilerze (debug toolbar, tryb _PS_MODE_DEV_ na stagingu) oraz w slow query log MySQL — powtarzający się pattern SELECT ... WHERE id_product = X wykonany dwadzieścia kilka razy pod rząd to niemal zawsze ten problem.
Osobny temat to cache. Moduł, który w hooku displayHeader wykonuje logikę niezależną od zalogowanego użytkownika, potrafi unieważnić cache stronowy albo wymusić jego omijanie — i wtedy cała konfiguracja cache przestaje działać, choć nikt jej nie zmieniał.
Reguła praktyczna: jeśli funkcja wymaga zapytania przy każdym renderze, przenieś ją do zadania cron (np. raz na 15 minut) albo do zasobu trzymanego w cache'u. Hook ma składać gotowe dane, a nie je liczyć. Zachowanie ograniczeń hooków i kontekstu opisuje dokumentacja dla deweloperów PrestaShop.
| Wskaźnik | Gdzie zmierzyć na stagingu | Wartość, przy której zaczynasz szukać winowajcy |
|---|---|---|
| TTFB | DevTools → Network → nagłówek odpowiedzi HTML | powyżej ~400 ms bez ruchu na serwerze |
| Liczba zapytań SQL | profiler / debug toolbar, zakładka SQL | powyżej ~80–120 na stronę kategorii lub produktu |
| Czas renderu szablonu | profilowanie w trybie debug | widoczny wzrost po włączeniu jednego modułu |
| Pamięć peak PHP | memory_get_peak_usage() lub log PHP-FPM | skok o dziesiątki MB po dołożeniu modułu |
W sklepie z jednym sklepem i jednym językiem prawie każdy moduł zachowa się poprawnie. Problem pojawia się przy multistore, i to nie dlatego, że moduł jest zepsuty — po prostu jego zasięg jest węższy, niż zakładał autor.
Zacznij od konfiguracji. Tabela configuration ma kolumny id_shop_group i id_shop. Jeśli obie są NULL, wpis jest globalny. Ten sam klucz może mieć osobną wartość dla sklepu 1 i sklepu 2, a Configuration::get('MOJ_KLUCZ') zwróci wartość zależną od aktualnego kontekstu. Moduł, który zapisuje ustawienie bez parametru sklepu, ustawia je globalnie i potem „działa” tylko w konfiguracji, w której był testowany.
Druga pułapka to własne tabele. Jeśli tworzysz je w instalacji modułu bez kolumn id_shop i id_shop_group, dane z obu sklepów wpadają do jednego worka. Wygląda to jak drobiazg, dopóki klient nie zgłosi, że na sklepie B widzi treści ze sklepu A. Łatwo o to przy automatycznym generowaniu struktury modułu — dlatego po wygenerowaniu szkieletu sprawdź definicje tabel, np. korzystając z generatora modułów PrestaShop, i dopisz kolumny sklepowe, jeśli planujesz multistore.
Trzecia rzecz to język. Tabele z sufiksem _lang mają id_lang, a brak wiersza dla danego języka oznacza fallback do języka domyślnego sklepu. W widokach nie używaj na sztywno Configuration::get('PS_LANG_DEFAULT') — bierz $this->context->language->id.
Test minimum przed wdrożeniem: włącz multistore na stagingu, dodaj drugi sklep, przypisz mu inną domenę i sprawdź moduł w kontekście sklepu drugiego — konfigurację, tabele i treści językowe.
Klasyczny <script> i <script type="module"> mają różny zasięg. W klasycznym skrypcie deklaracja var x = 1 na najwyższym poziomie tworzy globalną zmienną w window. W module ES to samo jest widoczne wyłącznie wewnątrz pliku — moduły mają własny scope i wykonują się odroczone. Efekt: kod szablonu nie widzi funkcji z modułu, a moduł nie widzi funkcji szablonu, dopóki nie połączy ich jawnie.
W PrestaShop 1.7 i 8 motyw korzysta z bundlera (webpack w motywie Classic i jego pochodnych), a jQuery jest już dołączone. Modul, który dokłada własną kopię jQuery, to klasyk: podwójne ładowanie, wtyczki podpinane do innej instancji, błędy typu $ is not a function. Do tego kolejność inicjalizacji — jeśli skrypt modułu startuje przed skryptem motywu, elementy jeszcze nie istnieją w DOM.
Kolizje nazw wykryjesz w DevTools. W zakładce Console sprawdź window.jQuery.fn.jquery i to, ile razy jQuery faktycznie się załadowało. W Sources zobacz kolejność plików i to, który moduł nadpisuje twój selektor klas lub atrybut data-*. W Performance nagraj sesję i sprawdź, czy skrypty nie blokują pierwszego renderu.
Zasada: moduł eksportuje minimum i komunikuje się przez zdarzenia (CustomEvent) albo publiczne API w jednym namespace, np. window.DropDigitalMoje. Nigdy przez zmienne globalne rozrzucone po plikach.
Konsekwencja dla SEO jest mierzalna: nadmiarowy i blokujący JS pogarsza LCP i INP, co widać w raporcie Core Web Vitals w Search Console. Mechanikę tych wskaźników opisuje web.dev – Core Web Vitals.
| Cecha | Klasyczny <script> | <script type="module"> |
|---|---|---|
| Scope zmiennych | globalny (window) | własny, zamknięty w pliku |
| Moment wykonania | od razu, blokuje parsowanie | odroczone, po sparsowaniu DOM |
| Widoczność dla motywu | przez window | tylko przez jawne window lub zdarzenia |
| Duplikaty | łatwe do przeoczenia | nadmiarowe importy i bundlowanie |
Każdy hook, kontroler i własna tabela to kolejne wejście do sklepu. Moduł, który obsługuje formularz na froncie, panel w back office, zapis do bazy i wypis danych w szablonie, ma cztery powierzchnie ataku — i wszystkie musi zamknąć sam, bo PrestaShop tego za niego nie zrobi.
Dane wejściowe i wyjściowe. Tools::getValue() zwraca dokładnie to, co przyszło — niczego nie waliduje. Sprawdzaj typ funkcjami Validate::isInt(), Validate::isEmail(), Validate::isGenericName(), Validate::isCleanHtml() i dopiero potem zapisuj. Na wyjściu nie polegaj na czyszczeniu przy zapisie: w pliku .tpl pisz {$nazwa|escape:'htmlall':'UTF-8'}. Najczęstszy błąd, jaki widzimy w audytach, to pole z formularza zapisane przez Configuration::updateValue() i wypisane w szablonie bez escape — gotowy stored XSS, który wykona się u każdego klienta wchodzącego na stronę. Zasady walidacji i konwencje kodu opisuje dokumentacja dla deweloperów PrestaShop.
Baza danych. Nie sklejaj zapytań ze zmiennych pobranych z getValue(). Identyfikatory rzutuj na (int), ciągi przepuszczaj przez pSQL(), a operacje ograniczaj do tabel z prefiksem sklepu i nazwą modułu. Pisanie do ps_product czy ps_orders w hooku zapisu zamówienia kończy się konfliktem z innymi modułami i niespodzianką po aktualizacji core.
CSRF i uprawnienia. Każda akcja POST w kontrolerze admina modułu musi przejść przez checkToken() z tokenem z {getAdminTokenLite}. Bez tego wystarczy, że zalogowany pracownik kliknie link z maila, żeby wykonać akcję w sklepie. Nie omijaj ACL: kontroler dziedziczący po ModuleAdminController ma respektować $this->access (view/add/edit/delete) oraz uprawnienia roli ustawione w profilach — moduł nie jest furtką obok uprawnień.
Pliki. Moduł nie potrzebuje prawa zapisu w /classes, /controllers, /themes ani w katalogu cache PrestaShop. Jeśli musi pisać, wyznacz katalog var/ wewnątrz /modules/nazwa/ i ustaw na nim 755 — nigdy 777 na cały /modules.
| Etap | Pytanie kontrolne | Zabezpieczenie |
|---|---|---|
| Przyjmowanie danych | Skąd moduł bierze dane i czy sprawdza typ? | Tools::getValue() + Validate::isInt/isEmail/isGenericName/isCleanHtml |
| Zapis danych | Do jakich tabel i w jakiej formie trafiają dane? | (int) dla ID, pSQL() dla ciągów, wyłącznie tabele z _DB_PREFIX_ i własne |
| Wypis danych | Czy każda zmienna w .tpl jest escapowana? | {$zmienna|escape:'htmlall':'UTF-8'} także dla danych z Configuration |
| Akcje w adminie | Czy POST ma token i sprawdzenie uprawnień? | checkToken() + token z {getAdminTokenLite} + $this->access |
| Dostęp do plików | Czy moduł zapisuje poza swoim katalogiem? | Tylko /modules/nazwa/var/, prawa 755, żadnego zapisu w core i cache |
Zasięg modułu najtaniej sprawdzić przed wdrożeniem. Testowanie na produkcji kosztuje klientów, kopiowanie bazy do stagingu — kilkanaście minut.
Środowisko. Staging to kopia produkcji: ten sam numer wersji PrestaShop (np. 8.1.5), ta sama wersja PHP (np. 8.1, nie 7.4), te same moduły w tych samych wersjach i ten sam szablon. Minimalny katalog testowy: 1000 produktów, w tym jeden z 20 kombinacjami i jeden przetłumaczony na wszystkie aktywne języki.
Pomiary przed i po. Włącz tryb debug (Zaawansowane parametry → Wydajność), odśwież stronę — na dole pojawi się liczba zapytań SQL i czas generowania. Zmierz cztery widoki: listę kategorii, kartę produktu, koszyk i podsumowanie zamówienia. Po pięć odświeżeń na widok, bierz medianę. Wzrost o 10–15 zapytań na stronę albo TTFB wyższe o 100 ms oznacza zwykle pętlę w pętli — zapytanie w foreach po produktach zamiast jednego z klauzulą IN(). Zapisuj wyniki w tabelce przed/po, bo po dwóch tygodniach nikt nie pamięta liczb.
Test aktualizacji. Na kopii stagingu zaktualizuj core o jedną wersję do przodu i sprawdź overrides: czy plik z /override/classes/Product.php nadal działa i czy nadpisywana metoda nie zmieniła sygnatury. Override skopiowany w całości, gdy klasa bazowa dostała nowy argument, to fatal error na produkcji. Bezpieczniej trzymać jedną metodę i wołać parent::metoda() zamiast kopiować ciało.
Multistore i języki. Przy dwóch sklepach sprawdź Configuration::get('MOJA_ZMIENNA', null, $id_shop_group, $id_shop) — bez kontekstu sklepu wartość zapisana w sklepie A wycieknie do B. To samo z tłumaczeniami: pole zapisane tylko dla jednego id_lang to klasyczna wpadka przy wdrożeniu na rynek czeski czy niemiecki.
Szkielet modułu wygenerujesz bez pisania od zera — sprawdź, jak użyć generatora szkieletu modułu PrestaShop i jakich błędów uniknąć przy podmianie nazw oraz rejestracji hooków w install().
| Kryterium | Własny moduł | Gotowa wtyczka |
|---|---|---|
| Czas do pierwszego wdrożenia | Zwykle 20–60 godzin pracy | 2–8 godzin konfiguracji |
| Kontrola zasięgu i override | Pełna, wiesz co modyfikuje | Ograniczona, kod po stronie wydawcy |
| Koszt utrzymania | Twoje godziny przy aktualizacjach core | Licencja roczna plus wsparcie wydawcy |
| Ryzyko konfliktu przy update | Zależne od liczby override | Zależne od tempa wydawcy |
Zleceniodawca zakłada, że hook wykonuje się raz na stronę. Ten sam kod w displayHeader działa przy każdym wejściu, a w displayOrderConfirmation tylko po złożeniu zamówienia — jeśli w displayHeader jest zapytanie do bazy, płacisz za nie na każdej stronie.
Jak wykryć: Wypisz hooki z metody install() modułu i porównaj je z tym, jak często faktycznie odpalają się w sklepie (karta produktu, koszyk, checkout, strona główna).
Jak naprawić: Przenieś logikę do możliwie najpóźniejszego hooka, który ma już potrzebny kontekst, i dodaj warunek sprawdzający kontroler (np. tylko na stronie produktu).
Modyfikacja plików core „na szybko” — dopisanie kilku linii w klasie lub kontrolerze, żeby moduł zadziałał.
Jak wykryć: Porównaj katalogi sklepu z czystą paczką instalacyjną tej samej wersji PrestaShop. Każda różnica poza /modules, /themes i /override to zmiana w core.
Jak naprawić: Cofnij zmianę i zrób to hookiem, własnym kontrolerem albo — jeśli naprawdę brak innej drogi — świadomym override'em zapisanym w dokumentacji projektu.
Dwa moduły nadpisujące tę samą klasę lub metodę w /override. Efektem jest błąd PHP, brak metody albo cicha utrata funkcji, którą trudno powiązać z instalacją modułu.
Jak wykryć: Sprawdź zawartość katalogu /override i listę modułów, które deklarują własne override'y; zwróć uwagę na daty plików — ostatnia instalacja zwykle nadpisała poprzednią.
Jak naprawić: Usuń jeden z konfliktujących override'ów, połącz logikę w jednym module albo zastąp override hookiem lub własnym zdarzeniem.
Poleganie na kolejności wykonania hooków bez rejestracji modułu i ustawienia pozycji. Moduł nie gwarantuje, że jego kod wykona się przed lub po innym module.
Jak wykryć: W panelu wejdź w Design > Positions i sprawdź pozycję modułu na liście wywołań dla danego hooka; przetestuj scenariusz po zmianie kolejności.
Jak naprawić: Zarejestruj moduł w hooku z jawną pozycją i wagą, a logikę uzależnioną od innych modułów oprzyj na własnym zdarzeniu zamiast na domyślnej kolejności.
Pobieranie danych w hooku, w którym te dane jeszcze nie istnieją w bazie. Typowy przykład: próba odczytania pełnego zamówienia w zdarzeniu, które odpala się przed jego zapisem.
Jak wykryć: W wybranym hooku wypisz dostępne obiekty (koszyk, zamówienie, klient). Jeśli obiekt jest pusty lub niespójny, kolejność zdarzeń jest zła.
Jak naprawić: Przenieś odczyt do późniejszego hooka (np. actionValidateOrder zamiast wcześniejszego zdarzenia koszyka) albo zaplanuj przetwarzanie asynchronicznie po zapisie danych.
Zapytania do bazy w pętli — pobranie listy produktów, a potem osobne zapytanie dla każdego z nich. Szeroki zasięg modułu zamienia jedno wejście na setki dodatkowych zapytań.
Jak wykryć: Włącz tryb debug w PrestaShop i porównaj liczbę zapytań na karcie produktu oraz stronie kategorii przed i po wyłączeniu modułu.
Jak naprawić: Zbierz identyfikatory i pobierz dane jednym zapytaniem z klauzulą IN lub przez DbQuery; wynik trzymaj w cache na czas renderu.
Module scope and important limitations w PrestaShop sprowadza się do jednego: moduł ma zasięg wyznaczony przez hooki, kontrolery, szablony, własne tabele i konfigurację — i nic poza tym nie dostanie za darmo. Granice są techniczne, nie formalne: kod działa z uprawnieniami procesu PHP, więc ogranicza go kolejność zdarzeń, dostępność danych i architektura sklepu. Zanim zlecisz przebudowę, sprawdź, czy wymaganie nie da się zamknąć hookiem albo własnym zdarzeniem, a override zostaw jako ostatnią opcję z pełną dokumentacją. Szeroki zasięg zawsze kosztuje wydajność — mierz liczbę zapytań i czas odpowiedzi, zamiast zgadywać.
W PHP zasięg modułu wyznaczają hooki, kontrolery, override'y, własne tabele i konfiguracja — kod działa w kontekście procesu serwera i ma dostęp do danych sklepu. W JavaScripcie na frontendzie mówimy o module ES, bundlerze i zakresie globalnym: kod widzi tylko to, co trafiło do przeglądarki, i nie sięgnie do bazy ani do plików sklepu. To dwa różne światy i mieszanie ich w jednym wymaganiu to najczęstsze źródło nieporozumień na etapie wyceny.
Nie. Każdy hook odpala się w konkretnym momencie cyklu życia strony i widzi tylko to, co zostało zapisane wcześniej. Jeśli próbujesz odczytać zamówienie w zdarzeniu, które wykonuje się przed jego utworzeniem, dostaniesz pusty obiekt albo błąd. Rozwiązaniem jest wybór późniejszego hooka albo przetworzenie danych po zapisie.
Nie zawsze, ale jest to najszerszy i najbardziej ryzykowny zasięg, bo nadpisuje logikę core w katalogu /override — a ta ginie przy aktualizacji sklepu. Override ma sens, gdy żaden hook nie daje dostępu do potrzebnego miejsca i gdy zmiana jest udokumentowana oraz wersjonowana. W większości przypadków taniej wychodzi dopisanie hooka lub własnego zdarzenia.
Najczęstsze przyczyny to konflikt override'ów, zmiana nazwy lub parametrów hooka w nowej wersji PrestaShop oraz zmiany w strukturze tabel. Drugi typowy powód to modyfikacje w plikach core, które aktualizacja nadpisała. Dlatego test aktualizacji wykonuje się zawsze na kopii sklepu, z włączonymi logami PHP.
Zmierz liczbę zapytań i czas odpowiedzi serwera dla karty produktu oraz strony kategorii — najpierw z włączonym modułem, potem z wyłączonym. Jeśli różnica jest wyraźna, sprawdź, czy moduł nie odpala zapytań w hooku widocznym na każdej stronie i czy nie pobiera danych w pętli. Pomiar wydajności frontendu warto uzupełnić metrykami z Core Web Vitals, ale samo TTFB pokazuje problem najszybciej.
Nie. Każda taka zmiana ginie przy aktualizacji, a jej debugowanie kosztuje zwykle więcej niż ponowne wdrożenie funkcji poprawną metodą. Jeśli brakuje hooka, dopisz własne zdarzenie albo użyj świadomego override'u zapisanego w repozytorium projektu. Wtedy przynajmniej wiadomo, co i dlaczego zostało zmienione.
Nie jest gwarantowana sama z siebie — zależy od tego, jak moduły są zarejestrowane w tabeli hooków i na jakiej pozycji stoją. Jeśli logika jednego modułu zależy od wyniku innego, trzeba to rozwiązać jawnie: pozycją w hooku, wagą albo własnym zdarzeniem. Poleganie na domyślnej kolejności kończy się błędami, które pojawiają się losowo po instalacji kolejnego modułu.
Jeśli nie wiesz, czy Twoje wymaganie zmieści się w module, czy będzie potrzebny override, opisz je nam — powiemy wprost, co jest wykonalne i ile to kosztuje. Przy budowie nowych modułów pomaga też uporządkowany start: zobacz, jak używać generatora modułów PrestaShop bez typowych błędów.