Управлять одним сайтом WordPress через админку — нормально. Управлять пятью — терпимо. Управлять пятьюдесятью — мучение. Каждый клик в сетевой админке превращается в отдельную операцию: зайти на сайт, обновить плагин, выйти, зайти на следующий. Умножьте на 50 сайтов, на 10 плагинов — получите 500 кликов только для одного обновления.
Знаете, что отличает опытного администратора сетей от новичка? Первый никогда не заходит в админку для рутинных операций. Он открывает терминал, набирает одну команду — и через 30 секунд все 50 сайтов обновлены. Это WP-CLI.
WP-CLI — это командная строка для WordPress. А для Multisite это не просто удобный инструмент, а необходимость. Без него сеть из 20+ сайтов превращается в источник постоянной головной боли. С ним — в управляемый, предсказуемый механизм.
В этом руководстве разберём все ключевые операции: массовые обновления, управление плагинами и темами, работа с пользователями, бэкапы и автоматизация через cron. Всё с реальными командами, которые можно копировать и применять.
Что такое WP-CLI и почему он обязателен для Multisite
WP-CLI (WordPress Command Line Interface) — официальный инструмент от команды WordPress для управления сайтом через терминал. Делает всё то же, что и админка, но в десятки раз быстрее.
Почему для Multisite он критичен:
- Масштаб: одна команда работает сразу на всех сайтах сети
- Скорость: массовое обновление 50 сайтов — 30 секунд вместо 30 минут
- Автоматизация: команды можно встраивать в cron-скрипты и CI/CD
- Надёжность: нет таймаутов, как при обновлениях через браузер
- Доступ к скрытым функциям: массовый поиск, регенерация миниатюр, очистка транзентов
Базовая установка (если ещё не установлен):
# Скачиваем phar-файл
curl -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar
# Делаем исполняемым
chmod +x wp-cli.phar
# Перемещаем в системную папку
sudo mv wp-cli.phar /usr/local/bin/wp
# Проверяем
wp --infoВсе команды в этом руководстве выполняются из корня WordPress-установки. Если вы в другой директории, добавьте флаг --path=/var/www/wordpress.
Базовые команды: навигация по сети
Прежде чем делать массовые операции, нужно понимать структуру сети. WP-CLI даёт полный контроль над списком сайтов.
Получить список всех сайтов:
# Все сайты с базовой информацией
wp site list
# С конкретными полями
wp site list --fields=blog_id,url,registered,last_updated
# Только публичные сайты
wp site list --field=url --public=1
# В формате CSV (удобно для импорта в таблицы)
wp site list --format=csv > sites.csvПереход между сайтами:
Любая команда WP-CLI по умолчанию работает на основном сайте (blog_id=1). Чтобы выполнить её на конкретном подсайте, используйте флаг --url:
# Получить опции конкретного сайта
wp option get siteurl --url=blog.custom-code.ru
# Посмотреть активных пользователей сайта
wp user list --url=shop.custom-code.ru --role=administratorА знаете, в чём настоящая магия? Флаг --network выполняет команду на всех сайтах сети одновременно:
# Обновить все опции "blogname" во всей сети
wp option update blogname "Custom Code Network" --networkМассовые обновления: ядро, плагины, темы
Это самая частая операция. В админке Multisite обновления выглядят просто, но на практике обновление 10 плагинов на 30 сайтах через браузер — это час кликов и祈祷, чтобы ничего не сломалось.
Обновление ядра WordPress для всей сети:
# Обновить ядро
wp core update
# Обновить базу данных для всех сайтов сети
wp core update-db --networkФлаг --network здесь критичен. Без него обновится только база основного сайта, а остальные 29 останутся со старой схемой. И начнут падать с ошибками.
Обновление плагинов на всех сайтах:
# Обновить все плагины на всех сайтах
wp plugin update --all --network
# Обновить конкретный плагин на всех сайтах
wp plugin update woocommerce --network
# Обновить плагины только на одном сайте
wp plugin update --all --url=shop.custom-code.ruОбновление тем:
# Все темы во всей сети
wp theme update --all --network
# Конкретная тема
wp theme update flavor --networkПроверка статуса обновлений:
Перед обновлением полезно посмотреть, что вообще требует обновления:
# Проверка ядра
wp core check-update
# Проверка плагинов
wp plugin list --update=available --network
# Проверка тем
wp theme list --update=available --networkМассовое управление плагинами
В Multisite есть два уровня активации плагинов: сетевая (на всех сайтах сразу) и индивидуальная (на конкретном сайте). WP-CLI умеет оба.
Активация для всей сети:
# Установить плагин
wp plugin install redis-cache
# Активировать для всей сети
wp plugin activate redis-cache --network
# Деактивировать для всей сети
wp plugin deactivate redis-cache --networkАктивация на конкретных сайтах:
# Активировать WooCommerce только на сайтах-магазинах
wp site list --field=url | grep shop | while read url; do
wp plugin activate woocommerce --url=$url
doneЭтот скрипт находит все сайты с «shop» в URL и активирует WooCommerce только на них. Полезно, когда в сети смешаны блоги и магазины.
Удаление плагина со всех сайтов:
# Сначала деактивируем везде
wp plugin deactivate bad-plugin --network
# Потом удаляем
wp plugin delete bad-pluginВажный нюанс: в Multisite плагин физически хранится в одном месте (wp-content/plugins/), поэтому удаляется один раз. Но деактивировать его нужно на каждом сайте отдельно — иначе останутся «висящие» активации в базе.
Массовое управление пользователями
В Multisite пользователи общие для всей сети, но права у них разные на разных сайтах. Админка показывает плоский список, и разобраться, кто куда имеет доступ, — тот ещё квест.
Просмотр пользователей сети:
# Все пользователи сети
wp user list --network
# Super Admins
wp super-admin list
# Пользователи конкретного сайта
wp user list --url=blog.custom-code.ru
# Поиск по email
wp user get user@example.com --networkМассовое добавление пользователей:
# Создать пользователя
wp user create editor editor@example.com --role=editor
# Добавить существующего пользователя на все сайты сети
wp site list --field=url | while read url; do
wp user add-role editor@example.com editor --url=$url
doneМассовое удаление спам-аккаунтов:
Если в сети открыта регистрация, рано или поздно набегают боты. Чистим их одним скриптом:
# Найти пользователей без постов и комментариев
wp user list --field=user_login --network | while read user; do
posts=$(wp db query "SELECT COUNT(*) FROM wp_posts WHERE post_author = (SELECT ID FROM wp_users WHERE user_login = '$user')" --skip-column-names)
if [ "$posts" -eq 0 ]; then
echo "Deleting spam user: $user"
wp user delete $user --network --yes
fi
done⚠️ Осторожно: этот скрипт удаляет пользователей навсегда. Сначала запустите его без команды wp user delete — просто выведите список. Проверьте, что не попали реальные пользователи.
Массовая работа с контентом
Контент в Multisite хранится в отдельных таблицах для каждого сайта (wp_2_posts, wp_3_posts). Но WP-CLI абстрагирует это — вы работаете с ним как с обычным сайтом.
Поиск и замена текста на всех сайтах:
Классическая задача: компания сменила название, и нужно обновить его во всех статьях. Через админку — сотни ручных правок. Через WP-CLI — одна команда:
# Поиск и замена с учётом сериализации
wp site list --field=url | while read url; do
wp search-replace 'Старое Название' 'Новое Название' --url=$url --all-tables
doneФлаг --all-tables гарантирует, что замена пройдёт во всех таблицах сайта, включая кастомные.
Экспорт контента со всех сайтов:
# Экспорт каждого сайта в отдельный XML
mkdir -p /backup/exports
wp site list --field=url | while read url; do
name=$(echo $url | sed 's/https\?:\/\///' | tr '.' '_')
wp export --url=$url --dir=/backup/exports --filename_format="${name}-%Y-%m-%d.xml"
doneЧерез 5 минут у вас будет папка с XML-файлами всех сайтов сети. Идеально для бэкапов или миграции.
Регенерация миниатюр:
Если изменили размеры миниатюр в теме или установили плагин для оптимизации изображений, нужно перегенерировать миниатюры для всех сайтов:
wp site list --field=url | while read url; do
echo "Regenerating for $url..."
wp media regenerate --url=$url --yes
doneОптимизация базы данных
Multisite создаёт отдельные таблицы для каждого сайта. При 50 сайтах это тысячи таблиц. Со временем они обрастают мусором: ревизиями, транзентами, спам-комментариями.
Очистка ревизий на всех сайтах:
# Оставить только 5 последних ревизий для каждого поста
wp site list --field=url | while read url; do
wp post delete $(wp post list --post_type=revision --url=$url --format=ids | awk '{for(i=6;i<=NF;i++) print $i}') --url=$url --force 2>/dev/null
doneБолее простой вариант — через прямой SQL-запрос:
# Удалить все ревизии старше 30 дней во всей сети
wp db query "DELETE FROM wp_posts WHERE post_type = 'revision' AND post_modified < DATE_SUB(NOW(), INTERVAL 30 DAY);"Очистка транзентов:
# Удалить все просроченные транзенты на всех сайтах
wp transient delete --expired --network
# Удалить все транзенты (аккуратно!)
wp transient delete --all --networkОптимизация всех таблиц:
# Оптимизация таблиц базы данных
wp db optimize
# Проверка целостности
wp db checkАвтоматизация через скрипты и cron
Ручное выполнение команд — это хорошо для разовых задач. Но настоящая сила WP-CLI раскрывается в автоматизации. Создаём скрипты и вешаем их на cron.
Скрипт ежедневного обслуживания:
Создаём файл /usr/local/bin/wp-multisite-maintenance.sh:
#!/bin/bash
# Конфигурация
WP_PATH="/var/www/wordpress"
LOG_FILE="/var/log/wp-maintenance.log"
DATE=$(date +%Y-%m-%d_%H-%M)
cd $WP_PATH
echo "[$DATE] Starting multisite maintenance..." >> $LOG_FILE
# 1. Очистка просроченных транзентов
echo "[$DATE] Cleaning expired transients..." >> $LOG_FILE
wp transient delete --expired --network --path=$WP_PATH >> $LOG_FILE 2>&1
# 2. Удаление спам-комментариев
echo "[$DATE] Deleting spam comments..." >> $LOG_FILE
wp site list --field=url --path=$WP_PATH | while read url; do
wp comment delete $(wp comment list --status=spam --url=$url --path=$WP_PATH --format=ids) --url=$url --path=$WP_PATH --force 2>/dev/null
done
# 3. Оптимизация базы данных
echo "[$DATE] Optimizing database..." >> $LOG_FILE
wp db optimize --path=$WP_PATH >> $LOG_FILE 2>&1
# 4. Проверка обновлений
echo "[$DATE] Checking for updates..." >> $LOG_FILE
wp core check-update --path=$WP_PATH >> $LOG_FILE 2>&1
wp plugin list --update=available --network --path=$WP_PATH >> $LOG_FILE 2>&1
# 5. Отправка отчёта в Telegram
REPORT=$(tail -n 50 $LOG_FILE)
curl -s -X POST "https://api.telegram.org/bot$BOT_TOKEN/sendMessage" \
-d chat_id="$CHAT_ID" \
-d text="🔧 WP Multisite Maintenance Report ($DATE):
$REPORT"
echo "[$DATE] Maintenance completed" >> $LOG_FILEДелаем исполняемым:
chmod +x /usr/local/bin/wp-multisite-maintenance.shДобавление в cron:
# Запуск каждый день в 3 часа ночи
0 3 * * * /usr/local/bin/wp-multisite-maintenance.shСкрипт безопасного обновления:
Обновления — рискованная операция. Создаём скрипт, который делает бэкап, обновляет и проверяет работоспособность:
#!/bin/bash
WP_PATH="/var/www/wordpress"
BACKUP_DIR="/backup/multisite"
DATE=$(date +%Y-%m-%d)
cd $WP_PATH
# 1. Бэкап базы данных
echo "Creating backup..."
wp db export $BACKUP_DIR/multisite-$DATE.sql
# 2. Обновление ядра
echo "Updating core..."
wp core update
wp core update-db --network
# 3. Обновление плагинов
echo "Updating plugins..."
wp plugin update --all --network
# 4. Обновление тем
echo "Updating themes..."
wp theme update --all --network
# 5. Проверка работоспособности каждого сайта
echo "Verifying sites..."
wp site list --field=url | while read url; do
status=$(curl -s -o /dev/null -w "%{http_code}" $url)
if [ "$status" != "200" ]; then
echo "⚠️ Site $url returned HTTP $status"
# Отправить алерт
curl -s -X POST "https://api.telegram.org/bot$BOT_TOKEN/sendMessage" \
-d chat_id="$CHAT_ID" \
-d text="🚨 ALERT: $url returned HTTP $status after update"
fi
done
echo "Update completed"Мониторинг здоровья сети
Multisite из десятков сайтов сложно мониторить через обычный аптайм-чекер. Нужны специализированные проверки.
Скрипт проверки всех сайтов:
#!/bin/bash
# Проверка доступности всех сайтов
wp site list --field=url | while read url; do
# HTTP-код ответа
http_code=$(curl -s -o /dev/null -w "%{http_code}" $url --max-time 10)
# Время ответа
response_time=$(curl -s -o /dev/null -w "%{time_total}" $url --max-time 10)
# Размер ответа
size=$(curl -s -o /dev/null -w "%{size_download}" $url --max-time 10)
echo "$url | HTTP $http_code | ${response_time}s | ${size} bytes"
# Алерт при проблемах
if [ "$http_code" != "200" ] || (( $(echo "$response_time > 5" | bc -l) )); then
curl -s -X POST "https://api.telegram.org/bot$BOT_TOKEN/sendMessage" \
-d chat_id="$CHAT_ID" \
-d text="⚠️ $url: HTTP $http_code, ${response_time}s"
fi
doneПоиск "мёртвых" сайтов:
В больших сетях часто есть заброшенные сайты, которые никто не обновляет годами. Находим их:
# Сайты, которые не обновлялись больше года
wp site list --fields=url,last_updated | awk '
NR > 1 {
split($2, a, "-");
last_update = mktime(a[1] " " a[2] " " a[3] " 0 0 0");
year_ago = systime() - 365 * 24 * 60 * 60;
if (last_update < year_ago) print "Inactive: " $1
}'Такие сайты — кандидаты на архивацию или удаление. Они создают нагрузку, но не приносят пользы.
Продвинутые техники
Параллельное выполнение команд:
Последовательное выполнение команд на 50 сайтах может занять час. Используем xargs с параллелизацией:
# Обновить плагины на всех сайтах параллельно (10 потоков)
wp site list --field=url | xargs -P 10 -I {} wp plugin update --all --url={}
# Проверить все сайты параллельно
wp site list --field=url | xargs -P 20 -I {} curl -s -o /dev/null -w "{}: %{http_code}\n" {}Флаг -P 10 означает 10 параллельных процессов. Не ставьте больше, чем у вас ядер CPU × 2 — получите обратный эффект из-за переключения контекста.
Клонирование сайта в сети:
Иногда нужно создать новый сайт по образу существующего. WP-CLI позволяет экспортировать контент и импортировать его на новый сайт:
# 1. Создать новый сайт
wp site create --slug=newblog --title="New Blog" --email=admin@example.com
# 2. Экспортировать контент с шаблона
wp export --url=template.custom-code.ru --dir=/tmp
# 3. Импортировать на новый сайт
wp import /tmp/template-*.xml --url=newblog.custom-code.ru --authors=createГенерация отчёта по сети:
#!/bin/bash
# Собрать статистику по всей сети
echo "=== MULTISITE NETWORK REPORT ==="
echo "Generated: $(date)"
echo ""
echo "Total sites: $(wp site list --format=count)"
echo "Total users: $(wp user list --network --format=count)"
echo ""
echo "=== TOP 10 SITES BY POST COUNT ==="
wp site list --field=url | while read url; do
count=$(wp post list --url=$url --post_type=post --post_status=publish --format=count 2>/dev/null)
echo "$count posts: $url"
done | sort -rn | head -10
echo ""
echo "=== PLUGINS INSTALLED ==="
wp plugin list --network --fields=name,version,status --format=table
echo ""
echo "=== PENDING UPDATES ==="
wp plugin list --update=available --network --format=table
wp theme list --update=available --network --format=tableЧек-лист: автоматизация Multisite
Пройдитесь по этому списку. Если хотя бы один пункт не автоматизирован — вы тратите время впустую.
- ✅ Массовое обновление плагинов — одна команда вместо сотни кликов
- ✅ Обновление ядра с --network — для обновления всех баз данных
- ✅ Ежедневная очистка транзентов — через cron
- ✅ Регулярная очистка ревизий — раз в неделю
- ✅ Мониторинг доступности всех сайтов — с алертами в Telegram
- ✅ Поиск заброшенных сайтов — раз в квартал
- ✅ Автоматические бэкапы базы данных — ежедневно
- ✅ Отчёт о состоянии сети — раз в неделю в почту/Telegram
- ✅ Параллельное выполнение — для ускорения массовых операций
- ✅ Безопасные обновления с откатом — бэкап перед обновлением
Решение частых проблем
WP-CLI выдаёт «Site not found» для подсайтов
Проблема в том, что WP-CLI определяет сайт по URL из $_SERVER['HTTP_HOST']. При выполнении команды из терминала эта переменная пуста. Решение — всегда указывать --url явно:
# Неправильно
wp option get blogname
# Правильно
wp option get blogname --url=blog.custom-code.ruКоманды выполняются слишком медленно
Если операция на 50 сайтах занимает час — включите параллельное выполнение через xargs -P. Также убедитесь, что включён OPcache и Redis Object Cache — без них WP-CLI работает в 3-5 раз медленнее.
Ошибка «Allowed memory size exhausted» при массовых операциях
WP-CLI использует тот же memory_limit, что и PHP-FPM. Для массовых операций увеличьте его временно:
# Временно увеличить лимит для WP-CLI
wp plugin update --all --network --skip-themes --skip-pluginsИли в wp-cli.yml в корне сайта:
php:
memory_limit: 1GНе могу выполнить команду — «Permission denied»
WP-CLI должен запускаться от того же пользователя, что и веб-сервер (обычно www-data). Запуск от root создаст файлы с правами root, и веб-сервер не сможет их читать. Решение:
# Запуск от нужного пользователя
sudo -u www-data wp plugin update --all --network
# Или добавить флаг --allow-root (не рекомендуется)
wp plugin update --all --network --allow-rootИтог
WP-CLI для Multisite — это не опция, а базовая необходимость. Без него управление сетью из десятков сайтов превращается в ручной труд, который съедает часы каждую неделю. С ним те же операции занимают минуты.
Главные преимущества: массовые обновления одной командой, автоматизация через cron, параллельное выполнение для скорости, скрипты для мониторинга и отчётов. Всё это превращает Multisite из источника стресса в управляемый механизм.
Начните с простого: освойте wp site list, wp plugin update --all --network и wp core update-db --network. Это покроет 80% повседневных задач. Потом добавляйте скрипты автоматизации и мониторинг. Через месяц вы удивитесь, как раньше жили без этого.
А главное — откройте терминал прямо сейчас. Наберите wp site list. Посмотрите на свою сеть глазами администратора, а не пользователя. Это другой уровень управления. И он вам понравится.