Przeniesienie strony WordPress ze środowiska deweloperskiego na domenę produkcyjną, zmiana nazwy marki czy wdrożenie certyfikatu SSL (przejście z HTTP na HTTPS) to rutynowe zadania każdego administratora i programisty. Na pierwszy rzut oka operacja wydaje się banalna: wystarczy wyeksportować bazę danych do pliku .sql, otworzyć go w edytorze kodu, uruchomić funkcję “Znajdź i zamień”, a następnie zaimportować plik z powrotem. Albo wykonać szybkie zapytanie SQL w phpMyAdminie.
Wykonanie takiego zabiegu na produkcyjnej bazie danych WordPressa kończy się natychmiastową awarią witryny. Znikają widgety w stopce i panelach bocznych, resetują się ustawienia kolorów i typografii w motywie, pola zaawansowane (ACF) zwracają puste wartości, a konfiguracje wtyczek e-commerce ulegają wyzerowaniu.
Przyczyną tego stanu rzeczy jest specyficzny sposób, w jaki silnik WordPress oraz wtyczki przechowują złożone struktury danych w relacyjnej bazie MySQL i MariaDB. Dokumentacja WordPressa ostrzega wprost: zwykłe wyszukiwanie i zamiana w całej bazie może uszkodzić serializację, bo część motywów i widgetów zapisuje adres razem z jego długością (Migrating WordPress, developer.wordpress.org). Zrozumienie mechanizmu serializacji PHP oraz opanowanie właściwych narzędzi, przede wszystkim interfejsu wiersza poleceń WP-CLI, to fundament bezpiecznego zarządzania stronami WordPress.
Czym są dane serializowane w bazie WordPress
Relacyjne bazy danych SQL są zaprojektowane do przechowywania danych skalarnych: liczb, krótkich ciągów znaków czy dat. WordPress często potrzebuje jednak zapisać w pojedynczym wierszu tabeli złożoną, wielowymiarową strukturę danych, na przykład tablicę zawierającą listę aktywnych widgetów, ich kolejność, przypisane ikony oraz parametry konfiguracyjne.
Zamiast tworzyć dziesiątki dodatkowych znormalizowanych tabel w bazie dla każdej wtyczki, twórcy WordPressa zdecydowali się na wykorzystanie natywnej funkcji języka PHP: serialize().
// Przykładowa tablica konfiguracyjna motywu w PHP
$theme_settings = array(
'site_name' => 'Mój Sklep WordPress',
'logo_url' => 'https://stara-domena.pl/logo.png',
'contact_mail' => '[email protected]'
);
// Wynik działania funkcji serialize($theme_settings)
// Zapisywany bezpośrednio w kolumnie option_value tabeli wp_options:
a:3:{s:9:"site_name";s:20:"Mój Sklep WordPress";s:8:"logo_url";s:32:"https://stara-domena.pl/logo.png";s:12:"contact_mail";s:21:"[email protected]";}Jak odczytać zserializowany ciąg znaków
Przyjrzyjmy się bliżej fragmentowi reprezentującemu adres URL logo:
s:32:"https://stara-domena.pl/logo.png";Każdy element w zserializowanym formacie PHP posiada ścisłą strukturę:
soznacza typ danych: string (ciąg znaków).32to deklarowana długość ciągu znaków (dokładna liczba bajtów)."https://stara-domena.pl/logo.png"to właściwa wartość zamknięta w cudzysłowach.
Kluczowym elementem całej układanki jest liczba 32. Silnik PHP podczas odczytywania danych z bazy wywołuje funkcję unserialize(). Parser PHP nie szuka zamykającego cudzysłowu na oślep, tylko odlicza dokładnie 32 bajty od wskazanego miejsca.
Dlaczego SQL REPLACE psuje dane serializowane
Wyobraźmy sobie, że migrujemy stronę na nową, dłuższą domenę: https://nowa-znacznie-dluzsza-domena-firmowa.pl. Nowy adres logo to: https://nowa-znacznie-dluzsza-domena-firmowa.pl/logo.png, który ma 56 znaków.
Jeśli wykonamy tradycyjne zapytanie SQL:
-- KRYTYCZNY BŁĄD: To zapytanie zniszczy serializację!
UPDATE wp_options
SET option_value = REPLACE(option_value, 'https://stara-domena.pl', 'https://nowa-znacznie-dluzsza-domena-firmowa.pl');W bazie danych powstanie następujący ciąg:
s:32:"https://nowa-znacznie-dluzsza-domena-firmowa.pl/logo.png";Co dzieje się w momencie uruchomienia strony przez użytkownika?
- WordPress pobiera wiersz z bazy danych i przekazuje go do funkcji
unserialize(). - Funkcja odczytuje nagłówek
s:32i oczekuje dokładnie 32 bajtów. - PHP odcina pierwsze 32 bajty nowego adresu, natrafiając wewnątrz stringa na przypadkowe litery zamiast wymaganego zamykającego cudzysłowu i średnika.
- Parser PHP rzuca błąd
PHP Notice: unserialize(): Error at offset...i zwraca wartośćfalse. - Motyw lub wtyczka, zamiast spodziewanej tablicy opcji, otrzymuje
false. - W efekcie WordPress uznaje, że dane nie istnieją, i przywraca domyślne ustawienia fabryczne motywu lub usuwa widgety.
Gdzie WordPress przechowuje adresy URL w bazie danych
Adresy URL w instalacji WordPress nie znajdują się w jednym miejscu. Są rozsiane po wielu tabelach systemowych oraz tabelach tworzonych przez zewnętrzne moduły:
graph TD
A["Baza Danych WordPress"] --> B["wp_options"]
A --> C["wp_posts"]
A --> D["wp_postmeta"]
A --> E["wp_comments / wp_commentmeta"]
A --> F["wp_usermeta"]
A --> G["Tabele wtyczek (WooCommerce, Formularze, SEO)"]
B --> B1["siteurl i home (Adresy główne)"]
B --> B2["sidebars_widgets (Serializowane)"]
B --> B3["theme_mods (Serializowane)"]
C --> C1["post_content (Linki, obrazki)"]
C --> C2["post_excerpt"]
C --> C3["guid (NIE zmieniać w opublikowanych!)"]
D --> D1["_elementor_data (JSON / Escaped)"]
D --> D2["_wp_attached_file (Ścieżki mediów)"]
D --> D3["Pola ACF (Serializowane)"]1. Tabela wp_options
To najważniejsza tabela konfiguracyjna. Zawiera dwa krytyczne rekordy decydujące o funkcjonowaniu strony:
siteurl: wskazuje, gdzie fizycznie znajdują się pliki WordPressa (ścieżka rdzenia).home: wskazuje adres główny witryny wpisywany przez użytkowników w przeglądarce.
Oprócz nich tabela przechowuje w postaci zserializowanej:
sidebars_widgets: układ widgetów w panelach bocznych i stopkach.theme_mods_[nazwa_motywu]: kolory, układ nagłówka, typografię i logo z konfiguratora motywów (Customizer).- Ustawienia wtyczek SEO (Rank Math, Yoast), wtyczek bezpieczeństwa oraz wtyczek cache.
2. Tabela wp_posts
Przechowuje treść wpisów, stron, produktów WooCommerce oraz elementów biblioteki mediów.
- Kolumna
post_content: zawiera bezwzględne odnośniki do innych podstron, osadzone tagi<img>, odnośniki do plików PDF oraz komentarze blokowe Gutenberga. - Kolumna
guid(Globally Unique Identifier): unikalny identyfikator wpisu. Ważna zasada: dokumentacja WordPressa mówi: “Nigdy, przenigdy nie zmieniaj zawartości kolumny GUID, w żadnych okolicznościach” (Migrating WordPress, developer.wordpress.org, tłumaczenie własne). Kolumnaguidnie powinna być zmieniana, ponieważ czytniki kanałów RSS używają jej do wykrywania nowych artykułów. Zmianaguidsprawi, że czytniki RSS potraktują wszystkie historyczne posty jako nowe i wyślą powtórne powiadomienia do subskrybentów.
3. Tabela wp_postmeta
Zawiera dodatkowe atrybuty wpisów i stron. To tutaj lądują zserializowane tablice zaawansowanych pól wtyczki Advanced Custom Fields (ACF), metadane załączników (_wp_attachment_metadata) oraz konfiguracje page builderów, takich jak Elementor czy Divi.
4. Tabele wp_usermeta i wp_comments
Zawiera adresy URL stron domowych autorów komentarzy oraz metadane profili użytkowników.
Zmiana domeny WordPress przez WP-CLI search-replace
Interfejs wiersza poleceń WordPressa (WP-CLI) to najszybsze, najbardziej niezawodne i w pełni zautomatyzowane narzędzie do migracji adresów URL. Działa bezpośrednio na serwerze przez połączenie SSH, operując na strukturach obiektowych PHP w pamięci operacyjnej.
Krok 1: Wykonanie kopii zapasowej (Backup)
Zanim wykonasz jakąkolwiek operację na bazie produkcyjnej, stwórz zrzut bazy do pliku SQL:
# Zrzut bazy z dodaniem instrukcji DROP TABLE
wp db export backup-przed-migracja-$(date +%Y%m%d_%H%M%S).sql --add-drop-tableJeśli baza ulegnie uszkodzeniu, w kilka sekund przywrócisz stan pierwotny:
wp db import backup-przed-migracja-*.sqlKrok 2: Uruchomienie przebiegu testowego (—dry-run)
Flaga --dry-run pozwala sprawdzić, ile wierszy i w których tabelach zostanie zmodyfikowanych, bez dokonywania żadnych zmian w bazie:
wp search-replace 'https://stara-domena.pl' 'https://nowa-domena.pl' --all-tables --dry-runWynikiem jest tabela z kolumnami Table, Column, Replacements i Type oraz linia podsumowania z łączną liczbą zamian. Kolumna Type pokazuje, czy dana kolumna była przetwarzana w SQL, czy w PHP. Jeśli liczba zamian jest zerowa, najczęściej stary adres różni się od zapisanego w bazie protokołem, prefiksem www albo końcowym ukośnikiem.
Krok 3: Wykonanie faktycznej zamiany produkcyjnej
Do wykonania ostatecznej zamiany zalecamy zestaw sprawdzonych flag optymalizacyjnych:
wp search-replace 'https://stara-domena.pl' 'https://nowa-domena.pl' \
--all-tables \
--precise \
--recurse-objects \
--skip-columns=guid \
--report-changed-onlySzczegółowe wyjaśnienie parametrów:
--all-tables: przeszukuje wszystkie tabele znajdujące się w bazie, łącznie z niestandardowymi tabelami wtyczek e-commerce, formularzy i logów.--precise: wymusza użycie PHP zamiast SQL dla wszystkich kolumn. Dokumentacja WP-CLI opisuje to jako wolniejsze, ale pewniejsze przy złożonych danych serializowanych.--recurse-objects: wchodzi rekurencyjnie w zserializowane obiekty. Jest domyślnie włączone, wyłącza się je przez--no-recurse-objects, więc wpisanie go jawnie tylko dokumentuje intencję.--skip-columns=guid: pomija kolumnęguidw tabeliwp_posts, chroniąc czytniki RSS przed duplikacją wpisów.--report-changed-only: wyświetla w podsumowaniu wyłącznie tabele, w których faktycznie dokonano zmian, ukrywając setki pustych wierszy.
Zmiana domeny w sieci WordPress Multisite
W instalacjach typu Multisite (sieć wielu witryn) tabele systemowe posiadają dedykowane prefiksy (np. wp_2_posts, wp_3_options), a informacje o domenach poszczególnych subwitryn znajdują się w tabelach wp_blogs i wp_site.
W takim środowisku należy użyć flagi --network, która obejmuje wszystkie tabele zarejestrowane w $wpdb dla całej sieci, albo --all-tables-with-prefix, która dodaje tabele z prefiksem niezarejestrowane w $wpdb:
wp search-replace 'https://stara-siec.pl' 'https://nowa-siec.pl' --network --all-tables-with-prefixDokumentacja WordPressa przyznaje, że przy zmianie domeny sieci Multisite tego kroku “nie da się jeszcze łatwo zautomatyzować” (Migrating WordPress, developer.wordpress.org, tłumaczenie własne). Po zamianie sprawdź ręcznie:
- tabele
wp_siteiwp_blogs, w których zapisane są domena i ścieżka sieci oraz każdej subwitryny, - opcje
home,siteurlifileupload_urlw tabeli opcji każdej witryny (wp_options,wp_2_optionsi kolejne), - przy przejściu z subdomen na podkatalogi lub odwrotnie: plik
.htaccessoraz stałąSUBDOMAIN_INSTALLwwp-config.php.
Jak wyeksportować bazę z nowymi adresami do pliku SQL
Jeśli przygotowujesz migrację bazy danych dla klienta na lokalnym środowisku i chcesz wygenerować gotowy plik SQL z podmienionymi domenami bez dotykania lokalnej bazy roboczej:
wp search-replace 'https://localhost/projekt' 'https://domena-klienta.pl' \
--all-tables \
--export=baza-gotowa-do-importu.sqlPrzejście z www na domenę bez www
Gdy zmienia się tylko prefiks, podmieniaj pełny adres razem z protokołem, żeby nie trafić w cudze ciągi znaków zawierające tę samą nazwę:
wp search-replace 'https://www.twojadomena.pl' 'https://twojadomena.pl' --all-tables --precise --skip-columns=guid --dry-runZmiana adresów URL wtyczką Better Search Replace
Jeżeli zarządzasz stroną na hostingu współdzielonym bez dostępu do SSH lub preferujesz obsługę z poziomu kokpitu WordPressa, najbezpieczniejszym rozwiązaniem jest wtyczka Better Search Replace rozwijana przez zespół WP Engine (dawniej Delicious Brains).
Krok po kroku w kokpicie WordPress:
1. Przejdź do: Wtyczki > Dodaj nową > Wyszukaj "Better Search Replace".
2. Zainstaluj i aktywuj wtyczkę.
3. Przejdź do: Narzędzia > Better Search Replace.
4. W polu "Search for" wprowadź stary adres URL (np. https://stara-domena.pl).
5. W polu "Replace with" wprowadź nowy adres URL (np. https://nowa-domena.pl).
6. Zaznacz wszystkie tabele na liście (użyj skrótu Ctrl+A na Windows lub Cmd+A na macOS).
7. Upewnij się, że opcja "Run as dry run?" (Uruchom na sucho) jest ZAZNACZONA.
8. Kliknij "Run Search/Replace" i przeanalizuj raport.
9. Odznacz opcję "Run as dry run?" i uruchom procedurę ponownie, aby zapisać zmiany.Błędy Better Search Replace i jak je naprawić
- Błąd 504 Gateway Timeout lub przekroczenie limitu czasu wykonywania skryptu (
max_execution_time): Przy dużych bazach serwer WWW może przerwać żądanie HTTP. W zakładce Settings wtyczki zmniejsz parametr Max Page Size. Domyślna wartość to 20000 wierszy na porcję, co widać w kodzie źródłowym wtyczki (class-bsr-admin.php); mniejsza porcja oznacza więcej krótszych żądań.
Jak zmienić siteurl i home w WordPressie
Dwie opcje z tabeli wp_options decydują, czy w ogóle zalogujesz się na stronę pod nowym adresem. Dokumentacja WordPressa (Changing The Site URL) rozróżnia je tak: home to “Adres witryny (URL)”, czyli adres wpisywany przez odwiedzających w przeglądarce, a siteurl to “Adres WordPressa (URL)”, czyli miejsce, w którym leżą pliki rdzenia. Oba pola w Ustawienia > Ogólne powinny zawierać https:// i nie powinny kończyć się ukośnikiem.
Dokumentacja opisuje kilka sposobów zmiany tych wartości. Każdy pasuje do innej sytuacji:
| Sposób | Kiedy go użyć | Na co uważać |
|---|---|---|
wp option update w WP-CLI | Masz SSH, kokpit nie działa | Zmienia tylko dwie opcje, resztę adresów poprawia wp search-replace |
Stałe WP_HOME i WP_SITEURL w wp-config.php | Trzeba szybko podnieść stronę | Wartości są wpisane na sztywno, pól w Ustawienia > Ogólne nie da się edytować |
update_option() w functions.php motywu | Masz tylko FTP | Kod trzeba usunąć zaraz po pierwszym załadowaniu kokpitu |
Stała RELOCATE | Strona przeniesiona do innego katalogu lub na inny serwer | Poprawia tylko adresy panelu, a pozostawiona w pliku jest niebezpieczna |
Edycja wp_options w phpMyAdmin | Masz tylko panel hostingu | Najpierw kopia bazy; prefiks tabel może nie być wp_ |
Zmiana siteurl i home przez WP-CLI
Dokumentacja podaje dwa polecenia, a po nich zamianę adresów w treści z pominięciem kolumny guid:
wp option update home 'https://nowa-domena.pl'
wp option update siteurl 'https://nowa-domena.pl'
wp search-replace 'https://stara-domena.pl' 'https://nowa-domena.pl' --skip-columns=guidZmiana adresu przez functions.php
Gdy masz dostęp tylko przez FTP, dokumentacja zaleca dopisanie do pliku functions.php aktywnego motywu, zaraz po otwierającym <?php, dwóch linii:
update_option( 'siteurl', 'https://nowa-domena.pl' );
update_option( 'home', 'https://nowa-domena.pl' );Po wgraniu pliku otwórz kilka razy ekran logowania lub kokpit, a potem usuń te linie. Dokumentacja pisze wprost: “Nie zostawiaj tego kodu w pliku functions.php” (Migrating WordPress, developer.wordpress.org, tłumaczenie własne). Kod wykonywałby się przy każdym żądaniu i nadpisywał opcje, które później zechcesz zmienić z poziomu kokpitu.
Stała RELOCATE po przeniesieniu katalogu
Stała define( 'RELOCATE', true ); dopisana w wp-config.php przed komentarzem That's all, stop editing! sprawia, że po zalogowaniu przez wp-login.php na nowym serwerze WordPress przyjmuje bieżący adres. Według dokumentacji poprawia ona tylko adresy panelu, nie resztę konfiguracji, a jej pozostawienie jest niebezpieczne: “Zawsze usuwaj linię RELOCATE z wp-config.php po zakończeniu pracy” (Migrating WordPress, developer.wordpress.org, tłumaczenie własne).
Transienty w przeniesionej bazie
Dokumentacja zwraca uwagę na transienty, czyli tymczasowe wartości zapisywane w wp_options. Mogą zawierać stare adresy, a ponieważ WordPress odtwarza je sam, w przeniesionej kopii bazy można je bezpiecznie usunąć. Z WP-CLI robi to wp transient delete --all, a dokumentacja podaje też zapytanie dla phpMyAdmina, poprzedzone kopią bazy:
DELETE FROM `wp_options` WHERE `option_name` LIKE '%\_transient\_%';Jak zmienić adresy URL, gdy kokpit WordPressa nie działa
W sytuacjach awaryjnych, gdy nie mamy dostępu do SSH, a kokpit WordPressa nie działa z powodu pętli przekierowań lub uszkodzonych plików, sprawdzonym narzędziem od ponad dekady pozostaje skrypt Search-Replace-DB (znany jako SRDB) stworzony przez agencję Interconnect/it.
Procedura użycia skryptu SRDB:
1. Pobierz oficjalne archiwum zip ze strony interconnectit.com.
2. Rozpakuj pliki i zmień nazwę folderu na unikalny, trudny do odgadnięcia ciąg (np. srdb-sec-8f7a9d/).
3. Prześlij folder na serwer przez FTP / SFTP do głównego katalogu instalacji WordPress (tam, gdzie znajduje się plik wp-config.php).
4. Otwórz w przeglądarce adres: https://twoja-domena.pl/srdb-sec-8f7a9d/.
5. Skrypt automatycznie odczyta dane logowania do bazy z pliku wp-config.php.
6. Wypełnij pola "replace" (stara wartość) i "with" (nowa wartość).
7. Kliknij "dry run", a po weryfikacji "live run".
8. KRYTYCZNE: Po zakończeniu kliknij czerwony przycisk "delete me", aby skrypt usunął się z serwera.[!CAUTION] Pozostawienie skryptu
Search-Replace-DBna działającym serwerze stanowi krytyczną lukę bezpieczeństwa. Każdy, kto odgadnie ścieżkę do skryptu, uzyskuje pełny dostęp do odczytu i modyfikacji bazy danych bez konieczności podawania hasła. Zawsze weryfikuj usunięcie folderu po zakończeniu prac!
Zmiana adresów URL w Elementorze, Divi i Gutenbergu
Nowoczesne page buildery oraz edytor blokowy Gutenberg wprowadzają dodatkowe warstwy kodowania danych, o których należy pamiętać podczas aktualizacji adresów URL.
graph LR
subgraph WP_CLI_Execution["Krok 1: Baza Danych"]
A["wp search-replace"] --> B["Tabele wp_posts, wp_postmeta, wp_options"]
end
subgraph Builder_Sync["Krok 2: Page Buildery"]
B --> C["Elementor: Narzędzia > Zmień URL"]
B --> D["Elementor: Regeneruj pliki CSS"]
end
subgraph Edge_Purge["Krok 3: Cache i Krawędź"]
C & D --> F["wp cache flush (Redis/Memcached)"]
F --> G["Purge CDN (Cloudflare)"]
end1. Adresy URL w danych JSON Elementora
Elementor przechowuje układ stron w polu meta _elementor_data w formacie JSON, w którym ukośniki w adresach URL są często poprzedzane znakiem ucieczki (ang. escaped slashes):
{\"url\":\"https:\/\/stara-domena.pl\/wp-content\/uploads\/2026\/08\/baner.jpg\"}Standardowe wyszukiwanie ciągu https://stara-domena.pl może nie dopasować ciągu z ukośnikami https:\/\/stara-domena.pl. Ponadto Elementor kompiluje reguły stylów do statycznych plików CSS w katalogu wp-content/uploads/elementor/css/.
Właściwa procedura po migracji strony na Elementorze:
- Wykonaj standardowe
wp search-replacew bazie. - Zaloguj się do kokpitu WordPress i przejdź do: Elementor > Narzędzia > Zastąp adres URL.
- Wpisz stary i nowy adres URL i kliknij Zastąp adres URL.
- W zakładce Ogólne kliknij przycisk Generuj pliki i dane od nowa (Regenerate Files & Data).
2. Adresy URL w blokach Gutenberga
Bloki Gutenberga przechowują atrybuty mediów bezpośrednio w komentarzach HTML wewnątrz post_content:
<!-- wp:image {"id":412,"sizeSlug":"full","linkDestination":"custom"} -->
<figure class="wp-block-image size-full"><a href="https://stara-domena.pl/oferta/"><img src="https://stara-domena.pl/wp-content/uploads/2026/08/grafika.png" alt="Oferta"/></a></figure>
<!-- /wp:image -->Zarówno wp search-replace, jak i Better Search Replace radzą sobie z tym bez problemu, pod warunkiem przeszukania kolumny post_content w tabeli wp_posts.
3. Adresy wpisane na sztywno w plikach motywu
Część motywów i wtyczek ma adresy zapisane bezpośrednio w plikach PHP, CSS lub JavaScript. Żadna zamiana w bazie ich nie obejmie, ale łatwo je znaleźć na serwerze:
grep -rn "stara-domena.pl" wp-content/themes/twoj-motyw/Zmiana domeny w sklepie WooCommerce
Podczas zmiany domeny w sklepie internetowym opartym o WooCommerce należy zwrócić szczególną uwagę na moduły komunikujące się z zewnętrznymi systemami płatności, kurierami oraz systemami ERP:
- Bramki płatności (Stripe, PayU, Przelewy24, PayPal):
- Większość bramek płatności rejestruje w swoich panelach deweloperskich adresy powiadomień zwrotnych (tzw. Webhooks / IPN). Jeśli zmieniasz domenę ze
stara.plnanowa.pl, powiadomienia o opłaconych zamówieniach będą trafiać na stary adres i generować błędy transakcji. - Po wykonaniu
wp search-replacenależy zalogować się do panelu każdej instytucji płatniczej i zaktualizować adres Webhooka (np.https://nowa.pl/?wc-api=WC_Gateway_PayU).
- Większość bramek płatności rejestruje w swoich panelach deweloperskich adresy powiadomień zwrotnych (tzw. Webhooks / IPN). Jeśli zmieniasz domenę ze
- Klucze i Webhooki WooCommerce REST API:
- W menu WooCommerce > Ustawienia > Zaawansowane > Webhooki sprawdź, czy adresy docelowe (Delivery URL) zostały zaktualizowane. Jeśli webhooki synchronizują stany magazynowe z systemem ERP (np. Subiekt GT, Comarch Optima), zaktualizuj adresy endpointów w oprogramowaniu integrującym.
- Pliki sesji i koszyki klientów:
- Tabela
wp_woocommerce_sessionsprzechowuje tymczasowe dane koszyków. Po zmianie domeny warto wyczyścić wygasłe sesje w menu WooCommerce > Status > Narzędzia > Wyczyść sesje klientów, aby uniknąć błędów tokenów sesyjnych po zmianie ciasteczek domenowych.
- Tabela
Search-replace na dużej bazie i klastrze MySQL
Przy bardzo dużych bazach jedno przejście wp search-replace po wszystkich tabelach trwa długo i przez cały ten czas zapisuje do tabel, z których korzysta działająca strona. Dokumentacja WP-CLI podaje dwa ograniczenia warte znajomości: tabele bez klucza głównego są pomijane, a opcje --regex i --log wyraźnie spowalniają pracę.
1. Jak podzielić search-replace na mniejsze części
Polecenie wp search-replace nie ma opcji --batch-size ani --limit; lista opcji w dokumentacji WP-CLI ich nie zawiera, a instrukcje, które je podają, nie zadziałają. Pracę dzieli się inaczej: podając nazwy tabel jako argumenty (dozwolone są symbole wieloznaczne) albo wykluczając tabele przez --skip-tables:
# Najpierw treści, potem metadane, osobnymi przebiegami
wp search-replace 'https://stara.pl' 'https://nowa.pl' wp_posts --precise --skip-columns=guid
wp search-replace 'https://stara.pl' 'https://nowa.pl' wp_postmeta --precise
# Wszystko poza dużą tabelą logów wtyczki
wp search-replace 'https://stara.pl' 'https://nowa.pl' --all-tables --skip-tables='wp_*_log' --precise --skip-columns=guidOpcja --include-columns zawęża zamianę do wskazanych kolumn, a przy --export liczbę wierszy w jednym poleceniu INSERT ustawia --export_insert_size (domyślnie 50).
2. Search-replace przy replikacji (Amazon Aurora, MySQL Galera)
Jeśli baza danych działa w architekturze Master-Slave lub klastrze Galera, masowa modyfikacja milionów rekordów wygeneruje potężny strumień danych w dzienniku binarnym (binlog). Może to doprowadzić do znacznego opóźnienia replikacji (Replication Lag) na węzłach odczytu.
Zalecana strategia dla środowisk High-Availability:
- Wykonanie operacji w oknie serwisowym o najniższym natężeniu ruchu.
- Tymczasowe odłączenie węzłów replikacyjnych na czas masowego zapisu.
- Wykorzystanie flagi
--exportw celu przygotowania przetworzonego pliku SQL na osobnej maszynie roboczej i zaimportowanie go w oknie serwisowym.
3. Tryb konserwacji na czas migracji
WP-CLI potrafi włączyć tryb konserwacji WordPressa, dzięki czemu odwiedzający nie zobaczą strony w połowie przestawionej na nowy adres:
wp maintenance-mode activate
wp search-replace 'https://stara.pl' 'https://nowa.pl' --all-tables --precise --skip-columns=guid
wp maintenance-mode deactivatePrzejście z HTTP na HTTPS i konfiguracja serwerów WWW
Jeżeli celem migracji nie jest zmiana nazwy domeny, lecz wdrożenie certyfikatu SSL i przejście z protokołu nieszyfrowanego na szyfrowany:
wp search-replace 'http://twojadomena.pl' 'https://twojadomena.pl' \
--all-tables \
--precise \
--skip-columns=guidDzięki temu eliminujesz problem tzw. Mixed Content (mieszana zawartość), w którym przeglądarka blokuje pobieranie skryptów, czcionek lub obrazków serwowanych po starym protokole http://.
Przekierowania 301 na poziomie serwera Nginx i Apache
Po zmianie domeny w bazie danych krytycznym krokiem z punktu widzenia SEO jest przekierowanie 100% ruchu ze starego adresu na nowy z kodem statusu HTTP 301 (Moved Permanently).
Konfiguracja Nginx (/etc/nginx/sites-available/stara-domena.conf):
server {
listen 80;
listen 443 ssl http2;
server_name stara-domena.pl www.stara-domena.pl;
ssl_certificate /etc/letsencrypt/live/stara-domena.pl/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/stara-domena.pl/privkey.pem;
return 301 https://nowa-domena.pl$request_uri;
}Konfiguracja Apache (.htaccess na starym serwerze):
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{HTTP_HOST} ^(?:www\.)?stara-domena\.pl$ [NC]
RewriteRule ^(.*)$ https://nowa-domena.pl/$1 [L,R=301]
</IfModule>Zmienne w pliku wp-config.php a wartości w bazie danych
Częstą praktyką na czas awarii jest wymuszenie adresów URL w pliku wp-config.php:
define('WP_HOME', 'https://nowa-domena.pl');
define('WP_SITEURL', 'https://nowa-domena.pl');Warto wiedzieć, jak te stałe działają w praktyce:
- Stałe zdefiniowane w
wp-config.phpnadpisują wartościsiteurlihomeodczytywane przez WordPressa, ale nie zmieniają wpisów w bazie danych. Dokumentacja nazywa to wprost “wpisaniem wartości na sztywno” i zaznacza, że nie jest to najlepsza poprawka. - Pól adresu w Ustawienia > Ogólne nie da się wtedy edytować.
- Wpisy w treści postów, załącznikach i widgetach nadal będą wskazywać na stary adres.
- Wymuszenie stałych w
wp-config.phptraktuj jako rozwiązanie tymczasowe; docelowo baza danych zawsze powinna być zaktualizowana poleceniemwp search-replace.
Checklista zmiany domeny WordPress
Przed przystąpieniem do prac warto postępować według ustrukturyzowanego planu działania:
| Etap | Zadanie | Narzędzie / Komenda |
|---|---|---|
| Przed migracją | Pełny zrzut bazy danych | wp db export backup-$(date +%s).sql --add-drop-table |
| Przed migracją | Kopia plików wp-content/uploads i .htaccess | rsync / tar -czf uploads.tar.gz |
| Przed migracją | Wyłączenie wtyczek cache i minifikacji | Kokpit WP / wp plugin deactivate |
| W trakcie | Test “na sucho” parametrów zamiany | wp search-replace 'old' 'new' --all-tables --dry-run |
| W trakcie | Faktyczna zamiana w bazie danych | wp search-replace 'old' 'new' --all-tables --precise --skip-columns=guid |
| W trakcie | Podmiana domen w builderach (Elementor) | Kokpit > Elementor > Narzędzia > Zastąp URL |
| Po migracji | Opróżnienie Object Cache i Transients | wp cache flush oraz wp transient delete --all |
| Po migracji | Przebudowa odnośników bezpośrednich (Permalinks) | wp rewrite flush --hard |
Skrypt Bash do synchronizacji bazy WordPress między środowiskami
W nowoczesnych procesach wytwórczych opartych na konteneryzacji Docker lub środowiskach deweloperskich (DDEV, Lando, LocalWP), ręczne wpisywanie poleceń bywa czasochłonne i podatne na błędy ludzkie. Standardem w zespołach inżynierskich jest przygotowanie uniwersalnego skryptu powłoki Bash, który automatyzuje pobieranie bazy produkcyjnej, import do środowiska lokalnego, podmianę domen oraz anonimizację wrażliwych danych klientów.
#!/usr/bin/env bash
# Skrypt automatycznej synchronizacji bazy danych: sync-db.sh
set -eo pipefail
PROD_HOST="twoj-serwer-produkcyjny.pl"
PROD_USER="deploy"
PROD_PATH="/var/www/html"
PROD_URL="https://twojafirma.pl"
LOCAL_URL="https://projekt.local"
BACKUP_DIR="./backups"
mkdir -p "${BACKUP_DIR}"
TIMESTAMP=$(date +"%Y%m%d_%H%M%S")
DUMP_FILE="${BACKUP_DIR}/dump_prod_${TIMESTAMP}.sql"
echo "==> 1/4 Pobieranie bazy produkcyjnej przez SSH..."
ssh "${PROD_USER}@${PROD_HOST}" "cd ${PROD_PATH} && wp db export - --add-drop-table" > "${DUMP_FILE}"
echo "==> 2/4 Import bazy do lokalnego środowiska..."
wp db import "${DUMP_FILE}"
echo "==> 3/4 Wykonywanie bezpiecznej zamiany domen z obsługą serializacji..."
wp search-replace "${PROD_URL}" "${LOCAL_URL}" \
--all-tables \
--precise \
--recurse-objects \
--skip-columns=guid \
--report-changed-only
echo "==> 4/4 Czyszczenie pamięci podręcznej i reset odnośników..."
wp cache flush
wp rewrite flush --hard
echo "==> Sukces! Środowisko lokalne jest w pełni zsynchronizowane pod adresem ${LOCAL_URL}."Weryfikacja poprawności serializacji po zakończeniu prac
Jeżeli chcesz mieć stuprocentową pewność, że żadne pole w bazie danych nie zostało uszkodzone podczas migracji, możesz uruchomić krótki jednolinijkowy skrypt PHP w WP-CLI, który weryfikuje integralność wszystkich zserializowanych rekordów w tabeli wp_options:
wp eval '
global $wpdb;
$options = $wpdb->get_results("SELECT option_name, option_value FROM {$wpdb->options} WHERE option_value LIKE \"a:%\" OR option_value LIKE \"O:%\"");
$broken = 0;
foreach ($options as $opt) {
if (is_serialized($opt->option_value) && @unserialize($opt->option_value) === false) {
echo "Uszkodzona opcja: " . $opt->option_name . PHP_EOL;
$broken++;
}
}
if ($broken === 0) {
echo "Wszystkie zserializowane opcje w tabeli wp_options są w 100% poprawne!" . PHP_EOL;
} else {
echo "Znaleziono " . $broken . " uszkodzonych rekordów!" . PHP_EOL;
}
'Błędy po zmianie domeny WordPress i ich naprawa
1. Pętla przekierowań po zmianie domeny (ERR_TOO_MANY_REDIRECTS)
Jeśli po zmianie domeny strona wpada w nieskończoną pętlę przekierowań:
- Sprawdź, czy adresy
siteurlihomew tabeliwp_optionsmają dokładnie taki sam protokół (https://) i prefiks (wwwvsnon-www), jak skonfigurowano na serwerze WWW lub w Cloudflare. - Sprawdź konfigurację SSL w Cloudflare (tryb SSL/TLS powinien być ustawiony na Full (Strict), a nie Flexible).
- Zresetuj plik
.htaccessdo domyślnej postaci WordPressa poleceniem:wp rewrite flush --hard
2. Zniknięcie stylów CSS i ikon po migracji
- Jeśli strona ładuje się jako surowy tekst bez stylów, najczęstszą przyczyną są arkusze i skrypty wciąż wskazujące stary adres, mieszana zawartość (Mixed Content) przy przejściu na HTTPS albo blokada zasobów przez politykę CORS.
- Uruchom konsolę deweloperską w przeglądarce (klawisz F12 > zakładka Console), aby zidentyfikować pliki ładowane ze starego adresu
http://.
3. Uszkodzone widgety lub pola ACF
- Jeśli zignorowano zasady serializacji i wykonano surowe zapytanie SQL
REPLACE, jedynym bezpiecznym wyjściem jest przywrócenie bazy z wykonanego wcześniej zrzutu SQL (wp db import backup.sql) i powtórzenie operacji za pomocąwp search-replace --precise.
4. Błąd Allowed memory size exhausted w WP-CLI
Podczas operacji search-replace na tabelach zawierających ogromne ilości danych tekstowych (np. rozbudowane tabele logów lub rewizji wpisów), proces PHP w terminalu może wyczerpać przydzielony limit pamięci RAM:
- Aby tymczasowo zwiększyć limit pamięci dla pojedynczego polecenia WP-CLI, uruchom komendę ze zmienną środowiskową PHP:
php -d memory_limit=1024M /usr/local/bin/wp search-replace 'https://stara.pl' 'https://nowa.pl' --all-tables - Warto również przed migracją usunąć zbędne rewizje wpisów oraz wygasłe transienty poleceniem:
wp transient delete --all && wp post delete $(wp post list --post_type='revision' --format=ids) --force
5. Niezgodność kodowania znaków i zestawu znaków (Collation)
Przy przenoszeniu zrzutu bazy danych na starszy lub inny serwer bazodanowy może się okazać, że docelowy serwer nie zna zestawu znaków (collation) użytego w zrzucie, na przykład utf8mb4_unicode_520_ci:
- Jeśli podczas importu pliku
.sqlpojawia się błąd#1273 - Unknown collation: 'utf8mb4_unicode_520_ci', zamień ten ciąg w pliku SQL przed importem:sed -i 's/utf8mb4_unicode_520_ci/utf8mb4_unicode_ci/g' backup.sql - Oba zestawy przechowują
utf8mb4, więc polskie znaki zostają zachowane; zmienia się tylko reguła sortowania i porównywania tekstu.
Podsumowanie
Prawidłowa aktualizacja adresów URL w bazie danych WordPress to proces wymagający świadomości działania mechanizmów języka PHP i relacyjnych baz danych. Stosowanie surowych zapytań SQL lub edycji plików w edytorach tekstowych to najprostsza droga do destabilizacji serwisu i utraty konfiguracji.
Narzędzie WP-CLI z flagami --all-tables --precise --skip-columns=guid, poprzedzone kopią zapasową i przebiegiem --dry-run, zachowuje dane serializowane i kolumnę guid w nienaruszonym stanie.
Planujesz kompleksową modernizację serwisu, zmianę architektury na headless lub migrację na platformy nowej generacji? Sprawdź nasze usługi w zakresie migracji z WordPress do Astro i Next.js oraz dedykowany audyt Core Web Vitals.







