
🔄 WordPress w podkatalogu: jak przenieść instalację z katalogu głównego i z powrotem
Znajoma sytuacja: podniósł Pan witrynę deweloperską, przygotował motyw, podłączył treść przez WP Migrate DB Pro i po wypchnięciu odkrył uszkodzone style, utracone obrazy i niedziałający panel wp-admin. Przyczyna prawie zawsze jest jedna: produkcja stoi w katalogu głównym, a dev w podkatalogu (lub odwrotnie), a prosta zamiana URL przez wyszukiwanie w bazie danych nie leczy tej różnicy.
Problem jest głębszy, niż się wydaje: w instalacji głównej WordPress wszystkie odnośniki (zarówno do stron, jak i do plików multimedialnych) używają tej samej domeny. W instalacji w podkatalogu odnośniki do treści pochodzą z adresu witryny, a odnośniki do zasobów (css, js, obrazy) z adresu WordPress. Zwykłe search-replace po bazie danych zastępuje wszystko jednakowo i psuje połowę ścieżek.
W tym poradniku omówiono dwie sprawdzone ścieżki migracji (tam i z powrotem) z konkretnymi ustawieniami wyszukiwania i zamiany, przygotowaniem pliku wp-config.php i właściwą kolejnością przenoszenia plików. Po lekturze albo ujednolici Pan schemat dev i produkcji, albo świadomie przeprowadzi migrację między różnymi typami instalacji bez uszkodzonego frontendu.
💡 Szybki przegląd:
- Proszę określić typ instalacji: czy „Adres WordPress" i „Adres witryny" w Ustawieniach → Ogólne są takie same
- Do migracji z podkatalogu do katalogu głównego: proszę zahardkodować WP_SITEURL w wp-config, wykonać zamianę
/subdir→/w bazie danych, przenieść pliki poziom wyżej, zaktualizować główny index.php - Do migracji z katalogu głównego do podkatalogu: proszę zamienić w bazie danych tylko ścieżki do
/wp-content, zaktualizować adres WordPress w ustawieniach, utworzyć podkatalog, skopiować index.php i .htaccess z powrotem do katalogu głównego - Po każdej migracji proszę wejść w Ustawienia → Bezpośrednie odnośniki i kliknąć „Zapisz": to przebuduje strukturę URL i wyczyści cache
Jak określić, gdzie jest zainstalowany WordPress
Jeśli instalował Pan WordPress ręcznie, z pewnością pamięta Pan, czy był to katalog główny domeny, czy podkatalog w rodzaju /wp lub /blog. Jeśli jednak witryna została odziedziczona po poprzednim deweloperze, wdrożona przez hosting jednym kliknięciem lub minęło kilka lat, szczegóły się zacierają.
Najszybszy sposób: proszę wejść do panelu administracyjnego WordPress, otworzyć Ustawienia → Ogólne i spojrzeć na pola „Adres WordPress (URL)" i „Adres witryny (URL)". Jeśli wartości są takie same, ma Pan do czynienia z instalacją główną:

Jeśli pola się różnią, WordPress jest zainstalowany w podkatalogu (w przykładzie poniżej jest to /subdir):

Dodatkowa oznaka instalacji w podkatalogu: podczas logowania do panelu administracyjnego URL zawiera podkatalog, na przykład example.com/wp/wp-admin/ zamiast example.com/wp-admin/.
Dlaczego nie można po prostu wziąć i przenieść
Sedno problemu tkwi w podwójnym systemie URL, którego WordPress używa podczas instalacji w podkatalogu. Przeanalizujmy to na konkretnych przykładach.
Załóżmy, że ma Pan instalację główną na example.com. Absolutnie wszystkie odnośniki w bazie danych, zarówno do wpisu /2025/about-page, jak i do obrazka /wp-content/uploads/photo.jpg, zaczynają się od //example.com. Zwykłe wyszukiwanie i zamiana //example.local → //example.com działa idealnie.
Teraz weźmy instalację w podkatalogu /wp. Odnośnik do tego samego wpisu wygląda jak //example.com/about-page (przez adres witryny), a odnośnik do tego samego obrazka jak //example.com/wp/wp-content/uploads/photo.jpg (przez adres WordPress z podkatalogiem). Prosta zamiana //example.local → //example.com uszkodzi pliki multimedialne: system będzie ich szukał bez /wp w ścieżce i otrzyma 404.
Poniższa tabela pokazuje, które grupy URL należy aktualizować w każdym kierunku migracji:
Kierunek | URL stron i postów | URL plików multimedialnych i zasobów | Ścieżki do plików w BD |
|---|---|---|---|
Podkatalog → katalog główny | Zamienić | Замінити | Замінити |
Katalog główny → podkatalog | Pozostawić bez zmian | Zamienić | Замінити |
Oprócz bazy danych trzeba fizycznie przenieść pliki i zaktualizować index.php w katalogu głównym, w przeciwnym razie WordPress nie znajdzie wp-blog-header.php. Dalej omówimy obie ścieżki krok po kroku.
Sposób 1: przeniesienie WordPressa z podkatalogu do katalogu głównego
To prostszy kierunek: usuwa Pan podkatalog ze ścieżek i wszystkie URL-e stają się „płaskie", jak w standardowej instalacji.
Krok 0: diagnostyka tego, co pójdzie nie tak
Przed interwencją warto zobaczyć skalę problemu na własne oczy. Na zrzucie ekranu poniżej pokazano ustawienia migracji z wp-in-a-subdirectory.local (WordPress w /subdir) na wp-standard-install.local (instalacja w katalogu głównym). Ustawienia WP Migrate DB Pro są standardowe, plus zamiana tytułu witryny dla demonstracji:

Rezultat jest zgodnie z przewidywaniami smutny: strony się otwierają, ale bez stylów i z uszkodzonymi obrazkami:

W HTML-u widać odnośniki do zasobów z martwą ścieżką /subdir, której na serwerze docelowym już nie ma. Próba wejścia do wp-admin powoduje przekierowanie na wp-standard-install.local/subdir/wp-login.php, a taki plik nie istnieje. Teraz to naprawimy.
Krok 1: przygotowanie
Przede wszystkim zabezpieczymy dostęp do panelu administracyjnego na czas migracji. Proszę dodać w wp-config.php stałe, które nadpiszą ustawienia z bazy danych, dzięki czemu WordPress będzie nadal wpuszczał Pana do panelu administracyjnego starą ścieżką z podkatalogiem, nawet po wyczyszczeniu bazy:
1 define( 'WP_SITEURL', 'http://wp-in-a-subdirectory.local/subdir' ); 2 define( 'WP_HOME', 'http://wp-in-a-subdirectory.local' );
Następnie proszę przełączyć witrynę w tryb konserwacji: proszę edytować plik index.php w publicznym katalogu głównym, zakomentować linię require( dirname( __FILE__ )... i po tagu zamykającym ?> wstawić html-zaślepkę z komunikatem o krótkiej przerwie technicznej. Odwiedzający zobaczą:

Pan/Pani w tym czasie nadal loguje się do panelu administracyjnego pod adresem http://wp-in-a-subdirectory.local/subdir/wp-admin/, stała WP_SITEURL działa.
Krok 2: wyszukiwanie i zamiana w bazie danych
Teraz czyścimy bazę. Proszę uruchomić wyszukiwanie i zamianę z następującymi parami (pokazano w interfejsie WP Migrate DB Pro, ale ta sama zasada działa z WP-CLI search-replace lub zapytaniami SQL przez phpMyAdmin):
//wp-in-a-subdirectory.local/subdir→//wp-in-a-subdirectory.local/app/public/subdir→/app/public(ścieżka do plików na serwerze)

Zaraz po migracji wygląd zewnętrzny nie ulegnie zmianie, wisi strona konserwacji, panel administracyjny działa przez wpisaną na sztywno stałą. Jeśli jednak zajrzeć do treści postów, obrazki na razie się nie ładują, a linki wewnętrzne „zgubiły" podkatalog, dokładnie o to nam chodziło na tym etapie:

Krok 3: fizyczne przeniesienie plików
Proszę usunąć (lub zakomentować) linie z WP_SITEURL i WP_HOME w pliku wp-config.php. Teraz panel administracyjny przestanie działać i od razu proszę przenieść pliki z podkatalogu poziom wyżej.
Przez SSH lub wiersz poleceń na serwerze robi się to trzema komendami:
1 rm index.php && mv subdir/* . && rm -rf subdir
Przez FTP lub menedżer plików hostingu proszę przeciągnąć całą zawartość podkatalogu do publicznego katalogu głównego z zastąpieniem pliku index.php:

Gotowe. Witryna otwiera się pod głównym adresem URL, obrazki i style są na swoim miejscu:

Ostatni szlif: proszę zalogować się do panelu administracyjnego (teraz jest to http://wp-in-a-subdirectory.local/wp-admin bez podkatalogu), otworzyć Ustawienia → Bezpośrednie odnośniki i kliknąć „Zapisz zmiany", nawet jeśli nic Pan/Pani nie zmieniał(a). WordPress przebuduje strukturę URL i wyczyści pamięć podręczną.
Sposób 2: przeniesienie WordPressa z katalogu głównego do podkatalogu
Wielu programistów uważa instalację WordPressa w podkatalogu za dobrą praktykę: pliki rdzenia nie zaśmiecają katalogu głównego, zarządzanie przez Git/Composer jest prostsze, a samą domenę można wykorzystać dla innych aplikacji. Jednak migracja istniejącej witryny do podkatalogu jest obiektywnie trudniejsza niż operacja odwrotna, ponieważ teraz część odnośników MUSI zachować podkatalog, a część nie.
Krok 0: diagnostyka
Ten sam punkt wyjścia: próbujemy standardowej migracji z instalacji w katalogu głównym wp-standard-install.local na instalację w podkatalogu wp-in-a-subdirectory.local (WordPress w /subdir):

Rezultat jest całkowicie oczekiwany: strony się otwierają, ale style i obrazy są uszkodzone, w ich ścieżkach brakuje /subdir:

W przeciwieństwie do pierwszego scenariusza odnośniki do postów i stron działają poprawnie, nie powinny one zawierać podkatalogu. Psują się właśnie zasoby (css, js, media), których ścieżki muszą teraz zawierać /subdir.
Krok 1: przygotowanie
Na tym etapie NIE definiujemy stałych WP_SITEURL i WP_HOME, nasze wyszukiwanie i zamiana nie dotkną tych wartości, a adres WordPressa zaktualizujemy ręcznie nieco później.
Stronę serwisową ustawiamy w ten sam sposób: komentujemy require(...) w index.php i dodajemy zaślepkę html. Odwiedzający widzą komunikat o pracach technicznych, a Pan/Pani nadal loguje się do panelu administracyjnego przez http://wp-standard-install.local/wp-admin/.
Krok 2: selektywna zamiana przez wyszukiwanie w bazie danych
Kluczowa różnica w porównaniu z pierwszym sposobem: zamieniamy TYLKO ścieżki do plików i zasobów, NIE dotykając adresów URL stron. W tym celu kierujemy zamianę według maski /wp-content:
//wp-standard-install.local/wp-content→//wp-standard-install.local/subdir/wp-content/app/public→/app/public/subdir(ścieżka na serwerze)

Po migracji sprawdzamy zawartość postów: odnośniki do innych stron witryny NIE zawierają podkatalogu (prawidłowo), a osadzone obrazy zawierają (również prawidłowo):

Krok 3: aktualizacja adresu WordPressa i przeniesienie plików
Teraz proszę przejść do Ustawienia → Ogólne i dopisać podkatalog na końcu „Adres WordPress (URL)", na przykład http://wp-standard-install.local/subdir. Natychmiast po zapisaniu panel administracyjny przestanie działać, ponieważ WordPress spróbuje znaleźć pliki w nowej ścieżce, a jeszcze ich tam nie ma:

Proszę utworzyć podkatalog subdir w publicznym katalogu głównym i przenieść do niego WSZYSTKIE pliki WordPressa. Następnie proszę skopiować index.php i .htaccess Z POWROTEM do katalogu głównego, aby strona serwisowa nadal była wyświetlana do czasu zakończenia prac:

Proszę przywrócić index.php WEWNĄTRZ podkatalogu do stanu fabrycznego, usunąć zaślepkę html i odkomentować wiersz z require:
1 <?php 2 define( 'WP_USE_THEMES', true ); 3 require( dirname( __FILE__ ) . '/wp-blog-header.php' );
Teraz panel administracyjny jest ponownie dostępny pod adresem http://wp-standard-install.local/subdir/wp-admin/:

Proszę sprawdzić, czy treść i obrazy są na swoim miejscu, a style się ładują:

Ostatni szlif: główny plik index.php
Pozostała aktualizacja pliku index.php w publicznym katalogu głównym. Proszę usunąć stronę serwisową i wpisać aktualną ścieżkę do wp-blog-header.php z uwzględnieniem podkatalogu:
1 <?php 2 define( 'WP_USE_THEMES', true ); 3 require( dirname( __FILE__ ) . '/subdir/wp-blog-header.php' );
Strona otwiera się pod głównym adresem URL, wszystkie zasoby są pobierane z podkatalogu:

Proszę ponownie przejść do Ustawienia → Bezpośrednie odnośniki i zapisać bez zmian, aby WordPress odświeżył strukturę URL.
Alternatywne narzędzia i oficjalna metoda
Opisane powyżej podejście z WP Migrate DB Pro jest wygodne, ale nie jedyne. Oto z czym jeszcze można pracować:
WP-CLI
search-replace. Poleceniewp search-replace '//oldsite.local/subdir' '//newsite.com'z flagą--dry-runnajpierw pokaże, ile wystąpień zostanie zastąpionych. W przypadku selektywnej zamiany (katalog główny → podkatalog) proszę zawęzić maskę:wp search-replace '//newsite.com/wp-content' '//newsite.com/subdir/wp-content'.Oficjalna metoda WordPress. Dokumentacja developer.wordpress.org opisuje procedurę „Giving WordPress Its Own Directory", ze szczegółowymi konfiguracjami dla Apache (.htaccess), nginx (server block) i IIS (web.config). Metoda nie wymaga wtyczek i działa na każdym hostingu.
Ręczny SQL. Jeśli zakres poprawek jest niewielki, można wykonać
UPDATE wp_posts SET post_content = REPLACE(post_content, '/subdir/', '/')bezpośrednio w phpMyAdmin, ale koniecznie z wcześniejszym backupem, ponieważ taka zamiana zniszczy dane zserializowane w wp_options i wp_postmeta.
Niezależnie od wybranego narzędzia zasada jest jedna: podczas migracji KATALOG GŁÓWNY → PODKATALOG proszę zastępować tylko /wp-content i ścieżki plików; podczas migracji PODKATALOG → KATALOG GŁÓWNY proszę zastępować wszystko, co odwołuje się do podkatalogu.
⁉️🤔 Często zadawane pytania
Czy do takiej migracji koniecznie trzeba używać WP Migrate DB Pro?
Nie. WP Migrate DB Pro daje po prostu wygodny interfejs do wyszukiwania i zamiany z obsługą zserializowanych danych PHP. Technicznie rzecz biorąc, można wykonać te same zamiany przez WP-CLI (polecenie
wp search-replacerównież poprawnie obsługuje serialized strings) lub użyć oficjalnej metody WordPress z ręcznym przeniesieniem plików i edycją index.php. Wtyczka oszczędza czas przy dużych i średnich projektach, gdzie jest wiele wystąpień.
Co zrobić, jeśli po migracji część obrazów nadal się nie ładuje?
Najczęstsza przyczyna: w bazie pozostały na sztywno wpisane adresy URL z bezwzględnymi ścieżkami starego serwera, które nie zostały objęte maską zamiany. Proszę sprawdzić treść postów przez phpMyAdmin:
SELECT ID, post_content FROM wp_posts WHERE post_content LIKE '%/subdir/%'(lub stara domena). Drugi kandydat to pamięć podręczna przeglądarki i CDN: proszę wyczyścić i sprawdzić w trybie incognito.
Czy po przeniesieniu trzeba aktualizować.htaccess?
Jeśli używają Państwo przyjaznych bezpośrednich odnośników, tak, ale WordPress robi to sam, gdy klikną Państwo „Zapisz" na stronie Ustawienia → Bezpośrednie odnośniki. Jeśli serwer nie ma praw do zapisu, WordPress pokaże gotową zawartość.htaccess, proszę skopiować ją ręcznie. Podczas migracji do podkatalogu proszę upewnić się, że główny.htaccess (nie ten wewnątrz podkatalogu) nie zawiera reguł, które kolidują z nową strukturą.
Czy można przeprowadzić migrację całkowicie bez przestoju?
Technicznie tak, jeśli użyją Państwo metody z przekierowaniami.htaccess (Method I z oficjalnej dokumentacji WordPress, „Bez zmiany URL"). W tym podejściu pliki są przenoszone do podkatalogu, a główny.htaccess płynnie kieruje wszystkie żądania do nowej lokalizacji. Odwiedzający nie zauważają przeprowadzki. Minus: pozostają Państwo na tej samej domenie, a adres URL strony formalnie się nie zmienia (podkatalog nie jest widoczny w pasku adresu).
Dlaczego WP Migrate DB Pro nie obsługuje od razu migracji między różnymi typami instalacji?
Deweloperzy Delicious Brains dyskutowali o tym na GitHubie przez prawie trzy lata. Źródło problemu: wtyczka stosuje JEDNĄ parę szukaj-zamień do CAŁEJ bazy, a do migracji między root a subdirectory potrzebne są RÓŻNE zamiany dla różnych grup URL (strony vs zasoby). Automatyczne określenie, który URL należy do której grupy, wymagałoby parsowania struktury treści, co wykracza poza prosty search-replace. Dlatego obecna rekomendacja brzmi: proszę doprowadzić strony do jednolitego schematu instalacji PRZED migracją.

Co w rezultacie: katalog główny czy podkatalog?
Wybór między instalacją WordPressa w katalogu głównym a w podkatalogu sprowadza się w istocie do jednego kompromisu. Instalacja w katalogu głównym jest prostsza: mniej ruchomych części, bezpośrednia zgodność między dev a production, żadnych niespodzianek z podwójnymi URL-ami. Instalacja w podkatalogu jest czystsza architektonicznie: pliki rdzenia są odizolowane, w katalogu głównym leży tylko index.php, łatwiej aktualizować WordPressa przez Git/Composer i bezpieczniej trzymać kilka aplikacji na jednej domenie.
Jeśli mają Państwo jeden serwis produkcyjny i jeden serwis deweloperski, proszę ujednolicić oba do jednego schematu (dowolnego) i zapomnieć o problemie. Jeśli pracują Państwo w zespole, gdzie część projektów historycznie jest w katalogu głównym, a część w podkatalogu, znają już Państwo dokładne maski wyszukiwania i zamiany dla każdego kierunku.
Główna zasada, którą warto dodać do zakładek: podczas migracji KATALOG GŁÓWNY → PODKATALOG proszę dotykać tylko /wp-content i ścieżek plikowych; podczas migracji PODKATALOG → KATALOG GŁÓWNY proszę zamieniać wszystko, co zawiera podkatalog. I zawsze, zawsze proszę klikać „Zapisz" w Bezpośrednich odnośnikach po przeprowadzce.



