Największy polski portal o sportach walki — MMA, boks, kickboxing, freak fights — działał na współdzielonym hostingu z WordPressem, Elementorem Pro i wtyczką Seraphinite Accelerator. Ponad 120 artykułów, archiwa kategorii i autorów, lata pracy redakcyjnej nagromadzone w CMS-ie. I wydajność, która nie nadążała za rosnącym ruchem.
Zadanie: zmigrować cały portal do Next.js bez żadnego downtime'u i bez regresji SEO. Poniżej opisuję dokładnie, co zrobiliśmy, jakie podejście przyjęliśmy i dlaczego — włącznie z technicznymi decyzjami, które sprawiają, że ten projekt różni się od typowej migracji headless.
Problem: Elementor + współdzielony hosting = sufit wydajnościowy
Seraphinite Accelerator z agresywnym cachowaniem robił co mógł, ale sufit był nieunikniony. Przy każdym żądaniu z niezakeszowanego IP serwer PHP musiał wygenerować stronę od zera — Elementor, baza danych, ładowanie motywu, wszystkie wtyczki. TTFB powyżej 600 ms dla zimnego cache'u był normą, nie wyjątkiem.
Dodatkowy problem: każda zmiana designu wymagała dostępu do panelu WP i znajomości Elementora. Brak kontroli nad frontendem oznaczał brak możliwości optymalizacji pod Core Web Vitals — Elementor generuje kilkadziesiąt kilobajtów własnego JavaScriptu i CSS-u, których nie można wyłączyć bez zepsucia layoutu.
Podejście — nie GraphQL API, ale static HTML export
Większość migracji headless WordPress wygląda tak: instalujemy WPGraphQL, budujemy Next.js pobierający dane przez GraphQL, deployujemy. To standardowe podejście.
W przypadku sportywalki.com.pl wybrałem inne rozwiązanie. Zamiast budować warstwę API GraphQL do istniejącego WP, wyeksportowałem pełny rendering każdej podstrony do statycznych plików JSON — Next.js serwuje je jako dynamiczne strony z własną warstwą transformacji HTML.
Dlaczego? Elementor generuje specyficzną strukturę HTML z własnymi klasami, inline stylami i interakcjami JS. Próba odtworzenia tego przez GraphQL wymagałaby parsowania surowych danych WP i ręcznego rekonstruowania layoutu każdej podstrony — przy 202 trasach to nierealne. Static HTML export zachowuje oryginalny rendering jeden do jednego, a transformacja Cheerio nadpisuje tylko to, co potrzebne.
Skala migracji — co zostało przeniesione
Kluczowy aspekt: wszystkie assety WordPress — CSS, JavaScript, obrazy — serwowane lokalnie z katalogu public/. Żadne żądanie przy renderowaniu strony nie trafia do serwera WP. WordPress jest całkowicie odizolowany od użytkownika końcowego.
Cheerio HTML Transform Pipeline — co robi i dlaczego jest konieczne
Wyeksportowany HTML z Elementora to nie gotowy, czysty kod. Zawiera martwy JavaScript, absolutne URL-e do starego hostingu i brakujące interakcje. Własny parser Cheerio przetwarza każdy wyeksportowany plik i wykonuje serię transformacji:
- Usuwanie martwego JavaScriptu — skrypty Elementora, jQuery i wszystkie inline skrypty niepotrzebne po odizolowaniu od WP.
- Normalizacja URL-i — wszystkie absolutne linki do starego hostingu zamieniane na relatywne lub nowe URL-e Vercel.
- Iniekcja sekcji FAQ — do każdego artykułu dodawana jest sekcja FAQ z 5 pytaniami wygenerowanymi przez AI. Łącznie 600 par pytanie/odpowiedź dla 120 artykułów.
- YouTube embeds — 10 filmów przypisanych do konkretnych artykułów osadzanych w odpowiednich miejscach, z
youtube-nocookie.comiloading="lazy". - Dynamiczny TOC — nagłówki H2/H3 wyekstrahowane, budowany spis treści dla każdego artykułu.
- Asset proxy fallback — trasy
/wp-assets/[...assetPath]jako fallback dla dynamicznych URL-i Elementora.
Elementor bez Elementora — interakcje w czystym TypeScript
Popupy scroll-triggered, off-canvas panele, FAQ akordeony — wszystkie działały przez JavaScript Elementora, który wymagał jQuery. Łącznie ponad 200 KB JavaScriptu zbędnego w nowej architekturze.
Każda interakcja odtworzona od zera w czystym TypeScript: popupy przez własny hook z IntersectionObserver, off-canvas panel jako komponent React z animacją CSS, FAQ akordeony jako prosty useState — kilkanaście linii kodu zamiast 200 KB zewnętrznej biblioteki.
Efekt: 200 KB mniej JavaScriptu po stronie użytkownika, bezpośrednie przełożenie na LCP i TTI.
Consent Mode v2 i GA4 — pełna implementacja od zera
Nowa implementacja to pełny Google Consent Mode v2 z granularnym systemem zgód w 5 kategoriach (niezbędne, funkcjonalne, personalizacja, analityczne, marketingowe) i synchroniczną inicjalizacją GA4 — brak okna wait_for_update, które przy błędnej implementacji powoduje nieprawidłowy stan zgód w raportach.
Każde zdarzenie zawiera kontekst strony: page_type (article/category/author), content_category (MMA/boks/kickboxing/freak), author. Dane w GA4 nie są płaskie — można filtrować po kategorii treści i zobaczyć, które sekcje portalu angażują użytkowników najgłębiej.
FAQ Schema — 600 par pytanie/odpowiedź wygenerowanych przez AI
Google Rich Results dla FAQ (FAQPage w JSON-LD) dają potencjalnie duże zwiększenie powierzchni w SERP. Przy 120 artykułach oznacza to ogromny potencjał, ale też ogromną ilość pracy — ręczne napisanie 5 pytań do każdego artykułu to 600 par.
Claude AI przeanalizował treść każdego z 120 artykułów i wygenerował 5 par pytanie/odpowiedź zgodnych z wytycznymi Google Rich Results — pytania w naturalnym języku polskim, odpowiedzi jako pełne zdania, bez powielania treści nagłówków. Cheerio pipeline wstrzykuje sekcję FAQ i odpowiadający JSON-LD do każdego artykułu automatycznie podczas buildowania.
SEO — zachowanie bez regresji
Migracja headless to ryzyko dla SEO. Błędne przekierowania, zaginięte meta tagi, zmieniona struktura URL — każdy z tych błędów może kosztować pozycje wypracowane przez lata.
- Wszystkie meta tagi, opisy, canonical URL, OG/Twitter cards — zachowane 1:1 z oryginalnego HTML.
- Robots.txt zachowany bez zmian — Next.js serwuje go ze statycznego pliku.
- Pełny zestaw XML sitemaps w standardzie Yoast SEO: post-sitemap, page-sitemap, category-sitemap, author-sitemap, sitemap_index.
- Brak regresji w Search Console po zmianie DNS — zero 404, zero zagubionych URL-i.
Wyniki wydajnościowe
Wnioski — kiedy static HTML export zamiast GraphQL
Podejście z static HTML export i Cheerio pipeline nie jest standardowe — i celowo. Jest optymalne gdy frontend jest zbudowany w Elementorze (rekonstrukcja layoutu przez GraphQL byłaby trudniejsza niż transformacja istniejącego HTML), gdy chcesz całkowicie odizolować WP od użytkownika, i gdy priorytetem jest brak regresji SEO — oryginalny HTML zachowuje wszystkie meta tagi i strukturę dokładnie tak jak były.
Dla nowych projektów, gdzie frontend jest budowany od zera, standardowe podejście WPGraphQL + Apollo Client jest prostsze i łatwiejsze w utrzymaniu. Ale dla migracji istniejącego serwisu z Elementorem — static HTML export bywa jedynym sensownym wyborem.
sportywalki.com.pl po migracji ma wydajność, której współdzielony hosting z WordPressem i Elementorem nigdy nie był w stanie zapewnić — i zachowany w 100% dorobek SEO wypracowany przez lata pracy redakcyjnej.


