Зараз 09:12, маркетинг вимагає новий плагін форми «прямо зараз», а WordPress спокійно відповідає: «Папка призначення вже існує.» Сайт все ще завантажується, але адмінка застрягла, встановлення не проходять, і кожний «застосунок» з інтернету радить видалити щось під wp-content, ніби це серветка.
Не робіть цього. wp-content — це місце, де ваш бізнес зберігає свої черевики. Якщо почнете тягати їх туди-сюди, решту дня будете вибачатися перед людьми з календарями.
Що насправді означає ця помилка (і чого вона не означає)
WordPress викидає «Папка призначення вже існує», коли намагається встановити або оновити плагін/тему і виявляє, що цільовий каталог з таким ім’ям уже присутній. Звучить очевидно, але ключова деталь така: WordPress не може з упевненістю визначити, чи існуючий каталог — це робоча інсталяція, часткова розпаковка, застарілий залишок після невдалого оновлення, чи щось, до чого він не повинен торкатися.
Тому WordPress грає змовчанням і відступає. Зазвичай це правильний вибір. Ваше завдання — визначити, з чим ви маєте справу:
- Легітимний існуючий плагін/тема (ви намагаєтесь «встановити» те, що вже є).
- Часткова інсталяція (каталог є, але файлів бракує; WordPress відмовляється перезаписувати).
- Проблеми з правами/власністю (WordPress не може видалити/замінити каталог, тож повідомляє, що він «існує», навіть якщо потрібно замінити).
- Невідповідність структури ZIP (архів розпаковується в ім’я папки, що конфліктує з наявною).
- Невідповідність абстракцій файлової системи (прямі записи vs FTP/SSH методи, тимчасові каталоги і ігри з umask).
Що це зазвичай не означає:
- «WordPress зламався» і потрібно перевстановити весь сайт.
- Причина видаляти випадкові папки під
wp-content, поки екран не зміниться. - Причина змінювати права на все до 777 (якщо тільки ваша модель загроз не «я люблю жити ризиковано»).
Цитата, варта стіни біля терміналу: «Надія — це не стратегія.» — Ген. Гордон Р. Салліван. Помилки WordPress часто спонукають до операцій надією. Не слідуйте їм.
Швидкий план діагностики (перевірте це передусім)
Якщо ви обмежені в часі, не блукайте. Робіть це як триаж інциденту.
Перш за все: підтвердьте, що саме WordPress намагається встановити
- Плагін чи тема? Ім’я/slug? З репозиторію чи завантажено ZIP?
- Це встановлення, оновлення чи спроба «повторної інсталяції»?
- Чи попереднє оновлення зазнало невдачі (білий екран, «режим обслуговування», застрягле повідомлення про оновлення)?
По-друге: подивіться каталог призначення
- Чи існує
wp-content/plugins/<slug>абоwp-content/themes/<slug>? - Це повне дерево чи напіврозпакований безлад?
- Чи є дивні сусідні об’єкти на кшталт
<slug>.tmp,<slug>_oldабо залишокupgrade?
По-третє: перевірте власність, права та шлях запису
- Чи може користувач веб-сервера записувати в
wp-contentіwp-content/upgrade? - Чи WordPress використовує прямий доступ до файлової системи або запитує FTP-облікові дані?
- Чи заповнений диск або вичерпані іноди?
По-четверте: перевірте логи (так, дійсно)
- Лог помилок веб-сервера: відмови в дозволах, помилки розпаковки, таймаути.
- Лог PHP-FPM: обмеження open_basedir, проблеми з тимчасовою директорією.
- Дебаг-лог WordPress: повідомлення про файлову систему, оновлення та розпаковку.
По-п’яте: вирішіть найменш ризиковий шлях
- Якщо каталог містить дійсну інсталяцію: робіть оновлення, а не встановлення; або використайте WP-CLI з
--forceобережно. - Якщо це часткова інсталяція: перейменуйте її, а потім встановіть чисто.
- Якщо це проблема з правами: виправте власність/ACL, потім повторіть оновлення.
- Якщо це структура ZIP: перепакуйте або виберіть інший ZIP.
Цікаві факти та історичний контекст (щоб дивні речі мали сенс)
Шість–десять коротких фактів, що пояснюють, чому ця помилка існує і чому вона досі дратує:
- WordPress спочатку розраховував на shared hosting, де «встановлення плагіна» означало «завантаження через FTP», а не атомарну заміну директорій.
- Система оновлення покладається на тимчасовий робочий простір (зазвичай
wp-content/upgrade) і послідовність копіювання/перейменування; коли ця послідовність переривається, залишки — часте явище. - ZIP-архіви не відзначаються стандартизованою добротою: багато вендорів упаковують ZIP з верхньою папкою, яка не відповідає slug плагіна, що спричиняє колізії або вкладені папки.
- На деяких хостах PHP працює під іншим користувачем, ніж вебсервер (або під пуловим користувачем), створюючи змішану власність, яка дає збої лише під час записів.
- Логіка «методу файлової системи» існує тому, що WordPress не може припустити доступ на запис; він пробує прямі записи, потім відкочується до FTP/SSH методів, коли блокується.
- Атомарна заміна директорій не завжди доступна на всіх файлових системах/моделях прав; WordPress діє обережно, щоб не видалити робочий код.
- Каталоги плагінів і тем стали майже пакетом менеджером задовго до того, як WordPress отримав надійну семантику відкатів/транзакцій.
- Застряглий «режим обслуговування» походить від одного файлу (
.maintenance), створеного під час оновлень; якщо очищення не відбулося, сайт може виглядати «вниз», хоча насправді все в порядку.
Сценарії відмов: реальні причини, чому папка «вже існує»
1) Плагін/тема вже встановлені, але ви знову «встановлюєте»
Найчастіше трапляється з завантаженням ZIP і пакунками вендорів. Папка існує, WordPress бачить її, відмовляється перезаписувати і виводить різке повідомлення. Правильний крок — або оновити з сторінки Плагінів, або видалити/перейменувати існуючий каталог після перевірки, що це безпечно.
2) Часткова розпаковка через попередню помилку
Таймаут під час розпаковки, заповнений диск, убитий PHP-воркер, таймаут зворотного проксі або інженер, який перезапустив PHP-FPM «щоб почистити». В результаті отримуєте каталог, який є, але неповний. WordPress не може вирішити, чи його видаляти, тому зупиняється.
3) Невідповідність прав/власності
Каталог існує і його треба замінити, але веб-процес не може його видалити. WordPress повідомляє «вже існує», бо спроба очищення зазнала невдачі і продовжувати небезпечно. Шукайтe Permission denied в логах — там і правда буде підказка.
4) SELinux/AppArmor або жорсткі політики
На захищених системах права можуть виглядати правильно, але обов’язковий контроль доступу блокує записи. Це проявляється як помилки доступу навіть при «правильних» бітових режимах.
5) Проблеми open_basedir або тимчасової директорії
Розпаковка часто використовує тимчасову директорію; якщо PHP не може записати туди, отримуєте напівзавершені встановлення і заплутані помилки. WordPress тоді зіштовхується з частково створеною папкою призначення і зупиняється.
6) Дивна поведінка файлової системи (NFS, CIFS, об’єктні томи)
Мережеві файлові системи можуть мати кешування, затримку видимості або семантику перейменування, що відрізняється від локальних ext4/XFS. Заміна директорії може провалюватися так, що виглядає як «існує», але насправді означає «перейменування не поширилося».
7) Інструменти деплойменту, що конфліктують з WordPress
Якщо ви деплоїте код через Git, rsync або контейнери, і WordPress намагається самовносити зміни, у вас два джерела істини, що змагаються. Помилка — це WordPress, який гавкає на зачинені двері.
Жарт №1: Оновлення WordPress — як офісні крісла: зазвичай все нормально, доки хтось не відкидається з упевненістю.
Практичні завдання: команди, виводи та які рішення ви приймаєте
Це реальні завдання, які ви можете виконати на Linux-хості. Кожне включає: команду, що типовий вивід означає, і як ви вирішуєте.
Завдання 1: Підтвердити наявність цільового каталогу
cr0x@server:~$ sudo ls -ld /var/www/html/wp-content/plugins/contact-form-7
drwxr-xr-x 5 root root 4096 Dec 27 08:41 /var/www/html/wp-content/plugins/contact-form-7
Значення: Каталог плагіна існує і належить root:root. Це підозріло на типовому WordPress-сервері, де веб-процес потребує прав на запис.
Рішення: Поки не видаляйте. Перевірте, чи це дійсна інсталяція і чи неправильно вказана власність.
Завдання 2: Перевірити, чи це часткова інсталяція (кількість файлів і очікувані файли)
cr0x@server:~$ sudo find /var/www/html/wp-content/plugins/contact-form-7 -maxdepth 2 -type f | wc -l
3
Значення: Лише 3 файли — це ймовірно неповна інсталяція для справжнього плагіна. Здоровий плагін зазвичай має десятки файлів.
Рішення: Розглядайте як часткову розпаковку. Плануйте перейменувати і перевстановити.
Завдання 3: Виявити користувача веб-сервера (Apache)
cr0x@server:~$ ps -eo user,comm | egrep 'apache2|httpd' | head
www-data apache2
www-data apache2
www-data apache2
Значення: Процеси Apache працюють як www-data.
Рішення: Каталоги плагінів/тем зазвичай повинні бути записувані www-data (або керуватися через деплоймент, але тоді WordPress не повинен оновлюватися самостійно).
Завдання 4: Виявити користувача пулу PHP-FPM (Nginx + PHP-FPM)
cr0x@server:~$ sudo grep -R "^\s*user\s*=" /etc/php/*/fpm/pool.d/www.conf | head -n 1
user = www-data
Значення: PHP виконується як www-data також (добре; менше несподіванок з мішаною власністю).
Рішення: Якщо ви все ще маєте каталоги, що належать root, вони ймовірно створені вручну (розпаковка як root, rsync як root або крок CI, що пішов не так).
Завдання 5: Перевірити записуваність wp-content від імені веб-користувача
cr0x@server:~$ sudo -u www-data bash -lc 'touch /var/www/html/wp-content/.write-test && echo ok && rm /var/www/html/wp-content/.write-test'
ok
Значення: Веб-користувач може записувати в wp-content принаймні на верхньому рівні.
Рішення: Помилка ймовірніше в конкретному підкаталозі (plugins/themes/upgrade) або через власність/ACL на тому каталозі.
Завдання 6: Перевірити здоров’я тимчасового каталогу upgrade
cr0x@server:~$ sudo -u www-data bash -lc 'mkdir -p /var/www/html/wp-content/upgrade && touch /var/www/html/wp-content/upgrade/.upgrade-test && ls -la /var/www/html/wp-content/upgrade | head'
total 8
drwxr-xr-x 2 www-data www-data 4096 Dec 27 09:01 .
drwxr-xr-x 10 www-data www-data 4096 Dec 27 09:01 ..
-rw-r--r-- 1 www-data www-data 0 Dec 27 09:01 .upgrade-test
Значення: WordPress може підготовлювати файли для оновлення.
Рішення: Якщо оновлення все ще не проходять, фокусуйтеся на власності каталогу призначення, місці на диску або структурі ZIP.
Завдання 7: Перевірити вільне місце на диску та іноди
cr0x@server:~$ df -h /var/www/html
Filesystem Size Used Avail Use% Mounted on
/dev/sda1 40G 39G 600M 99% /
Значення: Ви фактично без вільного місця. Розпаковка може обірватися посередині, залишивши каталог призначення.
Рішення: Спочатку звільніть місце. Потім очистіть часткові каталоги і повторіть спробу. Якщо ігнорувати це, ви будете генерувати напівінсталяції постійно.
cr0x@server:~$ df -i /var/www/html
Filesystem Inodes IUsed IFree IUse% Mounted on
/dev/sda1 2621440 2619000 2440 100% /
Значення: Іноди вичерпані. Це може ламати інсталяції навіть коли «місце на диску» виглядає нормально в інших розділах.
Рішення: Знайдіть і видаліть інодоємний смітник (каталоги кешу, старі резервні копії). Потім повторіть.
Завдання 8: Шукати застряглий режим обслуговування
cr0x@server:~$ sudo ls -la /var/www/html/.maintenance
-rw-r--r-- 1 www-data www-data 57 Dec 27 08:40 /var/www/html/.maintenance
Значення: Попереднє оновлення не прибрало файл. Користувачі можуть бачити «Короткочасно недоступно через планове обслуговування.»
Рішення: Якщо оновлення не виконується, видаліть його після перевірки, що немає активного процесу оновлення. Потім розбирайтеся, чому оновлення впало.
Завдання 9: Перевірити debug-лог WordPress на помилки розпаковки/фс
cr0x@server:~$ sudo tail -n 30 /var/www/html/wp-content/debug.log
[27-Dec-2025 08:41:12 UTC] PHP Warning: copy(/var/www/html/wp-content/plugins/contact-form-7/readme.txt): failed to open stream: Permission denied
[27-Dec-2025 08:41:12 UTC] PHP Warning: unlink(/var/www/html/wp-content/plugins/contact-form-7/readme.txt): Permission denied
Значення: Класична проблема власності/дозволів всередині каталогу призначення.
Рішення: Виправте власність/режим/ACL на цьому шляху. Не продовжуйте постійно повторювати встановлення; ви просто зловите журнали і нетерплячість.
Завдання 10: Переглянути логи веб-сервера / PHP для реальної помилки
cr0x@server:~$ sudo tail -n 50 /var/log/nginx/error.log
2025/12/27 08:41:12 [error] 12345#12345: *901 FastCGI sent in stderr: "PHP message: PHP Warning: mkdir(): Permission denied in /var/www/html/wp-admin/includes/class-wp-filesystem-direct.php on line 56" while reading response header from upstream
Значення: Метод файлової системи — direct, але mkdir зазнав відмови. Це не «логічна» проблема WordPress; це проблема на рівні ОС з доступом.
Рішення: Виправте права/власність, потім повторіть. Уникайте хакерських перезавантажень ZIP через адмінку, доки шлях запису не працює правильно.
Завдання 11: Перевірити структуру ZIP перед завантаженням (поширена проблема вендорів)
cr0x@server:~$ unzip -l /tmp/vendor-plugin.zip | head
Archive: /tmp/vendor-plugin.zip
Length Date Time Name
--------- ---------- ----- ----
0 2025-12-01 10:10 vendor-plugin/
0 2025-12-01 10:10 vendor-plugin/vendor-plugin/
2345 2025-12-01 10:10 vendor-plugin/vendor-plugin/plugin.php
Значення: Вкладена папка: vendor-plugin/vendor-plugin/. WordPress розпаковує до vendor-plugin, а фактичний плагін лежить на рівень глибше, що створює плутанину і може колідувати з наявними директоріями.
Рішення: Перепакуйте ZIP (топ-рівнева папка має бути slug плагіна і містити файли плагіна без зайвих вкладень) або встановіть через WP-CLI з коректного шляху.
Завдання 12: Використати WP-CLI, щоб побачити, що WordPress вважає встановленим
cr0x@server:~$ cd /var/www/html && sudo -u www-data wp plugin list --field=name | head
akismet
contact-form-7
hello
Значення: WordPress вже фіксує contact-form-7 як встановлений. Спроба встановлення з адмінки надлишкова або каталог пошкоджений, але все ще детектується.
Рішення: Розгляньте контрольоване перевстановлення через WP-CLI (з перезаписом), або перейменуйте каталог і встановіть чисто.
Завдання 13: Контрольоване перевстановлення через WP-CLI (плагін) без сліпого видалення
cr0x@server:~$ cd /var/www/html && sudo -u www-data wp plugin install contact-form-7 --force
Installing Contact Form 7 (6.0.3)
Downloading installation package from https://downloads.wordpress.org/plugin/contact-form-7.6.0.3.zip...
Unpacking the package...
Installing the plugin...
Plugin installed successfully.
Значення: --force наказує WP-CLI перезаписати. Це безпечніше, ніж ручне rm -rf, якщо ви довіряєте джерелу і права файлової системи коректні.
Рішення: Якщо це спрацювало, проблема була в адміні, що відмовлявся перезаписати, тоді як WP-CLI зробив це. Якщо не спрацювало, читайте точну помилку і виправляйте причину на рівні ОС.
Завдання 14: Перейменувати каталог призначення, щоб зберегти докази
cr0x@server:~$ sudo mv /var/www/html/wp-content/plugins/contact-form-7 /var/www/html/wp-content/plugins/contact-form-7.broken-20251227
Значення: Ви прибрали колізію і при цьому зберегли старий каталог для судової експертизи або відкату.
Рішення: Тепер повторіть встановлення. Якщо воно пройде — порівняйте старий каталог пізніше, щоб зрозуміти, що пішло не так.
Завдання 15: Виправити власність коректно (і тільки там, де потрібно)
cr0x@server:~$ sudo chown -R www-data:www-data /var/www/html/wp-content/plugins/contact-form-7
Значення: Веб-користувач тепер може керувати файлами всередині цього каталогу плагіна.
Рішення: Повторіть оновлення/встановлення. Якщо у вас є пайплайн деплойменту, що очікує власності root, зупиніться і вирішіть, хто володіє кодом: WordPress чи ваш пайплайн. Виберіть одне.
Завдання 16: Виявити і зняти незнімні атрибути (рідкісно, але гостро)
cr0x@server:~$ sudo lsattr -d /var/www/html/wp-content/plugins/contact-form-7
----i---------e------- /var/www/html/wp-content/plugins/contact-form-7
Значення: Директорія має атрибут immutable (i). Видалення і записи будуть зазнають невдачі навіть від root.
Рішення: Якщо це встановлено жорстким захистом або інструментом бекапу, зніміть immutable перед оновленням.
cr0x@server:~$ sudo chattr -i /var/www/html/wp-content/plugins/contact-form-7
Завдання 17: Перевірити контекст SELinux (якщо застосовно)
cr0x@server:~$ sudo getenforce
Enforcing
cr0x@server:~$ sudo ls -Zd /var/www/html/wp-content
unconfined_u:object_r:httpd_sys_content_t:s0 /var/www/html/wp-content
Значення: Якщо wp-content має мітку httpd_sys_content_t, Apache може читати, але не обов’язково записувати. Записувані шляхи зазвичай потребують httpd_sys_rw_content_t залежно від політики.
Рішення: Налаштуйте контексти лише для записуваних директорій, а не для всього docroot.
Завдання 18: Знайти залишкові робочі каталоги upgrade
cr0x@server:~$ sudo find /var/www/html/wp-content/upgrade -maxdepth 1 -type d -printf '%f\n' | head
upgrade
tmp-1234567890
tmp-1735290072
Значення: Старі тимчасові каталоги можуть вказувати на невдалі оновлення.
Рішення: Якщо оновлення не виконується, видаліть старі тимчасові каталоги, щоб зменшити колізії та захаращення, але збережіть останній, якщо потрібні докази.
Жарт №2: Нічого так не виглядає «enterprise-grade», як папка з ім’ям tmp-1735290072, яка тихо контролює ваш вікенд.
Безпечні виправлення, що не ламають wp-content
Стратегія A: Перейменуйте, не видаляйте (за замовчуванням переміщення)
Коли ви не на 100% упевнені, що в тій директорії, перейменуйте її. Перейменування оборотне, швидке і зберігає докази. Єдиний випадок, коли можна видалити одразу — коли ви чистите відому кеш-директорію або відомий тимчасовий каталог.
Добре: contact-form-7.broken-20251227
Погано: rm -rf contact-form-7 і потім «думаю, воно було в порядку?»
Стратегія B: Використовуйте WP-CLI для контрольованого перезапису
Адмінка WordPress обережна. WP-CLI — прямий інструмент. Якщо ви — ops людина, хочете детерміністичну поведінку і журнали, які можна зафіксувати. Використовуйте:
wp plugin install <slug> --forcewp theme install <slug> --force
Але лише після підтвердження, що шлях запису та права в порядку. Якщо права неправильні, примусові записи просто призведуть до голоснішої невдачі.
Стратегія C: Виправляйте власність/права виважено
Найнебезпечніше «вирішення» у світі WordPress — це масові зміни прав:
- Уникайте:
chmod -R 777будь-де. - Уникайте: рекурсивного chown усього docroot, якщо ви деплоїте код через Git/CI; це створить дрейф і здивує наступний деплой.
Робіть замість цього: тримайте код ядра під власністю користувача деплойменту (або root), а робочі директорії робіть доступними для запису лише для runtime-користувача:
wp-content/uploadswp-content/cache(якщо використовується)wp-content/upgrade- каталоги плагінів/тем лише якщо ви дозволяєте оновлення на місці
Стратегія D: Забороніть WordPress самовносити зміни в production (якщо можете)
Суб’єктивний погляд: на серйозних production-системах WordPress не повинен мати змогу оновлювати себе клацанням у wp-admin. Це не пуризм; це зменшення неконтрольованих змін. Якщо у вас є CI/CD, immutable-образи або навіть базовий контроль змін, керуйте оновленнями як деплойментами. Тоді цей клас помилок значно зменшиться.
Компроміс: ви мусите також припинити просити WordPress бути пакетним менеджером. Виберіть модель:
- Модель 1: WordPress керує плагінами/темами. Ви забезпечуєте права і приймаєте ризик змін через адмінку.
- Модель 2: Ваш пайплайн керує плагінами/темами. Ви вимикаєте модифікації файлів у WordPress і деплоїте артефакти.
Стратегія E: Відновити пошкоджену інсталяцію без втрати налаштувань
Деякі плагіни зберігають налаштування в базі даних, а не у файловій системі. Якщо директорія плагіна пошкоджена, зазвичай можна перевстановити файли плагіна, не втрачаючи налаштувань. Але «зазвичай» не означає «завжди».
Безпечний підхід:
- Зробіть резервну копію бази даних (або снапшот).
- Резервний копіюйте директорію плагіна, перейменувавши її.
- Чисто перевстановіть плагін/тему.
- Перевірте поведінку і логи.
- Лише потім видаліть старий каталог.
Три корпоративні міні-історії (як це йде не так у реальному житті)
Міні-історія 1: Інцидент через неправильне припущення
Середня компанія запускала WordPress за Nginx і PHP-FPM на віртуалці. Маркетинг мав доступ адміністратора і встановлював плагіни напряму. Оперна команда припустила, що раз сайт працював місяцями, права файлів «в порядку». Насправді ні — просто не тестували.
Одного ранку оновлення плагіна впало під час розпаковки. Каталог плагіна існував, був частково оновлений, і WordPress відмовився перевстановити: «Папка призначення вже існує.» Панель адміністрування постійно пропонувала оновлення, які не могли завершитись. Ніхто не перевірив місце на диску чи власність; просто п’ять разів повторили оновлення, створюючи ще більше тимчасових директорій.
Неправильне припущення було тонким: «якщо WordPress може читати плагіни, він може їх оновити.» На тому хості попереднє техобслуговування скопіювало каталоги плагінів як root з резервного tarball. WordPress міг читати, але не міг їх замінити.
Виправлення було нудним: chown лише на уражений каталог плагіна і каталог підготовки оновлення до PHP-FPM-користувача, потім перевстановлення через WP-CLI. Пост-мортемна дія: заборонити оновлення в продакшні і перемістити управління плагінами в пайплайн деплойменту.
Міні-історія 2: Оптимізація, що дала зворотний результат
Організація перемістила wp-content на мережеву файлову систему, щоб декілька вузлів могли спільно використовувати завантаження і плагіни. Це виглядало акуратно: одне джерело правди, немає rsync медіафайлів, простіше масштабування. Оптимізація була «спільне сховище вирішує все», і такі речення швидко старіють.
Під час оновлення плагіна WordPress розпаковував ZIP на вузлі A, але вузол B ще бачив старий стан через кешування і затримку метаданих. WordPress на вузлі B теж спробував оновити (так, люди іноді натискають кнопки двічі), зіткнувся з директорією в проміжному стані і викинув «Папка призначення вже існує.» Плагін вийшов напів-новим, напів-старим по різних вузлах.
Вони спробували «виправити» це шляхом збільшення таймаутів PHP і додавання повторних спроб. Це збільшило радіус ураження. Зрештою довелося зробити адмінку лише для читання під час деплойментів і забезпечити, щоб лише один вузол виконував оновлення — або ще краще, припинити оновлення через wp-admin зовсім.
Урок не в тому, щоб ніколи не використовувати NFS. Він полягає в тому, що якщо ваш додаток очікує локальної семантики файлової системи для атомарної заміни директорій, потрібно про це думати. Або централізуйте оновлення через одне завдання деплойменту, або пакетуйте плагіни/теми як артефакти і розгортайте передбачувано.
Міні-історія 3: Нудна, але правильна практика, що врятувала день
Великий внутрішній WordPress-службовий інстанс обслуговував документацію. Це не було гламурно, але критично. Команда дотримувалася двох практик: (1) кожна зміна проходила через пайплайн деплойменту, і (2) файлову систему було майже зроблено лише для читання для runtime-користувача, окрім uploads і невеликого набору записуваних директорій.
Одного дня вендор надіслав «hotfix плагін» у ZIP і наполягав на негайній інсталяції. Адміністратор спробував. WordPress не міг писати в директорію плагінів (задумано), і UI помилка була — передбачувано — варіантом конфлікту папки призначення / неможливістю перезаписати. Паніка тривала близько п’яти хвилин.
Оскільки практика була нудною та послідовною, відповідь була простою: команда підготувала плагін у билд-воркспейсі, перевірила структуру ZIP, перепакувала його правильно, відсканувала, а потім задеплоїла як будь-яку іншу зміну. Ніяких ручних chmod. Ніякої північної археології в wp-content.
Сайт залишився стабільним, а «аварія» стала звичайною зміною з аудитом. Дивно, як часто «ми деплоїмо однаково кожного разу» — це різниця між дрібним незручністю і великим простоєм.
Поширені помилки: симптом → корінна причина → виправлення
1) Симптом: «Папка призначення вже існує» при завантаженні ZIP
Корінна причина: Каталог плагіна/теми вже існує від попередньої інсталяції, або ZIP містить топ-рівневу папку, що співпадає з наявною директорією.
Виправлення: Перевірте шлях призначення. Перейменуйте існуючий каталог. Перевірте макет ZIP за допомогою unzip -l. Перепакуйте, якщо є вкладення.
2) Симптом: Помилка повторюється після того, як ви «видалили плагін» у wp-admin
Корінна причина: Видалення в UI не пройшло через права; каталог залишився на диску. UI WordPress — це не обіцянка, це запит.
Виправлення: Перевірте наявність каталогу на диску і власність. Видаліть/перейменуйте на диску, коли впевнені, що це безпечно.
3) Симптом: Оновлення не вдається; каталог плагіна існує, але плагін зламаний
Корінна причина: Часткова розпаковка через таймаут, заповнений диск, вичерпані іноди або убитий PHP-воркер.
Виправлення: Звільніть диск/іноди, очистіть застарілі тимчасові каталоги upgrade, перейменуйте пошкоджений каталог плагіна, перевстановіть через WP-CLI.
4) Симптом: WordPress несподівано просить FTP-облікові дані
Корінна причина: WordPress не може писати напряму в файлову систему, тому переключається на метод файлової системи через FTP.
Виправлення: Виправте права/власність для runtime-користувача на потрібних директоріях, або оберіть FTP/SSH робочий процес (не рекомендовано для production).
5) Симптом: Права виглядають правильно, але оновлення все одно не проходять
Корінна причина: SELinux/AppArmor блокує записи; або обмеження open_basedir/тимчасових директорій.
Виправлення: Перевірте режим примусового виконання та контексти; перевірте тимчасову директорію PHP; налаштуйте політику тільки для конкретних записуваних шляхів.
6) Симптом: Працює на одному вузлі, на іншому — ні (мультивузлова)
Корінна причина: Проблеми узгодженості спільного сховища або різні runtime-користувачі/UID мапінги між вузлами.
Виправлення: Забезпечте узгоджені UID/GID, централізуйте оновлення, уникайте оновлень через wp-admin у кластерних середовищах.
7) Симптом: Лише один плагін/тема не вдається оновити; інші — нормально
Корінна причина: Саме ця директорія має іншу власність, ACL, атрибут immutable або пошкоджений вміст.
Виправлення: Проінспектуйте цей шлях за допомогою ls -l, getfacl, lsattr. Ремонтуйте локально.
8) Симптом: «Не вдалося створити директорію» під час інсталяції, а потім «папка призначення вже існує» при наступній спробі
Корінна причина: Перша спроба створила директорію, але не змогла її заповнити; друга спроба зіткнулась із пустою залишковою папкою.
Виправлення: Видаліть/перейменуйте пусту папку, виправте первинну причину (права/диск/тимчасова директорія), потім повторіть інсталяцію.
Чеклісти / покроковий план (розумний, повторюваний)
Чекліст 1: Односерверний WordPress, де дозволені встановлення через wp-admin
- Визначте slug плагіна/теми, яку встановлюєте (ім’я папки під
wp-content). - Перевірте наявність: чи існує вже директорія?
- Перевірте стан: повна інсталяція чи часткова?
- Перевірте шлях запису: чи може runtime-користувач писати в
wp-contentіwp-content/upgrade? - Перевірте диск/іноди: не налагоджуйте інсталяції на повній файловій системі.
- Перейменуйте директорію, якщо підозрюєте часткову інсталяцію або корупцію.
- Перевстановіть через WP-CLI, якщо можливо (це простіше і скриптується).
- Перевірте: плагін активується, логи чисті, сайт відображається.
- Приберіть стару перейменовану директорію після періоду спостереження.
Чекліст 2: Production-система з CI/CD (рекомендовано)
- Вимкніть модифікацію файлів в production (щоб wp-admin не міг мутавати код).
- Зробіть docroot доступним лише для читання для runtime-користувача, окрім uploads і контрольованого набору директорій.
- Будуйте артефакти (плагіни/теми з зафіксованими версіями) в CI, а не на сервері.
- Деплойте атомарно (директорії release + swap через symlink), де можливо.
- План відкату повинен існувати і бути протестований (так, протестований).
- Спостерігайте: логи помилок, PHP-FPM і дебаг-логи WordPress збираються централізовано.
Крок за кроком: чисте відновлення після «папка призначення вже існує» (плагін)
- Зробіть снапшот файлової системи або хоча б швидкий tar каталогу
wp-content/plugins/<slug>і дамп бази даних. - Підтвердьте, що директорія існує і огляньте її.
- Перейменуйте
<slug>в<slug>.broken-<date>. - Забезпечте, щоб runtime-користувач міг писати в
wp-contentіwp-content/upgrade. - Встановіть/перевстановіть, використовуючи WP-CLI з
--force(або встановіть через адмінку, коли колізію видалено). - Активуйте плагін і проведіть швидкий функціональний тест (фронтенд, wp-admin, будь-які cron-завдання).
- Слідкуйте за логами протягом 10–15 хвилин нормального використання.
- Видаліть перейменовану пошкоджену директорію, коли впевнитесь.
Поширені питання
1) Чи означає «Папка призначення вже існує», що плагін уже встановлений?
Іноді. Це лише означає, що існує директорія з таким ім’ям. Вона може бути здоровою інсталяцією або напіврозпакованою директорією після невдалого оновлення. Підтвердіть за допомогою wp plugin list і огляду вмісту каталогу.
2) Чи варто видаляти папку під wp-content/plugins, щоб виправити це?
Краще спочатку перейменувати. Видалення незворотне і часто знищує докази, потрібні для розуміння невдачі. Перейменуйте, перевстановіть, перевірте, і тільки потім видаліть.
3) Чому WordPress відмовляється перезаписувати папку?
Тому що перезапис може бути руйнівним, якщо в існуючій директорії є робоча версія або локальні модифікації. WordPress обирає безпеку над зручністю, навіть якщо це незручно.
4) Чи може WP-CLI виправити це швидше, ніж wp-admin?
Так. WP-CLI дає детерміністичні прапори як --force і чіткіший вивід помилок. Також він уникає таймаутів браузера/проксі під час великих розпаковок.
5) Чи знищить перевстановлення плагіна його налаштування?
Зазвичай налаштування плагіна зберігаються в базі даних і переживуть перевстановлення файлів. Але деякі плагіни зберігають конфігуаційні файли в своєму каталозі. Зробіть резервну копію каталогу і бази даних перед перезаписом.
6) Я виправив права, але помилка лишається. Що далі?
Перевірте відмови SELinux/AppArmor, атрибути immutable і вичерпання диску/інодів. Також перевірте структуру ZIP — вкладені директорії можуть викликати повторні колізії.
7) Чому це частіше трапляється в кластерних налаштуваннях?
Тому що спільне сховище і кілька вузлів додають проблеми узгодженості і конкуренції. Два вузли, що одночасно намагаються «оновити» ту саму директорію — типовий сценарій напівнового коду і заплутаних перевірок існування.
8) Чи дозволяти WordPress оновлювати плагіни/теми в production?
Якщо у вас невеликий сайт на одиночному сервері і ви приймаєте ризик, це може бути нормально за наявності хороших резервних копій. Якщо ви працюєте в production з контролем змін, використовуйте CI/CD і обмежте запис runtime.
9) А як щодо налаштування WordPress FS_METHOD?
Примусове встановлення FS_METHOD в direct може приховати глибші проблеми з правами в деяких налаштуваннях і погіршити безпеку в інших. Виправіть базову власність/ACL і дозволяйте WordPress використовувати direct лише коли це доречно.
Наступні кроки, які ви реально можете зробити сьогодні
Помилка «Папка призначення вже існує» — це WordPress, що каже: «Я бачу щось на диску і не впевнений, чи мені на це наступати.» Ставтеся до цього як до запобіжного механізму, а не як до образи.
- Програйте швидкий план діагностики: підтвердіть slug, огляньте каталог призначення, перевірте права запису, диск/іноди, а потім логи.
- Перейменуйте перед видаленням. Зберігайте докази, менше жалю.
- Виправляйте причину (власність, каталог підготовки, SELinux, тимчасові директорії), а не симптом.
- Виберіть операційну модель: або WordPress керує плагінами/темами (і ви підтримуєте це), або ваш пайплайн керує ними (і WordPress перестає пробувати).
- Зробіть це повторюваним: оформіть наведені кроки у рукописний runbook і перестаньте щоразу знову вчитися на 9-й годині ранку.
Якщо не зробите нічого іншого: припиніть «виправляти» WordPress випадковим видаленням вмісту wp-content. Це не операції. Це гра на удачу з кращим брендом.