WPML wystarczy do stron w wielu językach, ale strona na wiele rynków potrzebuje jeszcze dwóch rzeczy: rozpoznania kraju odwiedzającego i sposobu, by ta wiedza nie rozbiła page cache. Na stronie ZEN.COM, która ma 25 wersji językowych w WPML, kraj podaje Cloudflare, różnice per kraj obsługuje JavaScript w przeglądarce, a przekierowania na wersję rynku zaprojektowaliśmy jako Cloudflare Worker na edge. Poniżej opisujemy, jak te warstwy współpracują i czego pilnować, żeby nie zepsuć cache ani SEO.
Czym jest WPML i jak przechowuje wersje językowe?
Wtyczka WPML (WordPress Multilingual) zamienia jedną instalację WordPressa w stronę wielojęzyczną. Każda wersja językowa strony to osobny wpis w bazie z własną treścią, tytułem i adresem, a WPML łączy je w grupę tłumaczeń. Dzięki temu wersja polska może mieć inne sekcje, inne ceny i inne wezwania do działania niż angielska, a nie sam przetłumaczony tekst.
Adresy wersji zwykle dostają prefiks języka, np. /pl/ albo /ro/. Ten prefiks przyda się dalej, bo po nim przekierowanie rozpozna, że użytkownik już jest we właściwej wersji.
Twoja strona obsługuje kilka rynków? Projektujemy strony na WordPressie z WPML, routingiem po kraju na Cloudflare i cache, który nie rozpada się od geolokalizacji. Opisz, ile masz rynków i czym różnią się ich treści. Strony internetowe →
WPML czy multisite WordPress?
To częste pytanie przy stronie na kilka rynków, więc krótko:
| WPML | Multisite WordPress | |
|---|---|---|
| Struktura | Jedna strona, wiele wersji językowych | Sieć osobnych stron w jednej instalacji |
| Panel | Jeden, przełącznik języka | Osobny panel każdej strony, wspólny panel sieci |
| Tłumaczenia | Powiązane ze sobą wpisy | Brak powiązań bez dodatkowej wtyczki |
| Pasuje, gdy | Rynki dzielą szablony i większość treści | Rynki prowadzą osobne zespoły z inną ofertą |
W ZEN.COM wszystkie rynki korzystają z tego samego motywu i tych samych modułów, więc został WPML. Teksty wpisane w szablony tłumaczy osobno Lokalise, co opisujemy w artykule o integracji Lokalise z WordPressem.
Jak rozpoznać kraj odwiedzającego na WordPressie?
Jeśli strona stoi za Cloudflare, kraj masz za darmo. Przy włączonej geolokalizacji IP Cloudflare dopisuje do każdego żądania nagłówek CF-IPCountry z dwuliterowym kodem kraju, ustalonym z adresu IP. PHP może go odczytać, a Worker na edge dostaje to samo jako pole country.
Po stronie przeglądarki kraj da się odczytać z adresu /cdn-cgi/trace na tej samej domenie. Odpowiedź to kilka linii tekstu, a kraj jest w polu loc. Na ZEN.COM korzystamy z obu źródeł: nagłówek decyduje o wersji rynku, a odczyt w przeglądarce o drobnych różnicach na stronie.
Dlaczego geolokalizacja w PHP psuje page cache?
Page cache zapisuje gotowy HTML strony i serwuje go kolejnym osobom bez uruchamiania WordPressa, co przy dużym ruchu decyduje o czasie odpowiedzi serwera. ZEN.COM korzysta z cache na dwóch poziomach, w hostingu Kinsta i we wtyczce WP Rocket. Jeśli PHP wstawi w HTML link zależny od kraju, cache zapisze wersję dla pierwszego odwiedzającego i pokaże ją wszystkim kolejnym, aż do wygaśnięcia albo ręcznego wyczyszczenia. Klient z Polski może więc dostać link przygotowany dla Niemca, który był na stronie minutę wcześniej.
Są dwa wyjścia, gdy nie chcesz wyłączać cache:
- Jedna wersja HTML w cache i podmiana w przeglądarce. Strona ładuje się z cache, a skrypt po ustaleniu kraju zmienia to, co trzeba.
- Przekierowanie, zanim żądanie dotrze do WordPressa. Worker na Cloudflare kieruje użytkownika na właściwą wersję językową, a każda wersja ma własny, wspólny dla wszystkich cache.
Jak pokazać inne linki w każdym kraju bez rozbijania cache?
Przykład z ZEN.COM to rejestracja konta firmowego, gdzie dla wybranych krajów przycisk rejestracji ma prowadzić na inny adres niż dla reszty świata, niezależnie od tego, którą wersję językową ktoś akurat czyta. Wersja serwerowa, która sprawdza kraj w PHP, rozbiłaby cache, więc linki podmienia JavaScript.
- Strona przychodzi z cache z domyślnymi linkami.
- Skrypt pyta
/cdn-cgi/traceo kraj. - Jeśli kraj jest na liście, przepisuje linki rejestracji na właściwy adres i zachowuje parametry z oryginalnego linku.
- Gdy ktoś kliknie, zanim kraj jest znany, link czeka najwyżej 1,5 sekundy, a potem prowadzi tam, gdzie wskazuje w tej chwili.
Wersje językowe tych krajów dostają właściwy link jeszcze po stronie serwera, bo tam warunkiem jest język strony, a nie IP, więc cache się nie rozjeżdża. Jedna rzecz wyszła przy wdrożeniu: po zmianie skryptu trzeba wyczyścić cache w obu warstwach, inaczej część odwiedzających dostaje stary HTML bez skryptu. Po wyczyszczeniu nowy HTML pojawiał się z opóźnieniem kilkunastu sekund.
Jak przekierować użytkownika na wersję rynku na edge?
Przekierowanie po kraju w PHP odpada z tego samego powodu co linki, bo przy pełnym page cache WordPress nie widzi większości żądań, więc nie ma przy czym podjąć decyzji. Dlatego routing językowy zaprojektowaliśmy jako Cloudflare Worker, czyli skrypt uruchamiany na serwerach Cloudflare przed dotarciem żądania do hostingu. Reguły sprawdza po kolei:
- Adres ma już prefiks języka: nic nie robi. Ktoś z reklamy albo z udostępnionego linku dostaje dokładnie tę wersję, którą kliknął.
- Żądanie wysłał robot: przepuszcza bez przekierowania. Najpierw sprawdza znacznik zweryfikowanego bota z Cloudflare, potem nagłówek User-Agent, żeby Googlebot widział każdą wersję.
- Użytkownik sam wybrał język: ciasteczko ustawione przez przełącznik języka wygrywa z krajem.
- Kraj jest na mapie: przekierowanie 302 na prefiks przypisany do kraju. Mapa obejmuje 22 kraje, reszta zostaje na wersji domyślnej.
Odpowiedź z przekierowaniem ma nagłówek Cache-Control: no-store, żeby żadna warstwa nie zapamiętała przekierowania dla kraju pierwszego odwiedzającego. Gdy Worker zgłosi błąd, przepuszcza żądanie dalej bez zmian (fail-open), więc awaria routingu nie wyłącza strony.
Cały Worker ma 177 linii, a 37 testów w Vitest sprawdza każdą ścieżkę decyzji, w tym boty, ciasteczko i nieznane kraje, więc zmiana mapy krajów nie wymaga ręcznego klikania po stronie. Wdrożenie idzie przez GitHub Actions.
Co sprawdzić przed włączeniem routingu po kraju?
Lista ryzyk, którą przygotowaliśmy przed wdrożeniem, przyda się przy każdej stronie na WPML:
- Prefiksy w WPML. Worker musi kierować na dokładnie te prefiksy, które ustawiono w WPML. Literówka w mapie albo inny format adresu dla jednego języka to błąd 404 dla całego kraju.
- Stare przekierowania w JavaScripcie. Jeśli motyw już przekierowuje część krajów w przeglądarce, po włączeniu Workera użytkownik przejdzie przez dwa przekierowania, więc przed startem trzeba zdecydować, która warstwa zostaje.
- Ciasteczko wyboru języka. Worker je czyta, ale ustawia je przełącznik języka w motywie. Bez tej zmiany ręczny wybór języka nie zostanie zapamiętany.
- Wpisy bez tłumaczenia. Przekierowanie na
/pl/blog/wpistrafi w 404, jeśli wpis nie ma polskiej wersji. To obsługuje już WordPress i WPML, nie Worker. - Staging. Worker przypięty od razu do całej domeny działa na wszystkich użytkownikach, więc najpierw testuje się go na osobnej trasie albo domenie testowej.
Strona z wieloma rynkami jest też trudniejsza dla wyszukiwarek AI, bo te muszą ustalić, która wersja odpowiada na pytanie z danego kraju. Jeśli zależy Ci na tym, żeby ChatGPT i AI Overviews cytowały właściwą wersję, zajrzyj do oferty pozycjonowania w AI.
Planujesz stronę na kilka rynków albo Twój WordPress z WPML zwalnia po dodaniu geolokalizacji? Budujemy strony internetowe z routingiem na Cloudflare i cache, który obsługuje różnice między krajami. Więcej o pracy dla ZEN.COM znajdziesz w case study.
