12k
All articles

ターミナルで暮らす人のための WP-CLI

WordPressの移行、バックアップ、ロックアウト対応、プラグインとコア更新、リモートSSH、シリアライズデータを安全に置換するWP-CLIコマンド集。

OpenReplay Team
OpenReplay Team
ターミナルで暮らす人のための WP-CLI

WP-CLI は WordPress インストールに対するコマンドラインインターフェースです。クリック数を減らしてくれますが、学ぶべき本当の理由は、ダッシュボードにそもそも画面が用意されていない仕事の数々にあります。ドメイン変更時のシリアライズされたオプションデータの書き換え、稼働中のサイトに対する任意の PHP の実行、そして 1 つのプロンプトから 10 個のインストールを更新すること、といった作業です。

多くの人は緊急時にこのツールと出会います。プラグインの更新で管理画面が落ち、ダッシュボードが読み込まれなくなり、FTP と phpMyAdmin が突然、復旧への唯一の道になる。その経路でも作業は進みますが、遅いうえにそれなりの度胸が要ります。

この記事は名前空間ではなく、仕事単位で構成しています。各セクションは、ダッシュボードでは苦痛あるいは不可能なタスクを示し、それを実行するコマンドと、安全に実行するためのフラグを続けて紹介します。

要点

  • wp search-replace は PHP データをアンシリアライズし、置換を適用してから再シリアライズします。だからこそ、生の SQL REPLACE() なら壊してしまうウィジェット設定やプラグインオプションも書き換えられます。
  • すべての置換はまず --dry-run で実行し、その後まったく同じコマンドをフラグなしで実行してください。
  • --skip-columns=guid で guid カラムを除外してください。フィードリーダーは投稿の guid を使って、その投稿を既に表示済みかどうかを判断するためです。
  • --ssh=[<scheme>:][<user>@]<host>[:<port>][<path>] はコマンドをリモートのインストールへプロキシします。リモートマシン側には wp で応答する独自の WP-CLI が必要です。
  • これらのコマンドはいずれも確認を求めず、取り消しもできません。そのため、まず wp db export です。

これらのコマンドは即座に実行される

確認ダイアログもプレビュー画面も、取り消しもありません。wp search-replace は Return キーを押した瞬間に、一致するすべての行に書き込みます。wp plugin deactivate --all は、ノートパソコン上と同じ気軽さで本番サイトのすべてを無効化します。唯一のロールバック手段は、事前に取得したデータベースのエクスポートだけです。ですから、必ず取得してください。

シリアライズされたデータを壊さずにドメインを変更するには?

ドメイン変更には wp search-replace が適切なツールです。シリアライズされた PHP を正しく読み取り、主キーには手を触れません。素の SQL による検索置換は、そのどちらもこなせません。理由はストレージ形式にあります。PHP の serialize() は、文字列をそのバイト長に続けて文字列本体という形で記録します。

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

何も考えない SQL の UPDATE ... REPLACE() は URL を https://example.com に書き換えますが、27 はそのまま残します。宣言された長さがペイロードと一致しなくなり、PHP はその値をアンシリアライズできなくなり、そこに格納されていたウィジェットやプラグインのオプションは何も告げずに空へ戻ります。WP-CLI は構造をアンシリアライズし、その内部で置換を行い、正しい長さで再シリアライズします。

3 段階で慎重に進めましょう。

# 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 を強制するため、低速ですが複雑なシリアライズ構造に対してはより確実です。正規表現モードも大幅に遅くなるので、リテラル文字列では対応できない場合にのみ使ってください。

複数サイトにまたがってプラグインとコアを更新するには?

1 つのコマンドで、更新が利用可能なすべてを更新できます。ダッシュボードのページネーションも、プラグインごとのチェックボックスもありません。

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

wp core update-db は WordPress のデータベース更新ルーチンを実行します。これはコア更新後にダッシュボードのアップグレード画面が代わりに実行してくれるステップです。アップグレードが中途半端ではなく完了するよう、wp core update の後に実行してください。

後述のエイリアスと組み合わせれば、同じ 1 行が 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 経由であるホストから別のホストへ直接送ることもできます。リスクのある変更の前に 1 回ダンプを取るよりも長期的な戦略については、OpenReplay の WordPress バックアップ関連記事でスケジューリングとオフサイト保管を扱っています。

締め出されたサイトに再び入るには?

ほぼすべての締め出し状況を 3 つのコマンドでカバーできます。プレッシャー下で実行するであろう順に並べてあります。新しい管理者を作成する、既存ユーザーのパスワードをリセットする、あるいはプラグインを完全に排除する、という 3 つです。

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 もブートストラップに失敗することがあります。--skip-plugins グローバルパラメータは、そのコマンドの実行中、すべてのプラグイン(または指定したリスト)の読み込みを止めます。

wp plugin deactivate broken-plugin --skip-plugins

スキップしても保存された状態は変わりません。この方法でスキップされたプラグインは依然として有効として報告されます。得られるのは、無効化処理を走らせられる程度に動作するブートストラップだけです。また、致命的なコードが mu-plugin にある場合には役に立ちません。WP-CLI はいずれにせよ mu-plugins を読み込むためです。多くの保守担当者が最初に WP-CLI を必要とするのはこの瞬間であり、FTP クライアントを開いてプラグインディレクトリをリネームするより手早く済みます。管理画面が戻ったら、診断にあたる残り半分の作業は、OpenReplay の WordPress ホワイトスクリーン・オブ・デスに関する記事でカバーされています。

wp eval による単発の PHP 実行

wp eval は、完全に読み込まれた WordPress インストールに対して任意の PHP を実行します。ダッシュボードに相当するものはなく、そこが要点です。プラグインが登録したあらゆる関数、あらゆるオプション、あらゆるクエリが 1 行で済むようになります。

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

これより長いものはファイルに置くべきです。wp eval-file は PHP ファイルのパスを受け取り、追加の位置引数を $args としてスクリプトに渡します。--skip-wordpress を渡せば WordPress のブートストラップを完全にスキップします。コードはメソッド内で実行されるため、触れるグローバル変数ごとに global 行が必要です。

wp eval にドライランはありません。スクリプトが書き込むものは、そのまま書き込まれます。エクスポートを取っておくべき最も明快な理由がこれです。

リモートホストに対して WP-CLI を実行するには?

ここからが、このツールが単なる便利機能ではなくなる領域です。WP-CLI の --ssh グローバルパラメータは --ssh=[<scheme>:][<user>@]<host>[:<port>][<path>] という形式を取り、コマンドを ssh バイナリに渡すことで動作します。ssh はそれを向こう側にある WP-CLI へ渡します。

wp --ssh=dev_user@example.com:2222~/webapps/production plugin list
構成要素ここでの値省略時のデフォルト
scheme(省略)ssh
userdev_user現在のシステムユーザー
hostexample.com必須
port222222
path~/webapps/productionssh ユーザーのホームディレクトリ

path には区切り文字が入りません。ポートの直後に、ポートを省略した場合はホストの直後に続けて書き、/ または ~ で始めてください。ssh のほか、ハンドブックの設定リファレンスには vagrant、docker、docker-compose、docker-compose-run が記載されています。最後のものは、すでに起動中のコンテナを使うのではなく、docker-compose run で新しいコンテナを起動します。

絶対的な前提条件が 1 つあります。リモートサーバーには独自の WP-CLI が必要で、しかもそれが wp で応答しなければなりません。手動でログインしたときには動く wp でも、--ssh 経由では command-not-found が返ってくることがあります。リモートコマンドを実行するシェルは、同じ $PATH を構築しないためです。多くのディストリビューションは ~/.bashrc の冒頭付近に、シェルが対話的でない場合に早期終了するガードを置いており、その下にある PATH の行は実行されません。zsh の場合、この状況では ~/.zshrc ではなく ~/.zshenv が読み込まれます。対処法は、リモート側で $PATH を明示的に設定することです。

あの文字列を 2 回入力すれば十分な理由になります。プロジェクトの 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

エイリアスグループは 1 回の呼び出しを複数のインストールに対して実行します。これが、クライアントサイト 10 件を保守することと、ダッシュボードに 10 回ログインすることの違いです。カレントディレクトリにないローカルインストールに対しては、--path グローバルパラメータで WordPress ファイルの場所を WP-CLI に伝えます。

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

次に進むべきところ

ここから持ち帰る価値のある考えは 1 つです。WP-CLI は WordPress のデータ構造を理解しており、mysql や phpMyAdmin は理解していない。だからこそドメイン変更は wp search-replace の仕事であり、他のどこの仕事でもありません。次に予定している移行を 1 つ選び、--dry-run の行を書き、レポートを読み、そのフラグを外す前に wp db export を実行してください。上記のすべては、Return キーを押した瞬間に不可逆になります。

FAQ

wp search-replace はマルチサイトネットワーク内のすべてのサイトを更新しますか?

いいえ。WordPress 自身が登録しているテーブルに対して動作するため、マルチサイトでは --network を追加しない限り現在のサイトのテーブルのみが対象になります。プレフィックスに関わらず、また WordPress が認識しているかどうかに関わらず、データベース内のすべてのテーブルに到達するには --all-tables を使ってください。これは --network および --all-tables-with-prefix より優先されます。ネットワーク上では、WP-CLI が正しいサイトで起動するよう --url も追加してください。

なぜ WP-CLI は root での実行を拒否するのですか?

WP-CLI は root ユーザーを検出すると YIKES エラーで停止します。インストール内のすべて、自分が書いたわけではないプラグインやテーマも含めて、サーバーに対する root の権限範囲を引き継ぐことになるため、悪意あるコードが 1 つあればマシン全体を奪われかねません。--allow-root フラグはこのチェックをスキップし、root で動作するコンテナではしばしば必要になりますが、プロジェクトは推奨していません。代わりに、WordPress ファイルを所有するシステムユーザーとして実行してください。

エラー 'This does not seem to be a WordPress installation' は何を意味しますか?

WP-CLI が探した場所に WordPress コアファイルが見つからず、ブートストラップできなかったという意味です。wp-admin、wp-content、wp-includes を含むディレクトリからコマンドを実行するか、--path グローバルパラメータでインストール先を指定してください。値は --path=/var/www/html のように等号の形式で渡してください。スペース区切りの引数ではフラグに値が渡らず、同じエラーが繰り返されます。

WP-CLI は Windows で動作しますか?

WP-CLI は Linux、macOS、FreeBSD、Cygwin といった UNIX ライクな環境向けに作られており、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.