Skip to content

Wszystko o WordPressie, tworzeniu stron — i nie tylko

🔄 WordPress w podkatalogu: jak przenieść instalację z katalogu głównego i z powrotem

🔄 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ą:

Adres WordPress i adres witryny są zgodne

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

Adres WordPress różni się od adresu witryny

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ć /subdir → `` (прибрати підкаталог)

Замінити /subdir/wp-content/wp-content

Замінити /app/public/subdir/app/public

Katalog główny → podkatalog

Pozostawić bez zmian

Zamienić /wp-content/subdir/wp-content

Замінити /app/public/app/public/subdir

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:

Ustawienia migracji WP Migrate DB Pro z podkatalogu

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

Wynik migracji bez stylów i z uszkodzonymi obrazami

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:

1define( 'WP_SITEURL', 'http://wp-in-a-subdirectory.local/subdir' );
2define( '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ą:

Strona serwisowa z komunikatem o pracach technicznych

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)
Okno wyszukiwania i zamiany WP Migrate DB Pro do usunięcia podkatalogu

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:

Treść wpisu po wyczyszczeniu bazy z podkatalogu

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:

1rm 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:

Przenoszenie plików WordPress do katalogu głównego przez FTP

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

Witryna działa poprawnie po przeniesieniu do katalogu głównego

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):

Ustawienia migracji WP Migrate DB Pro z katalogu głównego do podkatalogu

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

Uszkodzone style i obrazy po migracji do podkatalogu

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)
Ustawienia selektywnej zamiany w celu dodania podkatalogu

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):

Wpis po selektywnej zamianie: obrazy z podkatalogiem

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:

Aktualizacja adresu WordPress z dodaniem podkatalogu

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:

Pliki WordPress przeniesione do podkatalogu subdir

Proszę przywrócić index.php WEWNĄTRZ podkatalogu do stanu fabrycznego, usunąć zaślepkę html i odkomentować wiersz z require:

1<?php
2define( 'WP_USE_THEMES', true );
3require( dirname( __FILE__ ) . '/wp-blog-header.php' );

Teraz panel administracyjny jest ponownie dostępny pod adresem http://wp-standard-install.local/subdir/wp-admin/:

Panel administracyjny WordPress działa po przeniesieniu do podkatalogu

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

Treść wpisu zweryfikowana: wszystkie obrazy na swoim miejscu

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
2define( 'WP_USE_THEMES', true );
3require( dirname( __FILE__ ) . '/subdir/wp-blog-header.php' );

Strona otwiera się pod głównym adresem URL, wszystkie zasoby są pobierane z podkatalogu:

Witryna działa poprawnie po przeniesieniu do 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. Polecenie wp search-replace '//oldsite.local/subdir' '//newsite.com' z flagą --dry-run najpierw 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-replace ró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ą.

Dyskusja o wsparciu migracji na GitHub w Delicious Brains

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.