12k
All articles

WP-CLI для тех, кто живёт в терминале

Команды WP-CLI для миграций WordPress, резервных копий, потери доступа, обновления плагинов и ядра, удаленных SSH-задач и безопасного search-replace.

OpenReplay Team
OpenReplay Team
WP-CLI для тех, кто живёт в терминале

WP-CLI — это интерфейс командной строки для установки WordPress. Он экономит клики, но настоящая причина его освоить — набор задач, для которых в консоли администратора попросту нет экрана: переписывание сериализованных данных опций при смене домена, выполнение произвольного PHP на живом сайте и обновление десяти инсталляций из одной командной строки.

Большинство знакомится с ним в аварийной ситуации. Обновление плагина кладёт админку, панель управления не загружается, и внезапно FTP вместе с phpMyAdmin оказываются единственным путём обратно. Этот путь работает, но он медленный и требует определённой выдержки.

Статья построена по задачам, а не по пространствам имён. Каждый раздел — это задача, которая в панели администратора болезненна или невозможна, а следом идёт команда, которая её решает, и флаги, которые делают это безопасным.

Ключевые выводы

  • wp search-replace десериализует данные PHP, применяет замену и сериализует их обратно — именно поэтому команда способна переписать настройки виджетов и опции плагинов, которые «сырой» SQL-вызов REPLACE() испортил бы.
  • Каждую замену сначала запускайте с --dry-run, а затем выполняйте ту же самую команду без этого флага.
  • Исключайте колонку guid с помощью --skip-columns=guid, поскольку читалки лент используют guid записи, чтобы понять, показывали ли они её раньше.
  • --ssh=[<scheme>:][<user>@]<host>[:<port>][<path>] проксирует команду на удалённую инсталляцию, и на удалённой машине должна быть своя копия WP-CLI, доступная по команде wp.
  • Ни одна из этих команд не запрашивает подтверждения и ни одну нельзя отменить, поэтому сначала — wp db export.

Эти команды выполняются немедленно

Никакого диалога подтверждения, никакого предпросмотра, никакой отмены. wp search-replace пишет в каждую совпавшую строку в тот момент, когда вы нажимаете Enter. wp plugin deactivate --all отключает всё на продакшене так же охотно, как и на ноутбуке. Единственный откат, который у вас есть, — экспорт базы данных, сделанный заранее, так что сделайте его.

Как сменить домен, не сломав сериализованные данные?

wp search-replace — правильный инструмент для смены домена: он корректно читает сериализованный PHP и не трогает первичные ключи, а обычный SQL find-and-replace не умеет ни того, ни другого. Причина — в формате хранения: функция PHP serialize() записывает строку как её длину в байтах, а затем саму строку.

a:1:{s:3:"url";s:27:"https://staging.example.com";}

Слепой SQL-запрос UPDATE ... REPLACE() перепишет URL на https://example.com, оставив 27 нетронутым. Заявленная длина больше не соответствует содержимому, PHP уже не может десериализовать значение, и виджет или опция плагина, жившие в нём, молча превращаются в ничто. WP-CLI десериализует структуру, выполняет замену внутри неё и сериализует обратно с корректными длинами.

Действуйте в три шага:

# 1. report what would change; writes nothing
wp search-replace 'https://staging.example.com' 'https://example.com' \
  --skip-columns=guid --dry-run

# 2. optional: write the result to a SQL file instead of the database
wp search-replace 'https://staging.example.com' 'https://example.com' \
  --skip-columns=guid --export=migration.sql

# 3. apply it
wp search-replace 'https://staging.example.com' 'https://example.com' \
  --skip-columns=guid

--dry-run выполняет всю работу целиком и печатает отчёт, после чего отбрасывает изменения. --export отправляет результат в SQL-файл и не трогает рабочую базу, так что вы можете прочитать диф или применить его в другом месте. Пропускайте колонку guid, потому что WordPress считает guid записи неизменным на всю её жизнь: измените его — и читалки лент могут показать весь ваш архив как новые публикации.

Для неудобных вложенных данных добавьте --precise. По умолчанию команда использует быстрые SQL-запросы и автоматически переключается на PHP для колонок, содержащих сериализованные данные; --precise принудительно включает PHP для каждой колонки — это медленнее, но надёжнее при сложных сериализованных структурах. Режим регулярных выражений тоже существенно медленнее, так что прибегайте к нему только тогда, когда литеральной строки недостаточно.

Как обновлять плагины и ядро сразу на нескольких сайтах?

Одна команда обновляет всё, для чего доступно обновление, без постраничной навигации в панели и без чекбоксов у каждого плагина:

wp plugin update --all
wp core update
wp core update-db

wp core update-db запускает процедуру обновления базы данных WordPress — тот самый шаг, который панель администратора выполняет за вас на экране обновления после апдейта ядра. Выполняйте её после wp core update, чтобы обновление завершилось полностью, а не наполовину.

В сочетании с псевдонимами, о которых речь ниже, та же строка превращается в wp @all plugin update --all и последовательно проходит по всем инсталляциям, которые вы обслуживаете.

Экспорт до, импорт после

wp db export вызывает mysqldump и берёт хост базы, её имя, пользователя и пароль из wp-config.php, так что вам никогда не приходится вводить параметры подключения. Указывайте имя файла явно; если его не задать, будет создан {dbname}-{Y-m-d}-{random-hash}.sql.

wp db export backup-$(date +%Y%m%d-%H%M%S).sql

Восстановление — зеркальная операция:

wp db import backup-20250413-141055.sql

wp db import принимает либо имя файла, либо данные из пайпа, так что вы можете отправить экспорт напрямую с одного хоста на другой через ssh. Если нужна более долгосрочная стратегия, чем единственный дамп перед рискованным изменением, в статьях OpenReplay про резервное копирование WordPress разбираются расписания и хранение копий вне сервера.

Как вернуться на сайт, с которого вас заблокировало?

Три команды покрывают почти любую потерю доступа — в том порядке, в котором вы бы запускали их в цейтноте. Создать нового администратора, сбросить пароль существующего пользователя или вообще убрать плагины из уравнения:

wp user create ops ops@example.com --role=administrator
wp user reset-password admin --show-password --skip-email
wp plugin deactivate --all

wp user reset-password генерирует новый пароль; --show-password печатает его в терминал, а --skip-email не даёт уведомлению уйти в почтовый ящик, который вы, возможно, не контролируете. wp plugin deactivate принимает --all, чтобы отключить всё, а также --exclude=<name>, чтобы оставить активным список плагинов через запятую.

Когда админку сломала фатальная ошибка в плагине, WP-CLI может не суметь выполнить bootstrap ровно по той же причине, что и сайт. Глобальный параметр --skip-plugins запрещает загрузку всех плагинов или указанного списка на время выполнения команды:

wp plugin deactivate broken-plugin --skip-plugins

Пропуск не меняет сохранённое состояние: плагин, пропущенный таким образом, по-прежнему числится активным. Это лишь даёт вам рабочий bootstrap, чтобы деактивация смогла выполниться. Не поможет это и тогда, когда фатальный код находится в mu-плагине, потому что mu-плагины WP-CLI загружает в любом случае. Именно в этот момент большинству администраторов впервые и требуется WP-CLI — и это быстрее, чем открывать FTP-клиент и переименовывать каталоги плагинов. Когда админка вернётся, диагностическая часть работы разобрана в статье OpenReplay про белый экран смерти в WordPress.

Разовое выполнение PHP через wp eval

wp eval выполняет произвольный PHP на полностью загруженной инсталляции WordPress. Эквивалента в панели администратора нет, и в этом весь смысл: любая функция, зарегистрированная плагином, любая опция, любой запрос превращаются в однострочник.

wp eval 'echo get_option( "siteurl" );'
wp eval 'echo count( get_users( [ "role" => "administrator" ] ) );'

Всё, что длиннее, должно лежать в файле. wp eval-file принимает путь к PHP-файлу, передаёт скрипту все дополнительные позиционные аргументы как $args и полностью пропускает bootstrap WordPress, если указать --skip-wordpress. Ваш код выполняется внутри метода, поэтому для каждой глобальной переменной, к которой вы обращаетесь, нужна своя строка global.

Для wp eval не существует режима dry run. Что бы скрипт ни записал — он это запишет. Это самый убедительный аргумент в пользу экспорта.

Как выполнять WP-CLI на удалённом хосте?

Вот здесь инструмент перестаёт быть просто удобством. Глобальный параметр --ssh в WP-CLI имеет вид --ssh=[<scheme>:][<user>@]<host>[:<port>][<path>] и работает так: он передаёт вашу команду бинарнику ssh, а тот — экземпляру WP-CLI на другой стороне.

wp --ssh=dev_user@example.com:2222~/webapps/production plugin list
КомпонентЗначение здесьЗначение по умолчанию, если опущено
scheme(опущено)ssh
userdev_userтекущий системный пользователь
hostexample.comобязателен
port222222
path~/webapps/productionдомашний каталог ssh-пользователя

Путь не отделяется разделителем. Пишите его сразу после порта — или сразу после хоста, если порт опущен, — и начинайте с / или ~. Помимо ssh, справочник по конфигурации из handbook документирует схемы vagrant, docker, docker-compose и docker-compose-run. Последняя запускает свежий контейнер через docker-compose run, а не использует уже поднятый.

Одно требование абсолютно: на удалённом сервере должен быть собственный WP-CLI, и он должен отзываться на команду wp. wp, который прекрасно работает при ручном входе, вполне может вернуть command-not-found через --ssh, потому что оболочка, выполняющая удалённую команду, формирует $PATH иначе. В большинстве дистрибутивов в начале ~/.bashrc стоит проверка, которая завершает выполнение, если оболочка неинтерактивна, так что любая строка с PATH ниже неё никогда не выполняется; zsh в такой ситуации читает ~/.zshenv, а не ~/.zshrc. Решение — задать $PATH явно на удалённой стороне.

Набрать такую строку дважды — уже перебор. Зарегистрируйте псевдонимы в wp-cli.yml вашего проекта или в глобальном ~/.wp-cli/config.yml:

@prod:
  ssh: deploy@example.com~/webapps/production
@stage:
  ssh: deploy@staging.example.com~/webapps/staging
@all:
  - @prod
  - @stage
wp @prod plugin update --all
wp @all core check-update

Группа псевдонимов выполняет один вызов сразу для нескольких инсталляций — в этом и заключается разница между обслуживанием десяти клиентских сайтов и входом в десять панелей администратора. Для локальной инсталляции, которая находится не в текущем каталоге, глобальный параметр --path указывает WP-CLI, где лежат файлы WordPress:

wp --path=/var/www/example.com/htdocs plugin update --all

Что дальше

Единственная мысль, которую стоит отсюда унести: WP-CLI понимает структуры данных WordPress, а mysql и phpMyAdmin — нет, и именно поэтому смена домена — это работа для wp search-replace и ни для чего другого. Возьмите ближайшую запланированную миграцию, напишите строку с --dry-run, прочитайте отчёт и выполните wp db export перед тем, как убрать флаг. Всё описанное выше необратимо в тот самый момент, когда вы нажимаете Enter.

Часто задаваемые вопросы

Обновляет ли wp search-replace все сайты в сети multisite?

Нет. Команда работает с теми таблицами, которые регистрирует сам WordPress, поэтому в multisite вы получите только таблицы текущего сайта, если не добавите --network. Чтобы охватить каждую таблицу в базе данных — с любым префиксом и независимо от того, знает ли о ней WordPress, — используйте --all-tables: этот флаг имеет приоритет над --network и --all-tables-with-prefix. В сети также добавляйте --url, чтобы WP-CLI загрузился в контексте нужного сайта.

Почему WP-CLI отказывается работать от root?

WP-CLI останавливается с ошибкой YIKES, когда обнаруживает пользователя root. Всё, что находится внутри инсталляции, включая написанные не вами плагины и темы, унаследовало бы права root на сервере, так что один фрагмент враждебного кода мог бы захватить всю машину. Флаг --allow-root пропускает эту проверку, и контейнерам, работающим от root, он часто необходим, но проект не рекомендует его использовать. Вместо этого запускайте команды от системного пользователя, которому принадлежат файлы WordPress.

Что означает ошибка 'This does not seem to be a WordPress installation'?

WP-CLI не нашёл файлов ядра WordPress там, где искал, и поэтому не выполнил bootstrap. Запускайте команду из каталога, содержащего wp-admin, wp-content и wp-includes, либо укажите путь к инсталляции глобальным параметром --path. Передавайте значение через знак равенства, --path=/var/www/html, потому что при аргументе через пробел флаг остаётся без значения и та же ошибка повторяется.

Работает ли WP-CLI в Windows?

WP-CLI рассчитан на UNIX-подобное окружение — Linux, macOS, FreeBSD или Cygwin, — а в самой Windows поддерживается лишь частично, поэтому на машине с Windows надёжный путь — это WSL или Cygwin. Ему также требуется WordPress версии 4.9 или новее, а всё, что старше текущего релиза WordPress, может работать не в полном объёме.

DevTools for the frontend

Gain Debugging Superpowers

Unleash the power of session replay to reproduce bugs, track slowdowns and uncover frustrations in your app. Get complete visibility into your frontend with OpenReplay — the most advanced open-source session replay tool for developers.

Star on GitHub12k

We use cookies to improve your experience. By using our site, you accept cookies.