Wielojęzyczny WordPress z Polylang: praktyczny przewodnik implementacji
Jak wdrożyć wielojęzyczność w WordPress z Polylang: konfiguracja, SEO, hreflang, tłumaczenia automatyczne, integracja z ACF i WooCommerce. Realne pułapki, kod, ustawienia.
Wielojęzyczny WordPress z Polylang
Polylang to najlepsza wtyczka do wielojęzyczności w WordPress. Darmowa, open-source, aktywnie rozwijana. Ten post to kompletny przewodnik wdrożenia — instalacja, konfiguracja, SEO, integracje, realne problemy.
Dlaczego Polylang, nie WPML
Porównanie, które pokazuję klientom:
| Cecha | Polylang | WPML | |-------|----------|------| | Cena (1 strona, 1 rok) | $0 / $99 (Pro) | $39-159 | | Cena (1 strona, 5 lat) | $0 / $495 | $195-795 | | Custom post types | ✅ w darmowej | ✅ w płatnej | | ACF Pro integracja | ✅ w Pro | ✅ w pełnej | | WooCommerce integracja | ✅ w Pro | ✅ w pełnej | | Tłumaczenia automatyczne | DeepL (Pro) | Własny system | | Wydajność | Lżejsza | Cięższa (więcej query) | | Społeczność PL | Aktywna | Mniejsza |
Moja rekomendacja: Polylang. WPML jest 5-10x droższy w 5-letniej perspektywie i nie oferuje nic, czego Polylang nie ma. Wyjątek: gigantyczne portale z >50 custom post types, gdzie WPML ma bardziej dojrzałe integracje.
Instalacja i konfiguracja
# Wp-cli (szybsze niż przez GUI)
wp plugin install polylang --activate
wp plugin install polylang-pro --activate # opcjonalnie
Lub przez WP Admin → Plugins → Add New → "Polylang" → Install → Activate.
Ustawienia języków
Languages → Languages:
Języki: Polski (pl), English (en)
Kolejność URL: /pl/ dla polskiego (domyślny), /en/ dla angielskiego
Hide default language URL: OFF (lepsze dla SEO)
Language switcher: ON
Kluczowa decyzja: subdirectory (/pl/, /en/) vs subdomain
(pl.example.com, en.example.com).
Subdirectory wygrywa:
- Łatwiejsze SEO (cała domena buduje autorytet)
- Łatwiejsze certyfikaty SSL (jeden cert, nie dwa)
- Prostsze zarządzanie (jeden hosting, jedna konfiguracja)
Subdomain ma sens gdy:
- Różne zespoły obsługują różne wersje językowe
- Różne wymagania prawne (RODO, dane wrażliwe per kraj)
URL structure
W Settings → Permalinks:
Ustawienie: Post name (/%postname%/)
Polylang prefix: /pl/, /en/
Rezultat:
- Polska wersja:
example.com/pl/o-mnie/ - Angielska wersja:
example.com/en/about-me/
Każdy post/page/CPT ma osobny URL per język plus drugi URL w drugim języku. Polylang automatycznie je linkuje.
Tłumaczenie treści
Ręczne tłumaczenie (edytor WP)
Dla każdego postu Polylang dodaje meta box "Language" + przycisk "+" obok tytułu. Kliknij "+", wybierz język, napisz treść. Pola są zsynchronizowane (tytuł EN ↔ tytuł PL), ale treść jest niezależna.
Tłumaczenie automatyczne DeepL
Polylang Pro + DeepL API:
// wp-config.php
define('POLYLANG_DEEPL_API_KEY', 'twoj-klucz-deepl');
Workflow:
- Napisz post po polsku
- Kliknij "Translate with DeepL" w edytorze
- Polylang tłumaczy treść + excerpt + meta na EN
- Native speaker review + poprawki
DeepL Pro ($8/m dla 500k znaków) daje 80-90% jakości dla EN↔PL. Gorzej dla par NO/FI/DK. Zawsze review dla krytycznych stron (cennik, regulamin, polityka prywatności).
SEO: hreflang, canonical, sitemap
hreflang automatyczny
Polylang automatycznie dodaje hreflang w <head>:
<link rel="alternate" hreflang="pl" href="https://example.com/pl/o-mnie/" />
<link rel="alternate" hreflang="en" href="https://example.com/en/about-me/" />
<link rel="alternate" hreflang="x-default" href="https://example.com/pl/o-mnie/" />
To jest najlepsza praktyka SEO dla wielojęzycznych stron. Google używa hreflang do pokazywania prawidłowej wersji językowej w wynikach.
Weryfikacja:
# Sprawdź hreflang na stronie
curl -s https://example.com/pl/o-mnie/ | grep "hreflang"
Canonical URL
Polylang ustawia canonical URL do bieżącej wersji językowej (nie do wersji domyślnej). To jest poprawne SEO — każda wersja językowa ma własny canonical.
Sitemap (z Yoast / RankMath / SEOPress)
Wszystkie trzy popularne SEO pluginy mają integrację z Polylang. Sitemap zawiera wszystkie wersje językowe z prawidłowymi hreflang.
<!-- Przykład sitemap.xml -->
<url>
<loc>https://example.com/pl/o-mnie/</loc>
<xhtml:link rel="alternate" hreflang="pl" href="https://example.com/pl/o-mnie/" />
<xhtml:link rel="alternate" hreflang="en" href="https://example.com/en/about-me/" />
</url>
<url>
<loc>https://example.com/en/about-me/</loc>
<xhtml:link rel="alternate" hreflang="en" href="https://example.com/en/about-me/" />
<xhtml:link rel="alternate" hreflang="pl" href="https://example.com/pl/o-mnie/" />
</url>
Sprawdź czy SEO działa
# 1. hreflang w <head>
curl -s https://example.com/pl/o-mnie/ | grep hreflang
# 2. Canonical per język
curl -s https://example.com/pl/o-mnie/ | grep canonical
curl -s https://example.com/en/about-me/ | grep canonical
# 3. Search Console → International Targeting
# Sprawdź czy hreflang jest rozpoznawany (może trwać 2-4 tygodnie)
Integracja z ACF (custom fields)
Darmowy Polylang: custom fields ACF są per post, nie per język. To znaczy: wartość pola w EN musisz ręcznie wpisać w PL (lub odwrotnie).
Polylang Pro + ACF Pro rozwiązuje to: custom fields per język.
// functions.php — Polylang Pro + ACF Pro
add_filter('acf/settings/l10n', function () {
return true; // włącza tłumaczenia ACF
});
add_filter('acf/settings/l10n_textdomain', function () {
return 'your-textdomain';
});
Potem w ACF:
// Definicja pola z tłumaczeniem
acf_add_local_field_group([
'key' => 'group_clients',
'title' => 'Klienci',
'fields' => [
[
'key' => 'field_client_name',
'label' => 'Nazwa klienta',
'name' => 'client_name',
'type' => 'text',
],
],
'location' => [
[
[
'param' => 'post_type',
'operator' => '==',
'value' => 'projekt',
],
],
],
]);
Od teraz client_name ma osobne wartości per język. W pl.mdx masz
"Jan Kowalski", w en.mdx masz "John Smith".
Integracja z WooCommerce
Darmowy Polylang: produkty WooCommerce są wspólne (jeden produkt, dwie wersje językowe). Problem: cena, atrybuty, warianty są wspólne — co jest złe dla wielu sklepów.
Polylang Pro dla WooCommerce ($99/rok) daje:
- Ceny per język (np. 99 PLN / €22)
- Atrybuty per język (kolor "czerwony" / "red")
- Kategorie per język
- Shipping zones per język
Bez Pro: albo używasz multi-currency plugin (np. WOOCS), albo akceptujesz wspólną cenę (przeliczanie po kursie w display).
Language switcher w menu
Dodaj do Appearance → Menus:
Menu: Header
Items:
- Strona główna (PL) → /pl/
- O mnie (PL) → /pl/o-mnie/
- Blog (PL) → /pl/blog/
- [Polylang Language Switcher] ← dodaj jako "Language Switcher"
Language switcher pokazuje aktywny język + flagi (opcjonalnie). Możesz wybrać styl: dropdown, lista, flagi.
Moja rekomendacja: dropdown bez flag (flagi są problematyczne — np. polska strona nie ma jednej "oficjalnej" flagi, code-switch PL/EN z flagami jest niepoprawne politycznie dla niektórych rynków).
Hardening produkcyjny
1. Sprawdź czy nie ma duplikatów URL
Błąd: ta sama strona dostępna pod dwoma URL-ami
(/o-mnie/ i /pl/o-mnie/). Fix:
// functions.php — przekieruj non-prefixed URL do domyślnego języka
add_action('template_redirect', function () {
if (strpos($_SERVER['REQUEST_URI'], '/pl/') === 0 ||
strpos($_SERVER['REQUEST_URI'], '/en/') === 0) {
return; // OK
}
// Brak prefiksu — przekieruj do domyślnego
$default = pll_default_language();
wp_redirect(home_url("/{$default}" . $_SERVER['REQUEST_URI']), 301);
exit;
});
2. Cache per język
Jeśli używasz WP Super Cache lub W3 Total Cache, musisz wyłączyć
cache dla strony lub cache per język. Polylang ma integrację z
większością cache pluginów — włącz "Don't cache pages for visitors
with cookies" (Polylang ustawia cookie pll_language).
Dla pełnej kontroli (Cloudflare + APO) — patrz mój post o Cloudflare. Cache HTML per język to osobny URL, więc cache działa automatycznie.
3. Testowanie przed produkcją
# Test 1: Wszystkie wersje językowe są dostępne
for lang in pl en; do
echo "=== /${lang}/ ==="
curl -s -o /dev/null -w "%{http_code}\n" https://example.com/${lang}/
done
# Oczekiwane: 200, 200
# Test 2: hreflang w <head>
for lang in pl en; do
echo "=== hreflang /${lang}/ ==="
curl -s https://example.com/${lang}/ | grep hreflang | head -5
done
# Test 3: Canonical per język
for lang in pl en; do
echo "=== canonical /${lang}/ ==="
curl -s https://example.com/${lang}/ | grep canonical
done
# Test 4: Language switcher działa
curl -s https://example.com/pl/ | grep "pll-switcher" || echo "MISSING!"
Częste problemy
1. Po aktualizacji WP niektóre tłumaczenia znikają
Polylang trzyma tłumaczenia w wp_term_relationships. Po dużych
update'ach WP czasem czyści tę tabelę. Fix: backup bazy przed
aktualizacją, restore jeśli coś zniknie.
2. SEO plugin nie rozpoznaje wielojęzycznych URL
Yoast / RankMath wymaga ręcznej konfiguracji per język. Sprawdź w ustawieniach SEO czy "Permalink" jest prawidłowy per język (Polylang powinien to robić automatycznie, ale sprawdź ręcznie).
3. Sitemap.xml nie ma wszystkich wersji językowych
Włącz "Include all languages in sitemap" w ustawieniach SEO.
Sprawdź sitemap w /sitemap.xml — powinien mieć wszystkie wersje
z hreflang w <xhtml:link>.
4. ACF custom fields są puste po przełączeniu języka
Darmowy Polylang + ACF (bez Pro) → custom fields są wspólne. Wartość wpisana w PL jest widoczna w EN. Fix: Polylang Pro + ACF Pro, albo ręczne zarządzanie per język (przełącz język → wpisz inną wartość → zapisz).
Realne case studies
Case 1: Strona firmowa IT (PL + EN, 30 podstron)
Stack: Polylang (darmowy) + Elementor + ACF Wdrożenie: 2 dni Koszt: 2000 PLN SEO: Po 3 miesiącach ruch z EN keywords +120% (większość klientów zagranicznych)
Case 2: Sklep WooCommerce (PL + EN + DE, 500 produktów)
Stack: Polylang Pro + WooCommerce + ACF Pro Wdrożenie: 5 dni Koszt: 6500 PLN Funkcjonalność: Ceny per język (PLN, EUR, GBP), atrybuty per język, shipping zones per kraj
Case 3: Portal edukacyjny (PL + UA, 1000+ artykułów)
Stack: Polylang Pro + custom post types + DeepL Wdrożenie: 7 dni (w tym migracja z WPML) Koszt: 12000 PLN Efekt: tłumaczenie 1000 artykułów z PL na UA w 2 tygodnie (DeepL + native speaker review)
Co dalej
Jeśli potrzebujesz wdrożenia wielojęzycznego WordPress z Polylang — napisz do mnie. Realizacja: 2-5 dni, koszt od 2000 PLN.
Najczęściej zadawane pytania
Polylang Pro czy darmowy Polylang?
Czy mogę użyć Polylang z WPML import?
Jak działa SEO hreflang z Polylang?
Czy mogę tłumaczyć automatycznie przez DeepL / Google Translate?
Powiązane posty
- wordpress
WordPress REST API: praktyczne przypadki użycia dla custom post types
Jak używać WordPress REST API z custom post types w produkcji. Konkretne przykłady: headless CMS, mobile app backend, integracje z AI. Kod PHP + JS gotowy do użycia.
7 min - ngo
Najlepsze open-source'owe narzędzia do zarządzania NGO zdalnie w 2025
Kompletny przegląd open-source dla NGO: CiviCRM, Odoo, SuiteCRM, Kanboard, Nextcloud, Mattermost, Jitsi. Koszty, funkcje, porównania, realne wdrożenia z polskimi fundacjami.
7 min