
🔄 WordPress у підкаталозі: як перенести установку з кореня і назад
Знайома ситуація: ви підняли сайт розробки, зверстали тему, підключили контент через WP Migrate DB Pro, і після пушу виявили биті стилі, втрачені картинки і непрацюючий wp-admin. Причина майже завжди одна: production стоїть у корені, а dev, у підкаталозі (або навпаки), і пряма заміна URL пошуком у базі цю різницю не лікує.
Проблема глибша, ніж здається: у кореневій установці WordPress усі посилання (і на сторінки, і на медіафайли) використовують один і той самий домен. У підкаталоговій установці посилання на контент ідуть від адреси сайту, а посилання на ресурси (css, js, зображення), від адреси WordPress. Звичайний search-replace по базі заміняє все однаково і ламає половину шляхів.
У цьому посібнику розглянуто два перевірені маршрути міграції (туди і назад) із конкретними налаштуваннями пошуку-заміни, підготовкою wp-config.php і правильним порядком перенесення файлів. Після прочитання ви або приведете dev і production до єдиної схеми, або усвідомлено проведете міграцію між різнотипними установками без зламаного фронтенду.
💡 Швидкий огляд:
- Визначте тип установки: чи збігаються «Адреса WordPress» і «Адреса сайту» в Налаштуваннях → Загальні
- Для міграції з підкаталогу в корінь: захардкодьте WP_SITEURL у wp-config, виконайте заміну
/subdir→/у базі даних, перенесіть файли на рівень вище, оновіть кореневий index.php - Для міграції з кореня в підкаталог: замініть у БД лише шляхи до
/wp-content, оновіть адресу WordPress у налаштуваннях, створіть підкаталог, скопіюйте index.php і .htaccess назад у корінь - Після будь-якої міграції зайдіть у Налаштування → Постійні посилання і натисніть «Зберегти»: це перебудує структуру URL і скине кеш
Як визначити, де встановлено WordPress
Якщо ви ставили WordPress вручну, ви напевно пам'ятаєте, чи був це корінь домену чи підкаталог на кшталт /wp або /blog. Але якщо сайт успадкований від попереднього розробника, розгорнутий хостингом в один клік або минуло кілька років, деталі стираються.
Найшвидший спосіб: зайдіть в адмінку WordPress, відкрийте Налаштування → Загальні і подивіться на поля «Адреса WordPress (URL)» і «Адреса сайту (URL)». Якщо значення збігаються, перед вами коренева установка:

Якщо поля різняться, WordPress встановлений у підкаталог (у прикладі нижче це /subdir):

Додаткова ознака підкаталогової установки: під час входу в адмінку URL містить підкаталог, наприклад, example.com/wp/wp-admin/ замість example.com/wp-admin/.
Чому не можна просто взяти і перенести
Корінь проблеми полягає у подвійній системі URL, яку WordPress використовує під час встановлення в підкаталог. Розберемо на конкретних прикладах.
Припустимо, у вас коренева установка на example.com. Абсолютно всі посилання в базі даних, і на пост /2025/about-page, і на картинку /wp-content/uploads/photo.jpg, починаються з //example.com. Звичайний пошук-заміна //example.local → //example.com працює ідеально.
Тепер візьмемо установку в підкаталозі /wp. Посилання на той самий пост виглядає як //example.com/about-page (через адресу сайту), а посилання на ту саму картинку, //example.com/wp/wp-content/uploads/photo.jpg (через адресу WordPress із підкаталогом). Проста заміна //example.local → //example.com зламає медіафайли: система шукатиме їх без /wp у шляху і отримає 404.
Таблиця нижче показує, які групи URL потрібно оновлювати в кожному напрямку міграції:
Напрямок | URL сторінок і постів | URL медіафайлів і ресурсів | Шляхи до файлів у БД |
|---|---|---|---|
Підкаталог → корінь | Замінити | Замінити | Замінити |
Корінь → підкаталог | Залишити як є | Замінити | Замінити |
Крім бази даних, потрібно фізично перемістити файли і оновити index.php в корені, інакше WordPress не знайде wp-blog-header.php. Далі розберемо обидва маршрути покроково.
Спосіб 1: перенесення WordPress із підкаталогу в корінь
Це простіший напрямок: ви прибираєте підкаталог зі шляхів, і всі URL стають «пласкими», як у стандартній установці.
Крок 0: діагностика того, що піде не так
Перед втручанням корисно побачити масштаб проблеми на власні очі. На скриншоті нижче показано налаштування міграції з wp-in-a-subdirectory.local (WordPress у /subdir) на wp-standard-install.local (коренева установка). Налаштування WP Migrate DB Pro стандартні, плюс заміна заголовка сайту для демонстрації:

Результат очікувано сумний: сторінки відкриваються, але без стилів і з битими картинками:

У HTML видно посилання на ресурси з мертвим шляхом /subdir, якого на цільовому сервері вже немає. Спроба зайти в wp-admin спричиняє редирект на wp-standard-install.local/subdir/wp-login.php, а такого файлу не існує. Тепер полагодимо.
Крок 1: підготовка
Насамперед захистимо доступ до адмінки на час міграції. Додайте в wp-config.php константи, які перевизначать налаштування з бази даних, так WordPress продовжить пускати вас в адмінку за старим шляхом із підкаталогом, навіть після того як ми почистимо базу:
1 define( 'WP_SITEURL', 'http://wp-in-a-subdirectory.local/subdir' ); 2 define( 'WP_HOME', 'http://wp-in-a-subdirectory.local' );
Потім переведіть сайт у режим техобслуговування: відредагуйте index.php у публічному корені, закоментуйте рядок require( dirname( __FILE__ )... і після закривального тега ?> вставте html-заглушку з повідомленням про короткий простій. Відвідувачі побачать таке:

Ви при цьому продовжуєте заходити в адмінку за адресою http://wp-in-a-subdirectory.local/subdir/wp-admin/, константа WP_SITEURL працює.
Крок 2: пошук і заміна в базі даних
Тепер чистимо базу. Запустіть пошук-заміну з такими парами (показано в інтерфейсі WP Migrate DB Pro, але той самий принцип працює з WP-CLI search-replace або SQL-запитами через phpMyAdmin):
//wp-in-a-subdirectory.local/subdir→//wp-in-a-subdirectory.local/app/public/subdir→/app/public(шлях до файлів на сервері)

Одразу після міграції зовнішній вигляд не зміниться, висить сторінка обслуговування, адмінка працює через жорстко прописану константу. Але якщо заглянути у вміст постів, картинки поки не завантажуються, а внутрішні посилання «втратили» підкаталог, саме цього ми й домагалися на цьому етапі:

Крок 3: фізичне перенесення файлів
Видаліть (або закоментуйте) рядки з WP_SITEURL і WP_HOME у wp-config.php. Тепер адмінка відвалиться, і одразу переносьте файли з підкаталогу на рівень вище.
Через SSH або командний рядок на сервері це робиться в три команди:
1 rm index.php && mv subdir/* . && rm -rf subdir
Через FTP або файловий менеджер хостингу перетягніть весь вміст підкаталогу в публічний корінь із заміною index.php:

Готово. Сайт відкривається за кореневим URL, картинки і стилі на місці:

Останній штрих: зайдіть в адмінку (тепер це http://wp-in-a-subdirectory.local/wp-admin без підкаталогу), відкрийте Налаштування → Постійні посилання і натисніть «Зберегти зміни», навіть якщо нічого не змінювали. WordPress перебудує структуру URL і скине кеш.
Спосіб 2: перенесення WordPress із кореня в підкаталог
Багато розробників вважають встановлення WordPress в підкаталог хорошою практикою: файли ядра не захаращують корінь, спрощується керування через Git/Composer, а сам домен можна використовувати для інших застосунків. Але міграція наявного сайту в підкаталог об'єктивно складніша за зворотну, тому що тепер частина посилань ПОВИННА зберегти підкаталог, а частина, ні.
Крок 0: діагностика
Та сама початкова точка: пробуємо стандартну міграцію з кореневої установки wp-standard-install.local на підкаталогову wp-in-a-subdirectory.local (WordPress у /subdir):

Результат повністю очікуваний: сторінки відкриваються, але стилі і зображення б'ються, до них не дописано /subdir у шляху:

На відміну від першого сценарію, посилання на пости і сторінки працюють коректно, вони і не мають містити підкаталог. Ламаються саме ресурси (css, js, медіа), шляхи до яких тепер зобов'язані включати /subdir.
Крок 1: підготовка
Константи WP_SITEURL і WP_HOME на цьому етапі НЕ прописуємо, наш пошук-заміна не торкнеться цих значень, і ми оновимо адресу WordPress вручну трохи пізніше.
Сторінку обслуговування ставимо тим самим способом: коментуємо require(...) в index.php і додаємо html-заглушку. Відвідувачі бачать повідомлення про техобслуговування, а ви продовжуєте заходити в адмінку за http://wp-standard-install.local/wp-admin/.
Крок 2: вибіркова заміна пошуком у базі
Ключова відмінність від першого способу: ми заміняємо ЛИШЕ шляхи до файлів і ресурсів, НЕ чіпаючи URL сторінок. Для цього таргетуємо заміну за маскою /wp-content:
//wp-standard-install.local/wp-content→//wp-standard-install.local/subdir/wp-content/app/public→/app/public/subdir(шлях на сервері)

Після міграції перевіряємо вміст постів: посилання на інші сторінки сайту НЕ містять підкаталог (правильно), а вбудовані зображення містять (теж правильно):

Крок 3: оновлення адреси WordPress і перенесення файлів
Тепер зайдіть у Налаштування → Загальні і допишіть підкаталог у кінець «Адреса WordPress (URL)», наприклад, http://wp-standard-install.local/subdir. Одразу після збереження адмінка відвалиться, бо WordPress спробує знайти файли за новим шляхом, а їх там ще немає:

Створіть підкаталог subdir у публічному корені і перемістіть у нього ВСІ файли WordPress. Потім скопіюйте index.php і .htaccess НАЗАД у корінь, щоб сторінка обслуговування продовжувала висіти, поки ми завершуємо:

Відновіть index.php ВСЕРЕДИНІ підкаталогу до заводського стану, приберіть html-заглушку і розкоментуйте рядок з require:
1 <?php 2 define( 'WP_USE_THEMES', true ); 3 require( dirname( __FILE__ ) . '/wp-blog-header.php' );
Тепер адмінка знову доступна за адресою http://wp-standard-install.local/subdir/wp-admin/:

Перевірте контент, картинки на місці, стилі підвантажуються:

Фінальний штрих: кореневий index.php
Залишилося оновити index.php у публічному корені. Приберіть сторінку обслуговування і пропишіть актуальний шлях до wp-blog-header.php з урахуванням підкаталогу:
1 <?php 2 define( 'WP_USE_THEMES', true ); 3 require( dirname( __FILE__ ) . '/subdir/wp-blog-header.php' );
Сайт відкривається за кореневим URL, усі ресурси зібрані з підкаталогу:

Знову зайдіть у Налаштування → Постійні посилання і збережіть без змін, щоб WordPress освіжив структуру URL.
Альтернативні інструменти і офіційний метод
Описаний вище підхід із WP Migrate DB Pro зручний, але не єдиний. Ось із чим ще можна працювати:
WP-CLI
search-replace. Командаwp search-replace '//oldsite.local/subdir' '//newsite.com'із прапорцем--dry-runспершу покаже, скільки входжень буде замінено. Для вибіркової заміни (корінь → підкаталог) звузьте маску:wp search-replace '//newsite.com/wp-content' '//newsite.com/subdir/wp-content'.Офіційний метод WordPress. Документація developer.wordpress.org описує процедуру «Giving WordPress Its Own Directory», з детальними конфігураціями для Apache (.htaccess), nginx (server block) і IIS (web.config). Метод не потребує плагінів і працює на будь-якому хостингу.
Ручний SQL. Якщо обсяг правок невеликий, можна виконати
UPDATE wp_posts SET post_content = REPLACE(post_content, '/subdir/', '/')напряму в phpMyAdmin, але обов'язково з попереднім бекапом, серіалізовані дані у wp_options і wp_postmeta така заміна зруйнує.
Який би інструмент ви не обрали, правило одне: під час міграції КОРІНЬ → ПІДКАТАЛОГ заміняйте лише /wp-content і файлові шляхи; під час міграції ПІДКАТАЛОГ → КОРІНЬ заміняйте все, що посилається на підкаталог.
⁉️🤔 Часті запитання
Чи обов'язково використовувати WP Migrate DB Pro для такої міграції?
Ні. WP Migrate DB Pro просто дає зручний інтерфейс для пошуку-заміни з розумінням серіалізованих даних PHP. Технічно ви можете виконати ті самі заміни через WP-CLI (команда
wp search-replaceтеж коректно обробляє serialized strings) або використати офіційний метод WordPress із ручним перенесенням файлів і правкою index.php. Плагін економить час на великих і середніх проєктах, де багато входжень.
Що робити, якщо після міграції частина картинок все одно не завантажується?
Найчастіша причина: у базі залишилися жорстко прописані URL з абсолютними шляхами старого сервера, які не потрапили під маску заміни. Перевірте контент постів через phpMyAdmin:
SELECT ID, post_content FROM wp_posts WHERE post_content LIKE '%/subdir/%'(або старий домен). Другий кандидат, кеш браузера і CDN: скиньте і перевірте в режимі інкогніто.
Чи потрібно оновлювати.htaccess після перенесення?
Якщо ви використовуєте красиві постійні посилання, так, але WordPress робить це сам, коли ви натискаєте «Зберегти» на сторінці Налаштування → Постійні посилання. Якщо прав на запис у сервера немає, WordPress покаже готовий вміст.htaccess, скопіюйте його вручну. При міграції в підкаталог переконайтеся, що кореневий.htaccess (не той, що всередині підкаталогу) не містить правил, які конфліктують із новою структурою.
Чи можна виконати міграцію взагалі без даунтайму?
Технічно так, якщо використовувати метод із.htaccess-редиректами (Method I з офіційної документації WordPress, «Без зміни URL»). За такого підходу файли переносяться в підкаталог, а кореневий.htaccess безшовно спрямовує всі запити в нове розташування. Відвідувачі не помічають переїзду. Мінус: ви залишаєтеся на тому самому домені, і URL сайту формально не змінюється (підкаталог не видно в адресному рядку).
Чому WP Migrate DB Pro не підтримує міграцію між різнотипними установками з коробки?
Розробники Delicious Brains обговорювали це на GitHub майже три роки. Корінь проблеми: плагін застосовує ОДНУ пару пошук-заміна до ВСІЄЇ бази, а для міграції між root і subdirectory потрібні РІЗНІ заміни для різних груп URL (сторінки vs ресурси). Автоматичне визначення того, який саме URL до якої групи належить, потребувало б парсингу структури контенту, що виходить за межі простого search-replace. Тому поточна рекомендація: приведіть сайти до єдиної схеми встановлення ДО міграції.

Що в підсумку: корінь чи підкаталог?
Вибір між кореневою і підкаталоговою установкою WordPress, по суті, зводиться до одного компромісу. Коренева установка простіша: менше рухомих частин, пряма сумісність між dev і production, жодних сюрпризів із подвійними URL. Підкаталогова чистіша архітектурно: файли ядра ізольовані, в корені лежить лише index.php, легше оновлювати WordPress через Git/Composer і безпечніше тримати кілька застосунків на одному домені.
Якщо у вас один production-сайт і один dev-сайт, приведіть обидва до єдиної схеми (будь-якої) і забудьте про проблему. Якщо ви працюєте в команді, де частина проєктів історично в корені, а частина, в підкаталозі, тепер ви знаєте точні маски пошуку-заміни для кожного напрямку.
Головне правило, яке варто занести в закладки: під час міграції КОРІНЬ → ПІДКАТАЛОГ чіпайте лише /wp-content і файлові шляхи; під час міграції ПІДКАТАЛОГ → КОРІНЬ заміняйте все, що містить підкаталог. І завжди, завжди натискайте «Зберегти» в Постійних посиланнях після переїзду.



