2026年6月2日

2026年6月2日

WordPressのCI/CDをGitHub Actionsで組む方法|PHPCS・PHPUnit・rsyncデプロイ

WordPressのテーマやプラグインをGitで管理しているなら、GitHub Actionsで「プッシュのたびに検査し、mainに入ったら本番へ反映する」流れを作れます。この記事では、PHPの構文チェック、WordPressコーディング規約(WPCS)のチェック、PHPUnitによるテスト、rsyncによるデプロイを、1つのワークフローファイルにまとめる手順を説明します。

対象は、テーマやプラグインのディレクトリ単位でリポジトリを作っている構成です。WordPress本体やアップロード済みの画像(wp-content/uploads)はリポジトリに入れず、デプロイでも触らない前提にしています。

全体の流れ

作るワークフローは2つのジョブで構成します。

ジョブ 動くタイミング 内容
test すべてのプッシュとプルリクエスト PHPの構文チェック、PHPCS(WPCS)、PHPUnit
deploy mainへのプッシュで、test が成功したときだけ rsyncでサーバーのテーマ(プラグイン)ディレクトリへ同期

deploy は needs: test で test の成功を条件にします。テストに失敗した変更は本番へ届きません。

準備1:リポジトリにWPCSを入れる

WordPressコーディング規約のチェックには、PHP_CodeSnifferとWordPress Coding Standards(WPCS)を使います。Composerで開発用の依存として追加します。

composer config allow-plugins.dealerdirect/phpcodesniffer-composer-installer true
composer require --dev wp-coding-standards/wpcs:"^3.0"

1行目は、WPCSと一緒に入るComposerプラグインの実行を許可する設定です。これを入れないと、規約の登録が行われません。2026年10月時点でWPCSの最新は3.x系です。

検査する範囲と規約は、リポジトリ直下の .phpcs.xml.dist に書いておきます。CIでもローカルでも同じ設定で動きます。

<?xml version="1.0"?>
<ruleset name="My Theme">
    <file>.</file>
    <exclude-pattern>/vendor/*</exclude-pattern>
    <exclude-pattern>/node_modules/*</exclude-pattern>
    <exclude-pattern>/tests/*</exclude-pattern>

    <arg name="extensions" value="php"/>
    <arg value="sp"/>

    <rule ref="WordPress"/>
</ruleset>

既存のコードに初めて適用すると大量の指摘が出ることがあります。まずローカルで vendor/bin/phpcs を実行し、vendor/bin/phpcbf で自動修正できるものを直してから、CIに組み込むと進めやすくなります。

準備2:PHPUnitのテスト一式を作る(プラグインの場合)

プラグインであれば、WP-CLIの wp scaffold plugin-tests でテストの雛形を作れます。--ci=github を付けると、GitHub Actions用のワークフロー(.github/workflows/testing.yml)も生成されます。

wp scaffold plugin-tests my-plugin --ci=github

生成されるおもなファイルは次のとおりです。

  • phpunit.xml.dist:PHPUnitの設定
  • bin/install-wp-tests.sh:WordPressのテストライブラリとテスト用データベースを用意するスクリプト
  • tests/bootstrap.php、tests/test-sample.php:テストの起動処理とサンプル

WordPressのテストライブラリはPHPUnitとYoast PHPUnit Polyfillsを必要とします。どちらもComposerで開発用の依存に加えておきます(2026年10月時点で、WordPress本体のテストはPolyfillsの1.x系とPHPUnit 9系の組み合わせで動いています)。

composer require --dev phpunit/phpunit:"^9.6" yoast/phpunit-polyfills:"^1.1"

生成されたワークフローをそのまま使ってもかまいません。この記事では、構文チェックやデプロイと同じファイルにまとめる形で書き直します。テストの書き方はWordPressのユニットテストをPHPUnitで書く方法で扱っています。テーマのようにテストを用意しない場合は、後述のワークフローからPHPUnitの部分を外してください。

準備3:デプロイ用のSSH鍵とシークレットを登録する

デプロイには、本番サーバーへSSHで接続できる専用の鍵を使います。個人の鍵を流用せず、デプロイ専用のユーザーと鍵を作り、書き込める範囲をテーマ(プラグイン)のディレクトリに絞っておくと、鍵が漏れたときの被害を小さくできます。

# 手元で鍵を作る(パスフレーズなし。CIから使うため)
ssh-keygen -t ed25519 -f deploy_key -C "github-actions-deploy" -N ""

# 公開鍵をサーバーのデプロイ用ユーザーに登録
ssh-copy-id -i deploy_key.pub deploy@example.com

# サーバーのホスト鍵を取得し、内容を目で確かめてから登録する
ssh-keyscan -t ed25519 example.com

GitHubのリポジトリで「Settings」→「Secrets and variables」→「Actions」を開き、次の値を登録します。秘密にすべき値はSecrets、そうでない値はVariablesに分けます。

種類 名前 中身
Secret SSH_PRIVATE_KEY deploy_key(秘密鍵)の内容
Secret SSH_KNOWN_HOSTS ssh-keyscan で確かめたホスト鍵の行
Variable DEPLOY_HOST example.com
Variable DEPLOY_USER deploy
Variable DEPLOY_PATH /var/www/html/wp-content/themes/my-theme

ワークフローの中で ssh-keyscan を実行して接続先を自動で信頼させる書き方を見かけますが、その時点で接続先が偽物でも気づけません。ホスト鍵は事前に確かめた値をシークレットに入れておきます。シークレットの扱いの詳細はGitHub Actionsのシークレット管理方法を参照してください。

ワークフローファイルを書く

.github/workflows/ci-cd.yml を作り、次の内容を書きます。echo でファイルに1行ずつ追記するのではなく、エディタでYAMLとして書いてください。YAMLはインデント(半角スペース)で構造を表すため、追記方式では崩れやすくなります。

name: CI/CD

on:
  push:
    branches: [main]
  pull_request:

jobs:
  test:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        php: ['8.2', '8.3', '8.4']
    services:
      mysql:
        image: mysql:8.0
        env:
          MYSQL_ROOT_PASSWORD: root
          MYSQL_DATABASE: wordpress_test
        ports:
          - 3306:3306
        options: >-
          --health-cmd="mysqladmin ping -h 127.0.0.1"
          --health-interval=10s
          --health-timeout=5s
          --health-retries=5
    steps:
      - uses: actions/checkout@v7

      - uses: shivammathur/setup-php@v2
        with:
          php-version: ${{ matrix.php }}
          tools: composer
          coverage: none

      - name: Install dependencies
        run: composer install --no-progress --prefer-dist

      - name: PHP syntax check
        run: find . -path ./vendor -prune -o -name '*.php' -print0 | xargs -0 -n1 php -l

      - name: WordPress Coding Standards
        run: vendor/bin/phpcs

      - name: Install WordPress test suite
        run: bash bin/install-wp-tests.sh wordpress_test root root 127.0.0.1 latest true

      - name: PHPUnit
        env:
          WP_TESTS_PHPUNIT_POLYFILLS_PATH: ${{ github.workspace }}/vendor/yoast/phpunit-polyfills
        run: vendor/bin/phpunit

  deploy:
    needs: test
    if: github.event_name == 'push' && github.ref == 'refs/heads/main'
    runs-on: ubuntu-latest
    environment: production
    concurrency: production
    steps:
      - uses: actions/checkout@v7

      - name: Set up SSH
        env:
          SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }}
          SSH_KNOWN_HOSTS: ${{ secrets.SSH_KNOWN_HOSTS }}
        run: |
          install -m 700 -d ~/.ssh
          printf '%s\n' "$SSH_PRIVATE_KEY" > ~/.ssh/deploy_key
          chmod 600 ~/.ssh/deploy_key
          printf '%s\n' "$SSH_KNOWN_HOSTS" > ~/.ssh/known_hosts

      - name: Deploy with rsync
        env:
          DEPLOY_HOST: ${{ vars.DEPLOY_HOST }}
          DEPLOY_USER: ${{ vars.DEPLOY_USER }}
          DEPLOY_PATH: ${{ vars.DEPLOY_PATH }}
        run: |
          rsync -az --delete \
            --exclude-from=.deployignore \
            -e "ssh -i ~/.ssh/deploy_key" \
            ./ "${DEPLOY_USER}@${DEPLOY_HOST}:${DEPLOY_PATH}/"

ポイントを補足します。

  • matrix.php で、複数のPHPバージョンで同じ検査を並行して実行します。並べるバージョンは、本番サーバーと、サポートしたい範囲に合わせて決めてください(2026年10月時点の例です)。
  • services.mysql は、PHPUnitで使うテスト用データベースです。テストを使わない場合は、services と最後の2ステップを削除します。
  • 構文チェックの行は、vendor を除くすべての .php ファイルに php -l を実行します。1つでもエラーがあれば xargs が0以外で終了し、ジョブが失敗します。
  • bin/install-wp-tests.sh の引数は、データベース名・ユーザー・パスワード・ホスト・WordPressのバージョン・データベース作成を省くかどうかの順です。データベースはMySQLのサービス側(MYSQL_DATABASE)で作っているため、最後を true にしています。
  • WP_TESTS_PHPUNIT_POLYFILLS_PATH は、WordPressのテストライブラリにPolyfillsの場所を教えるための環境変数です。wp scaffold が作る tests/bootstrap.php がこの値を読み取ります。
  • deploy の if で、プルリクエストでは動かず、mainへのプッシュのときだけ動くようにしています。
  • concurrency: production で、デプロイが同時に2本走らないようにしています。
  • シークレットは env で環境変数に渡してからスクリプトで使います。${{ secrets.… }} を run の中に直接書くより、値がシェルの構文として解釈される心配が少なくなります。

本番に送らないファイルを決める

rsync --delete は、リポジトリに無いファイルをサーバー側から削除します。送らないファイルを .deployignore に書いておきます。ここに書いたパスは送信の対象外になり、サーバー側に同名のファイルがあっても削除されません。

.git/
.github/
tests/
bin/
vendor/
node_modules/
.phpcs.xml.dist
phpunit.xml.dist
composer.json
composer.lock
.deployignore

テーマやプラグインが実行時にComposerのライブラリを必要とする場合は、vendor/ を除外せず、デプロイジョブの中で composer install --no-dev --optimize-autoloader を実行してから送ってください。開発用のPHPCSやPHPUnitまで本番に送らずに済みます。

初回は、rsyncに --dry-run を付けたステップで、送信・削除されるファイルの一覧を確かめてから本番を動かすと安全です。

本番デプロイの前に承認を挟む

environment: production を指定したジョブは、リポジトリの「Settings」→「Environments」で作った production 環境の保護ルールに従います。「Required reviewers」を設定すると、指定した人が承認するまでデプロイジョブは待機します。環境の保護ルールが使えるかどうかは、リポジトリの公開・非公開とGitHubのプランによって異なります。使えない場合は、ブランチ保護でmainへの直接プッシュを禁止し、プルリクエストのレビューを必須にする方法で代わりにできます。

動作を確かめる

  1. 作業用ブランチでわざと構文エラーを入れてプッシュし、プルリクエストの「Checks」で test ジョブが失敗することを確かめる
  2. 修正してプッシュし、test が成功し、deploy は動かない(プルリクエストなので)ことを確かめる
  3. mainへマージし、deploy が動いてサーバーのファイルが更新されたことを確かめる

デプロイ後にページキャッシュが残って変更が見えない場合は、キャッシュ系プラグインの機能か、サーバーで wp cache flush(オブジェクトキャッシュの削除)を実行して確かめます。

つまずきやすい点

  • Permission denied (publickey):公開鍵がデプロイ用ユーザーの ~/.ssh/authorized_keys に入っているか、秘密鍵のシークレットに改行まで含めて貼ったかを確かめる
  • Host key verification failed:SSH_KNOWN_HOSTS の行が、接続先のホスト名(またはIPアドレス)と一致しているかを確かめる
  • rsyncの権限エラー:デプロイ用ユーザーが DEPLOY_PATH に書き込めるか、サーバー側にrsyncが入っているかを確かめる
  • PHPCSの指摘が多すぎてマージできない:既存コードの指摘を phpcbf で減らすか、.phpcs.xml.dist で除外するルールを明示する

まとめ

  • テストとデプロイを別ジョブにし、needs でテストの成功をデプロイの条件にする
  • WPCSはComposerで入れ、.phpcs.xml.dist でCIとローカルの設定をそろえる
  • プラグインのテストは wp scaffold plugin-tests --ci=github で雛形を作れる
  • SSHの秘密鍵とホスト鍵はシークレットに入れ、デプロイ専用の鍵とユーザーを使う
  • rsync --delete は除外ファイルを決め、初回は --dry-run で確かめる

関連記事:

お気軽にご相談ください

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