2026年8月4日

2026年8月4日

WP-CLIとGitHub ActionsでWordPressのCI/CDパイプラインを構築する方法

WordPress の CI/CD は、GitHub Actions で「コードチェック → サーバーへ転送 → WP-CLI で後処理」という流れを組むと、手作業の FTP アップロードをなくし、毎回同じ手順でデプロイできるようになります。この記事では、テーマやプラグインのリポジトリを例に、チェック用のジョブ、SSH と rsync によるデプロイ、WP-CLI のエイリアスを使ったリモート操作、デプロイ後の処理と切り戻しの考え方までを説明します。

パイプラインの全体像

ここで作るパイプラインは次の2段構成です。

  1. CI(チェック):プルリクエストと main ブランチへのプッシュのたびに、Composer の依存関係を入れて PHP_CodeSniffer(必要なら PHPUnit)を実行する
  2. CD(デプロイ):main へのプッシュでチェックが通ったときだけ、本番サーバーへ SSH で接続し、データベースのバックアップ、ファイル転送、WP-CLI による後処理を行う

リポジトリに含めるのは、自分たちが開発するテーマやプラグインのコードだけにするのが扱いやすい構成です。WordPress 本体、wp-config.php、wp-content/uploads はサーバー側で管理し、パイプラインからは触りません。wp-config.php にはデータベースのパスワードなどが含まれるため、リポジトリに入れないことが大前提です。

事前準備

デプロイ用の SSH 鍵とユーザー

CI から接続するための専用の SSH 鍵ペアを作り、公開鍵を本番サーバーのデプロイ用ユーザーに登録します。個人の鍵を流用すると、退職や鍵の更新のたびにパイプラインが止まり、漏えい時の影響範囲も大きくなります。デプロイ用ユーザーには、公開ディレクトリへの書き込みと wp の実行に必要な権限だけを与えます。

GitHub のシークレットに登録する

秘密鍵や接続先は、リポジトリの設定画面にある Actions 用のシークレットに登録します。この記事の例では次の名前を使います。

  • DEPLOY_SSH_KEY:デプロイ用の秘密鍵
  • DEPLOY_KNOWN_HOSTS:接続先サーバーのホスト鍵(手元で ssh-keyscan example.com を実行し、フィンガープリントを確認してから登録)
  • DEPLOY_USER、DEPLOY_HOST:接続ユーザー名とホスト名

本番用のシークレットは、GitHub の environment(環境)に紐づけて登録すると、承認者の設定やブランチの制限をかけられます。画面の項目名は変わることがあるため、GitHub のドキュメントで確認してください(2026年10月現在)。

コーディング規約の設定

チェック用に、composer require --dev wp-coding-standards/wpcs で WordPress Coding Standards を入れ、リポジトリ直下に phpcs.xml.dist を置いて対象ディレクトリを決めておきます。こうしておくと、CI でも手元でも vendor/bin/phpcs だけで同じチェックが走ります。

GitHub Actions のワークフロー

.github/workflows/deploy.yml として次のファイルを置きます。テーマ my-theme のリポジトリを /var/www/example.com の WordPress へ配置する例です。

name: CI/CD

on:
  pull_request:
  push:
    branches: [main]

jobs:
  check:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: shivammathur/setup-php@v2
        with:
          php-version: '8.3'
          tools: composer
          coverage: none

      - run: composer validate --strict
      - run: composer install --no-interaction --prefer-dist --no-progress
      - run: vendor/bin/phpcs

  deploy:
    needs: check
    if: github.event_name == 'push' && github.ref == 'refs/heads/main'
    runs-on: ubuntu-latest
    environment: production
    concurrency:
      group: deploy-production
      cancel-in-progress: false
    env:
      DEPLOY_USER: ${{ secrets.DEPLOY_USER }}
      DEPLOY_HOST: ${{ secrets.DEPLOY_HOST }}
      WP_PATH: /var/www/example.com
    steps:
      - uses: actions/checkout@v4

      - uses: shivammathur/setup-php@v2
        with:
          php-version: '8.3'
          tools: composer
          coverage: none

      - name: 本番用の依存関係を入れる
        run: composer install --no-dev --no-interaction --prefer-dist --optimize-autoloader

      - name: SSH の準備
        env:
          SSH_KEY: ${{ secrets.DEPLOY_SSH_KEY }}
          KNOWN_HOSTS: ${{ secrets.DEPLOY_KNOWN_HOSTS }}
        run: |
          mkdir -p ~/.ssh
          printf '%s\n' "$SSH_KEY" > ~/.ssh/id_deploy
          chmod 600 ~/.ssh/id_deploy
          printf '%s\n' "$KNOWN_HOSTS" > ~/.ssh/known_hosts

      - name: データベースをバックアップ
        run: |
          ssh -i ~/.ssh/id_deploy "$DEPLOY_USER@$DEPLOY_HOST" \
            "mkdir -p ~/backups && wp db export ~/backups/pre-deploy-${GITHUB_SHA}.sql --path=$WP_PATH"

      - name: テーマを転送
        run: |
          rsync -az --delete \
            --exclude='.git' --exclude='.github' --exclude='node_modules' --exclude='tests' \
            -e "ssh -i ~/.ssh/id_deploy" \
            ./ "$DEPLOY_USER@$DEPLOY_HOST:$WP_PATH/wp-content/themes/my-theme/"

      - name: WP-CLI で後処理
        run: |
          ssh -i ~/.ssh/id_deploy "$DEPLOY_USER@$DEPLOY_HOST" \
            "wp core update-db --path=$WP_PATH && wp cache flush --path=$WP_PATH"

      - name: 動作確認
        run: curl -fsS -o /dev/null https://example.com/

アクションのメジャーバージョン(@v4、@v2)は、各リポジトリで最新の推奨を確認してから使ってください。

設定のポイント

  • **シークレットは env 経由で渡す**:run の中に ${{ secrets.… }} を直接埋め込むより、環境変数として渡すほうが、シェルの解釈による事故を避けやすくなります。GitHub はログ上のシークレットの値を伏せ字にしますが、echo で出力するような書き方は避けます。
  • **--delete の範囲に注意**:rsync の --delete は、転送元にないファイルを転送先から消します。転送先をテーマのディレクトリに限定しているのはこのためです。WordPress のルートに向けて --delete を付けると、uploads や wp-config.php が消える恐れがあります。最初は --dry-run を付けて実行し、消える対象を確認してください。
  • **concurrency で同時デプロイを防ぐ**:続けてプッシュしたときにデプロイが並行して走ると、ファイルが混ざった状態になりえます。同じグループのジョブを順番に実行させます。
  • ホスト鍵を検証する:StrictHostKeyChecking=no でホスト鍵の確認を省く例を見かけますが、接続先のなりすましに気づけなくなります。known_hosts を登録して検証させます。

テストを追加したい場合、プラグインであれば wp scaffold plugin-tests でテスト用の雛形を作り、check ジョブに PHPUnit の実行を足す方法があります。テスト用のデータベースが必要になるため、最初は規約チェックだけで始め、慣れてから広げるのが現実的です。

WP-CLI のエイリアスでリモートを操作する

デプロイ後の確認や手動の運用作業では、WP-CLI のエイリアスを使うと ssh を毎回組み立てずに済みます。プロジェクト直下の wp-cli.yml に接続先を書きます。

# wp-cli.yml
@staging:
  ssh: deploy@staging.example.com/var/www/staging.example.com
@production:
  ssh: deploy@example.com/var/www/example.com
wp cli alias list
wp @staging plugin list --update=available
wp @production core version

エイリアスは手元の ssh コマンドを使って接続し、接続先の wp を実行します。そのため、接続先に WP-CLI がインストールされていること、手元の ~/.ssh/config や SSH エージェントで鍵が使える状態になっていることが前提です。CI で使う場合は、ランナーに WP-CLI を入れたうえで同じ設定を置けば、ワークフローの ssh ... "wp ..." を wp @production ... に置き換えられます。

@production を付けたコマンドは本番に直接作用します。wp search-replace などデータを書き換えるコマンドは、まず @staging で試し、本番では --dry-run で件数を確認してから実行してください。

デプロイ後に実行する WP-CLI コマンド

後処理は「毎回実行してよいもの」と「必要なときだけ実行するもの」に分けて考えます。

  • wp core update-db:WordPress 本体のデータベース更新を適用します。更新が不要なら何もしないので、毎回実行して問題ありません。マルチサイトでは --network を付けます。
  • wp cache flush:オブジェクトキャッシュを消します。ページキャッシュ系プラグインのキャッシュは別管理のことが多いため、各プラグインの WP-CLI コマンドや設定を確認します。
  • wp rewrite flush:カスタム投稿タイプやリライトルールを変更したときだけ実行します。毎回実行する必要はありません。

プラグインが独自にデータベースを更新する仕組みを持っている場合、その実行方法はプラグインごとに異なります。各プラグインのドキュメントを確認し、必要ならワークフローに追加します。

切り戻し(ロールバック)の考え方

デプロイで不具合が出たときに戻せる手段を、パイプラインを作る段階で決めておきます。

  • コードを戻す:問題のコミットを git revert して main にプッシュすれば、同じパイプラインで前の状態が配置されます。手順が普段のデプロイと同じなので、慌てているときでも間違えにくい方法です。
  • データベースを戻す:デプロイ前に書き出した pre-deploy-<コミットID>.sql を wp db import で戻せます。ただし、バックアップ以降に入った注文やコメントも消えるため、最後の手段と考えてください。
  • より短時間で戻したい場合:リリースごとにディレクトリを分け、シンボリックリンクを切り替える方式にすると、前のリリースへ数秒で戻せます。Deployer のようなデプロイツールがこの方式を提供しています。

本番に適用する前に、ステージング環境向けに同じワークフローを用意し、デプロイと切り戻しの両方を一度試しておくと、いざというときに慌てずに済みます。

まとめ

  • CI は PR とプッシュごとに composer install と phpcs を実行し、CD は main でチェックが通ったときだけ動かす
  • 秘密鍵や接続先は GitHub のシークレット(本番は environment)に登録し、env 経由で渡す。wp-config.php はリポジトリに入れない
  • rsync の --delete は転送先をテーマ・プラグインのディレクトリに限定し、最初は --dry-run で確認する
  • デプロイ前に wp db export、デプロイ後に wp core update-db と wp cache flush。wp rewrite flush は必要なときだけ
  • wp-cli.yml のエイリアス(@staging、@production)でリモート操作を簡単にし、切り戻し手順も事前に試しておく

お気軽にご相談ください

お見積りへ お問い合わせへ
▲