Moje portfolio na luckadomena.pl działa w architekturze headless: WordPress pod adresem cms.luckadomena.pl służy wyłącznie do zarządzania treścią, a stronę, którą widzisz, generuje Next.js. Brzmi nowocześnie i takie jest, ale to nie jest rozwiązanie dla każdego projektu. W tym wpisie opisuję, kiedy headless WordPress ma sens, kiedy jest przerostem formy i jakie decyzje podjąłem przy własnej stronie.
Czym jest headless WordPress?
W klasycznym WordPressie jeden system robi wszystko: przechowuje treść, renderuje szablon PHP i wysyła gotowy HTML do przeglądarki. W podejściu headless „odcinamy głowę”, czyli warstwę prezentacji. WordPress zostaje panelem do pisania wpisów i udostępnia dane przez REST API (np. /wp-json/wp/v2/posts) albo GraphQL (wtyczka WPGraphQL). Frontend to osobna aplikacja, u mnie w Next.js, która te dane pobiera i sama decyduje, jak je wyświetlić.
Kiedy headless WordPress ma sens
- Chcesz pełnej kontroli nad frontendem. Żadnych ograniczeń motywu, żadnego page buildera – komponenty React, TypeScript i nowoczesne narzędzia.
- Zależy Ci na wydajności. Strony można wygenerować z góry jako statyczny HTML, który ładuje się błyskawicznie i nie obciąża serwera przy każdym wejściu.
- Bezpieczeństwo ma znaczenie. Panel WordPressa żyje na osobnej subdomenie, a publiczna strona to czyste pliki – nie ma tam PHP ani bazy danych, które można zaatakować.
- Treść trafia w kilka miejsc. Te same dane z API może wykorzystać strona, aplikacja mobilna czy newsletter.
- Redakcja zna WordPressa. Osoba pisząca treści dalej pracuje w znanym panelu, a deweloper ma swobodę po stronie frontendu.
Kiedy to przerost formy
- Klient chce sam układać strony w page builderze. Elementor czy Gutenberg z rozbudowanymi blokami tracą sens, bo frontend nie wie, jak je wyrenderować.
- Projekt opiera się na wtyczkach działających na froncie. Formularze, koszyk WooCommerce, wtyczki SEO generujące meta tagi – w headless każdą z tych rzeczy trzeba zbudować lub podpiąć samodzielnie.
- Mały budżet i brak dewelopera na stałe. Zamiast jednej aplikacji utrzymujesz dwie. Każda zmiana wyglądu to praca programisty, a nie kliknięcie w panelu.
- Prosta wizytówka firmy. Dobrze zoptymalizowany klasyczny WordPress z lekkim motywem w zupełności wystarczy.
Jak zrobiłem to w praktyce
Najważniejsza decyzja dotyczyła sposobu renderowania. Next.js daje kilka możliwości:
- SSG (Static Site Generation) – strony generowane raz, podczas budowania,
- SSR (Server-Side Rendering) – strona generowana przy każdym wejściu, wymaga serwera Node.js,
- ISR (Incremental Static Regeneration) – statyczne strony odświeżane w tle co określony czas, również wymaga serwera.
Portfolio stoi na zwykłym hostingu współdzielonym, bez Node.js. Wybrałem więc pełny statyczny eksport: w konfiguracji ustawiam output: 'export', a podczas buildu Next.js pobiera z WordPressa wszystkie wpisy i dla każdego generuje osobny plik HTML. Listę adresów dostarcza funkcja generateStaticParams:
export async function generateStaticParams() {
const posts = await getPosts()
return posts.map(post => ({ slug: post.slug }))
}
Dodatkowo włączyłem trailingSlash: true. Każda podstrona zapisuje się wtedy jako blog/nazwa-wpisu/index.html, a serwer Apache serwuje ją bez żadnych reguł przepisywania adresów.
Cena tego wyboru jest jasna: nowy wpis na blogu pojawia się na stronie dopiero po ponownym zbudowaniu i wgraniu plików. Przy portfolio, gdzie treść zmienia się rzadko, to rozsądny kompromis w zamian za szybkość, bezpieczeństwo i tani hosting.
Pułapki, na które trzeba się przygotować
SEO jest po Twojej stronie
Wtyczka SEO w WordPressie nie wygeneruje meta tagów na froncie w Next.js. Tytuły, opisy, Open Graph, mapę witryny i robots.txt trzeba zbudować samodzielnie – na szczęście App Router ma do tego wbudowane API (metadata, generateMetadata, sitemap.ts).
Pobieraj tylko potrzebne dane
REST API WordPressa domyślnie zwraca bardzo dużo pól. Parametr _fields pozwala ograniczyć odpowiedź do tego, czego naprawdę używasz, np. ?_fields=slug,title,excerpt,date. Mniej danych to szybszy build.
Hydracja i dane z przeglądarki
Strona generowana na etapie buildu nie ma dostępu do window ani localStorage. Jeśli zapisujesz w przeglądarce np. wybrany język albo ustawienia dostępności, odczyt musi być zrobiony tak, aby pierwszy render po stronie klienta zgadzał się z HTML-em z buildu. Ja użyłem do tego hooka useSyncExternalStore, który ma osobną wartość dla serwera i dla przeglądarki.
Obrazy
Wbudowana optymalizacja obrazów w Next.js działa na serwerze, więc przy statycznym eksporcie trzeba ją wyłączyć (images.unoptimized) i zadbać o rozmiary oraz formaty plików już w WordPressie.
Podsumowanie: krótka checklista decyzji
- Czy potrzebujesz pełnej kontroli nad frontendem i wydajności na najwyższym poziomie? Headless ma sens.
- Czy klient chce sam budować strony w page builderze i korzystać z wielu wtyczek frontowych? Zostań przy klasycznym WordPressie.
- Czy masz hosting z Node.js? Jeśli nie, statyczny eksport to dobre wyjście – pod warunkiem, że akceptujesz ponowny build przy każdej zmianie treści.
Headless WordPress to narzędzie, nie cel sam w sobie. W moim przypadku pozwolił połączyć wygodny panel do pisania z szybkim, nowoczesnym frontendem – i właśnie dlatego go wybrałem.