Witryna oparta na WordPressie z Elementorem — wolne ładowanie, słabe Core Web Vitals, brak kontroli nad strukturą HTML i JSON-LD, rosnące trudności z obsługą wielojęzyczności. Brzmi znajomo. W przypadku trimsandfasteners.com, producenta i dystrybutora zamków błyskawicznych i pasmanteryjnych na rynki EN i PL, te problemy przekładały się bezpośrednio na słabą indeksację i ograniczone możliwości dalszego rozwoju serwisu.
Celem projektu taf-next było oddzielenie warstwy prezentacji od backendu CMS, przejęcie pełnej kontroli nad performancem i SEO, przy jednoczesnym zachowaniu całej treści zarządzanej w WordPressie przez redakcję. Poniżej opisuję dokładnie, co zbudowaliśmy i jakie decyzje techniczne podjęliśmy.
Architektura: Headless WordPress + Next.js App Router
WordPress na subdomenie wp.trimsandfasteners.com pełni wyłącznie rolę backendu — przechowuje treści, taksonomie, produkty i media. Dane pobierane są przez własne endpointy REST API (/wp-json/taf/v1/...) oraz standardowe WP REST API. Frontend zbudowany w Next.js 15 z App Routerem nie ma żadnego bezpośredniego kontaktu z bazą danych ani silnikiem PHP WordPress.
Model renderowania — SSG, ISR i Server Components
Wybór trybu renderowania per-route to jedna z kluczowych decyzji w projekcie Next.js. Tu zastosowaliśmy trzy podejścia w zależności od charakteru danych:
SSG (Static Site Generation) dla stron kategorii, podkategorii i wpisów blogowych. Strony generowane w całości przy buildzie, serwowane z CDN Vercel bez żadnego opóźnienia serwerowego — TTFB poniżej 100ms globalnie. Idealny tryb dla treści, które zmieniają się rzadko, a są odwiedzane najczęściej.
ISR (Incremental Static Regeneration) dla danych dynamicznych — automatyczne odświeżanie cache bez pełnego rebuildu. Kiedy redaktor zaktualizuje opis produktu w WordPressie, zmiana pojawi się na froncie po ustalonym interwale bez konieczności triggerowania nowego deploymentu.
Server Components jako domyślny model renderowania — JavaScript wysyłany do przeglądarki ograniczony wyłącznie do interaktywnych wysp: popupy produktowe, FAQ accordion, filtry. Reszta strony nie wysyła żadnego JS do klienta — to bezpośrednie przełożenie na niższe INP i szybszy Time to Interactive.
Wielojęzyczność z Polylang — locale-aware routing
Witryna działa w dwóch językach (EN/PL) z pełną segmentacją URL: / dla angielskiego i /pl/ dla polskiego. Implementacja wielojęzyczności w headless WordPress z Polylangiem ma jedną nieoczywistą pułapkę: Polylang przydziela różne Post ID dla tłumaczeń — angielska wersja posta i polska wersja to osobne rekordy w bazie, powiązane relacją.
Wymagało to osobnej obsługi mapowania między wersjami językowymi przy każdym zapytaniu do API. Zaimplementowano [locale] dynamic segment z middleware zarządzającym detekcją języka — przeglądarka bez preferencji językowej dostaje EN, request z nagłówkiem Accept-Language: pl jest automatycznie przekierowany do /pl/.
Interaktywny katalog produktów — Zipper Popup z in-memory cache
Kluczowa funkcja serwisu: kliknięcie zamka błyskawicznego w katalogu otwiera modal z pełnymi danymi technicznymi. To jednocześnie najważniejszy element interaktywny i największe wyzwanie wydajnościowe — modal musi się otwierać natychmiast, a dane muszą być poprawne językowo.
Rozwiązanie składa się z trzech warstw:
In-memory cache po stronie klienta z kluczem ${productId}-${locale} — pierwsze otwarcie popupu wykonuje fetch do API route, kolejne są natychmiastowe z pamięci. Cache rozróżnia wersje językowe, eliminując problem serwowania treści EN po przełączeniu języka na PL.
Locale-aware API route (/api/zipper/[id]?lang=pl) z parametrem lang przekazywanym do endpointu WP. Route działa jako proxy między frontendem a WordPress — ukrywa strukturę backendu, umożliwia cache'owanie odpowiedzi i dodaje warstwę transformacji danych.
PL Override Map — dla 13 produktów z kategorii nylon Polylang nie posiadał przetłumaczonych opisów w bazie WP. Zamiast ingerować w bazę danych klienta, stworzono plik src/lib/pl-zipper-overrides.ts z polskimi tłumaczeniami aplikowanymi po stronie Next.js API route. Zmiana izolowana całkowicie po stronie frontendu — backend WP nienaruszony.
FAQ Accordion i JSON-LD Schema — structured data, której Elementor nie dawał
W poprzedniej implementacji Elementor generował FAQ accordion jako widget, ale nie emitował żadnych structured data. To oznaczało, że Google crawlował pytania i odpowiedzi jako zwykły tekst, bez możliwości wyświetlenia ich jako rich result w SERP.
Po migracji na Next.js:
- Komponent
FaqAccordionz animowanym rozwijaniem odpowiedzi zbudowany jako Client Component zuseState. - Automatyczne generowanie schematu
FAQPagewedług specyfikacji Schema.org osadzanego jako<script type="application/ld+json">w initial HTML. - Pomimo że
FaqAccordionjest Client Component ('use client'), Next.js App Router wykonuje SSR również dla komponentów klienckich — JSON-LD jest obecny w source przy pierwszym załadowaniu strony, indeksowalny przez Googlebot bez JavaScript. - Ten sam pattern zastosowano w komponencie
PersonalizationContentna stronach personalizacji.
Przykładowa struktura emitowanego JSON-LD:
{
"@context": "https://schema.org",
"@type": "FAQPage",
"mainEntity": [
{
"@type": "Question",
"name": "What are coil (nylon) zippers...",
"acceptedAnswer": {
"@type": "Answer",
"text": "Coil zippers, also known as nylon zippers..."
}
}
]
}
Przekierowania 301 — konsolidacja link equity
Każda migracja URL-i to ryzyko utraty pozycji. Wszystkie historyczne URL-e z WordPressa zmigrowały do nowej struktury z zachowaniem wartości SEO:
Przekierowania zdefiniowane w next.config.ts — obsługiwane na poziomie CDN Vercel przed trafieniem requestu do aplikacji. Zero narzutu serwerowego, zero konfiguracji po stronie WordPress, zero ryzyka zepsucia przy aktualizacjach WP.
Strategia serwowania obrazów — świadoma decyzja architektoniczna
Obrazy produktowe serwowane są bezpośrednio z origin (wp.trimsandfasteners.com), z pominięciem pośredniej transformacji po stronie CDN. To nie było zaniedbanie — to świadoma decyzja.
WordPress dostarcza pliki już w odpowiednio skompresowanych formatach (WebP/JPEG), a dodatkowy processing layer na ścieżce krytycznej popupów wyłącznie wydłużałby czas odpowiedzi. Zipper Popup to interakcja wrażliwa na latency — użytkownik oczekuje natychmiastowego otwarcia modala. Eliminacja zbędnej warstwy pośredniej redukuje liczbę hopów na ścieżce obrazu i skraca czas odpowiedzi przy otwieraniu modali produktowych.
Skonfigurowano remotePatterns w next.config.ts obejmując cały host WP, co umożliwiło ładowanie ikon aplikacji i mediów z różnych lokalizacji na serwerze.
Wyniki po wdrożeniu
Po migracji z WordPress+Elementor na Next.js zanotowano znaczący wzrost indeksacji serwisu w Google Search Console. Strony wcześniej słabo indeksowalne — z powodu client-side renderingu Elementora i całkowitego braku structured data — zaczęły być poprawnie crawlowane i zaindeksowane. Przyczyniły się do tego przede wszystkim:
- Czysty, semantyczny HTML generowany przez React Server Components — Googlebot dostaje gotowy markup bez potrzeby uruchamiania JavaScript.
- JSON-LD structured data (FAQ schema) emitowane w initial HTML — wcześniej całkowicie nieobecne w implementacji Elementor.
- Poprawna struktura URL po wdrożeniu przekierowań 301 — konsolidacja link equity ze starych URL-i do nowych.
- Core Web Vitals w zielonych progach — LCP, CLS i INP w normie dzięki statycznemu generowaniu i eliminacji Elementor JS.
Wnioski — co daje headless dla serwisu B2B
trimsandfasteners.com to typowy serwis B2B w niszy produkcyjnej — katalog produktów, content marketing po angielsku i polsku, formularz zapytania. Dokładnie tam, gdzie klasyczny WordPress z Elementorem ma strukturalne ograniczenia, a headless Next.js daje największą przewagę:
- Structured data jako przewaga SEO. Elementor generuje widgety, nie schematy. Next.js daje pełną kontrolę nad każdym
<script type="application/ld+json">— FAQ, Product, BreadcrumbList — wszystkie w initial HTML, wszystkie indeksowalne. - Wielojęzyczność bez kompromisów. Locale-aware routing z next-intl + middleware to rozwiązanie, które skaluje się bez wtyczek premium. Polylang po stronie WP zarządza treścią, next-intl zarządza routingiem — każda warstwa robi swoje.
- SSG jako fundament wydajności. Strony kategorii zamków błyskawicznych generowane raz, serwowane dla każdego kolejnego użytkownika z CDN — TTFB niezależny od obciążenia serwera WP.
- Izolacja frontendu od backendu. PL Override Map to idealny przykład — problem z tłumaczeniami rozwiązany po stronie Next.js bez dotykania bazy WP. Klient zarządza treścią w znajomym panelu, front ewoluuje niezależnie.
Migracja dała klientowi to, czego Elementor nie był w stanie zaoferować: pełną kontrolę nad rendered output, mierzalne wyniki SEO i fundamenty pod dalszy rozwój — nowe landing pages, integracje i funkcje bez dotykania WordPressa.


