T-CREATOR

CI/CD で更新を自動化:GitHub Actions と WordPress の安全デプロイ

CI/CD で更新を自動化:GitHub Actions と WordPress の安全デプロイ

WordPress サイトの更新作業、手動でやっていると時間がかかるだけでなく、ヒューマンエラーのリスクも高まります。GitHub Actions を使えば、コードの変更から本番環境へのデプロイまでを自動化でき、安全かつ効率的な運用が実現できるんです。

この記事では、GitHub Actions を使った WordPress の CI/CD パイプラインの構築方法を、初心者の方にもわかりやすく解説します。テスト自動化からステージング環境での検証、本番デプロイまで、段階的に進めていきましょう。

背景

WordPress 開発における従来の課題

WordPress は世界中で広く使われている CMS ですが、開発・運用面では手作業が多く残っています。FTP でファイルをアップロードしたり、本番環境で直接編集したりする運用は、以下のようなリスクを抱えているんですね。

  • コードの変更履歴が残らない
  • 複数人での開発時に競合が発生しやすい
  • テスト環境がなく、本番で直接確認する
  • デプロイ作業のミスで本番サイトが停止する

CI/CD がもたらす価値

CI/CD(継続的インテグレーション/継続的デリバリー)は、これらの課題を解決する開発手法です。コードの変更を自動でテストし、安全にデプロイする仕組みを構築することで、開発スピードと品質の両立が可能になります。

以下の図は、従来の手動デプロイと CI/CD を使った自動デプロイの違いを示しています。

mermaidflowchart TD
  subgraph manual["従来の手動デプロイ"]
    dev1["開発者がコード編集"] --> ftp1["FTP で<br/>ファイルアップロード"]
    ftp1 --> prod1["本番環境へ<br/>直接反映"]
    prod1 --> error1["エラー発生時は<br/>手動で修正"]
  end

  subgraph cicd["CI/CD 自動デプロイ"]
    dev2["開発者が<br/>Git にプッシュ"] --> test["自動テスト実行"]
    test --> stage["ステージング環境<br/>へデプロイ"]
    stage --> check["動作確認"]
    check --> deploy["本番環境へ<br/>安全にデプロイ"]
  end

図で理解できる要点:

  • 従来の手動デプロイは本番環境へ直接反映されるため、エラーが即座にユーザーに影響します
  • CI/CD では段階的な検証を経るため、問題を事前に発見できます
  • 自動化により人的ミスが減り、デプロイの安全性が向上します

課題

WordPress サイトに CI/CD を導入する際には、いくつかの技術的課題があります。

WordPress 特有の構造

WordPress はテーマ、プラグイン、アップロードファイル、データベースなど、複数の要素で構成されています。これらのうち、どの部分をバージョン管理し、どの部分をデプロイ対象にするか判断が必要です。

データベースとの同期

WordPress はコンテンツをデータベースに保存するため、コードだけをデプロイしても完全な環境の再現はできません。ステージング環境と本番環境のデータベースをどう扱うかが重要になります。

セキュリティ設定の管理

wp-config.php に含まれるデータベース接続情報や認証キーは、Git リポジトリに直接コミットすると漏洩のリスクがあります。環境ごとに異なる設定を安全に管理する仕組みが必要ですね。

以下の図は、WordPress の構成要素とデプロイ対象の関係を示しています。

mermaidflowchart LR
  subgraph wp["WordPress 構成要素"]
    core["WordPress<br/>コア"]
    theme["テーマ"]
    plugin["プラグイン"]
    upload["アップロード<br/>ファイル"]
    db[("データベース")]
    config["wp-config.php"]
  end

  subgraph git["Git 管理対象"]
    theme --> git_theme["テーマ"]
    plugin --> git_plugin["プラグイン"]
    config -.-> git_config["環境変数<br/>テンプレート"]
  end

  subgraph deploy["デプロイ対象"]
    git_theme --> deploy_theme["テーマ"]
    git_plugin --> deploy_plugin["プラグイン"]
  end

  subgraph env["環境固有"]
    upload --> env_upload["アップロード"]
    db --> env_db["データベース"]
    config --> env_config["設定ファイル"]
  end

図で理解できる要点:

  • テーマとプラグインは Git で管理し、デプロイ対象に含めます
  • アップロードファイルとデータベースは環境固有のため、デプロイ対象外です
  • wp-config.php は環境変数を使って各環境で動的に生成します

解決策

GitHub Actions を使った WordPress の CI/CD パイプラインを構築することで、上記の課題を解決できます。

パイプラインの全体設計

効果的な CI/CD パイプラインには、以下の要素が必要です。

  • ソースコード管理: Git でテーマとプラグインを管理
  • 自動テスト: コードの品質を継続的にチェック
  • ステージング環境: 本番環境と同じ構成でテスト
  • 本番デプロイ: 承認プロセスを経た安全なデプロイ

以下の図は、GitHub Actions を使った WordPress CI/CD パイプラインの全体フローを示しています。

mermaidflowchart TD
  push["開発者が<br/>Git にプッシュ"] --> trigger["GitHub Actions<br/>トリガー"]
  trigger --> lint["コードチェック<br/>(PHP_CodeSniffer)"]
  lint --> unit["ユニットテスト<br/>(PHPUnit)"]
  unit -->|success| branch{ブランチ判定}

  branch -->|develop| stage["ステージング環境<br/>へデプロイ"]
  stage --> e2e["E2E テスト<br/>(Playwright)"]

  branch -->|main| approval["手動承認<br/>(GitHub Environment)"]
  approval --> prod["本番環境へ<br/>デプロイ"]

  unit -->|failure| notify["Slack へ<br/>エラー通知"]
  e2e -->|failure| notify
  prod --> complete["デプロイ完了<br/>通知"]

図で理解できる要点:

  • develop ブランチへのプッシュは自動的にステージング環境へデプロイされます
  • main ブランチへのマージは手動承認を経て本番環境へデプロイされます
  • 各段階でテストが実行され、失敗時は通知が送られます

リポジトリ構成

WordPress プロジェクトの Git リポジトリは、以下のような構成が推奨されます。

perl├── .github/
│   └── workflows/
│       ├── deploy-staging.yml
│       └── deploy-production.yml
├── themes/
│   └── my-theme/
│       ├── functions.php
│       ├── style.css
│       └── ...
├── plugins/
│   └── my-plugin/
│       ├── my-plugin.php
│       └── ...
├── tests/
│   ├── unit/
│   └── e2e/
├── .env.example
├── .gitignore
└── composer.json

環境変数の管理

セキュリティ情報は GitHub の Secrets 機能で管理します。各環境ごとに必要な変数を登録しましょう。

#変数名説明
1STAGING_HOSTステージング環境のホスト名staging.example.com
2STAGING_USERSSH ユーザー名deploy-user
3STAGING_KEYSSH 秘密鍵(秘密鍵の内容)
4PRODUCTION_HOST本番環境のホスト名example.com
5PRODUCTION_USERSSH ユーザー名deploy-user
6PRODUCTION_KEYSSH 秘密鍵(秘密鍵の内容)

具体例

実際に GitHub Actions を使った WordPress の CI/CD パイプラインを構築していきます。

ステップ 1: ワークフローファイルの作成

まず、ステージング環境へのデプロイワークフローを作成します。.github​/​workflows​/​deploy-staging.yml を作成しましょう。

yamlname: Deploy to Staging

# トリガー設定:develop ブランチへのプッシュで実行
on:
  push:
    branches:
      - develop

jobs:
  test:
    name: Run Tests
    runs-on: ubuntu-latest

このワークフローは develop ブランチへのプッシュをトリガーとして実行されます。

次に、テスト環境のセットアップを定義します。

yamlsteps:
  # リポジトリのコードをチェックアウト
  - name: Checkout code
    uses: actions/checkout@v4

  # PHP 環境のセットアップ
  - name: Setup PHP
    uses: shivammathur/setup-php@v2
    with:
      php-version: '8.2'
      extensions: mbstring, xml, mysqli
      tools: composer

PHP 8.2 と必要な拡張機能をインストールしています。WordPress の動作に必要な mbstringxmlmysqli を含めます。

続いて、依存関係のインストールとコードチェックを実行します。

yaml# Composer 依存関係のインストール
- name: Install dependencies
  run: composer install --no-dev --optimize-autoloader

# PHP コードスタイルチェック
- name: Run PHP_CodeSniffer
  run: vendor/bin/phpcs --standard=WordPress themes/my-theme

# ユニットテストの実行
- name: Run PHPUnit
  run: vendor/bin/phpunit tests/unit

PHP_CodeSniffer で WordPress コーディング規約に準拠しているかチェックし、PHPUnit でユニットテストを実行します。

ステップ 2: デプロイジョブの設定

テストが成功したら、ステージング環境へデプロイするジョブを追加します。

yamldeploy:
  name: Deploy to Staging
  runs-on: ubuntu-latest
  needs: test # test ジョブが成功したら実行

  steps:
    # リポジトリのコードをチェックアウト
    - name: Checkout code
      uses: actions/checkout@v4

needs: test により、テストジョブが成功した場合のみデプロイが実行されます。

SSH 接続を設定し、rsync でファイルを転送します。

yaml# SSH キーのセットアップ
- name: Setup SSH
  run: |
    mkdir -p ~/.ssh
    echo "${{ secrets.STAGING_KEY }}" > ~/.ssh/id_rsa
    chmod 600 ~/.ssh/id_rsa
    ssh-keyscan -H ${{ secrets.STAGING_HOST }} >> ~/.ssh/known_hosts

# rsync でファイルを転送
- name: Deploy files
  run: |
    rsync -avz --delete \
      --exclude='.git*' \
      --exclude='node_modules' \
      --exclude='tests' \
      themes/my-theme/ \
      ${{ secrets.STAGING_USER }}@${{ secrets.STAGING_HOST }}:/var/www/html/wp-content/themes/my-theme/

rsync コマンドで、テーマファイルをステージング環境へ転送します。--exclude で不要なファイルを除外しています。

デプロイ後、E2E テストを実行して動作確認を行います。

yaml# E2E テストの実行
- name: Run E2E Tests
  run: |
    npx playwright install --with-deps
    npx playwright test tests/e2e
  env:
    BASE_URL: https://${{ secrets.STAGING_HOST }}

Playwright を使って、実際にブラウザでサイトの動作を確認します。

ステップ 3: 本番デプロイワークフローの作成

次に、本番環境へのデプロイワークフローを作成します。.github​/​workflows​/​deploy-production.yml を作成しましょう。

yamlname: Deploy to Production

# トリガー設定:main ブランチへのプッシュで実行
on:
  push:
    branches:
      - main

jobs:
  deploy:
    name: Deploy to Production
    runs-on: ubuntu-latest
    # 本番環境の設定(手動承認が必要)
    environment:
      name: production
      url: https://${{ secrets.PRODUCTION_HOST }}

environment: production を設定することで、GitHub の Environment Protection Rules により手動承認が必要になります。

本番デプロイの手順は、ステージングとほぼ同じですが、より慎重に進めます。

yamlsteps:
  - name: Checkout code
    uses: actions/checkout@v4

  # バックアップの作成
  - name: Create backup
    run: |
      ssh ${{ secrets.PRODUCTION_USER }}@${{ secrets.PRODUCTION_HOST }} \
        "tar -czf /backups/theme-$(date +%Y%m%d-%H%M%S).tar.gz \
        /var/www/html/wp-content/themes/my-theme/"

デプロイ前に、既存のテーマファイルをバックアップします。万が一問題が発生した場合に、すぐにロールバックできるようにするためです。

本番環境へのファイル転送を実行します。

yaml- name: Setup SSH
  run: |
    mkdir -p ~/.ssh
    echo "${{ secrets.PRODUCTION_KEY }}" > ~/.ssh/id_rsa
    chmod 600 ~/.ssh/id_rsa
    ssh-keyscan -H ${{ secrets.PRODUCTION_HOST }} >> ~/.ssh/known_hosts

- name: Deploy files
  run: |
    rsync -avz --delete \
      --exclude='.git*' \
      --exclude='node_modules' \
      --exclude='tests' \
      themes/my-theme/ \
      ${{ secrets.PRODUCTION_USER }}@${{ secrets.PRODUCTION_HOST }}:/var/www/html/wp-content/themes/my-theme/

ステージングと同じ rsync コマンドを使いますが、本番環境への接続情報を使用します。

デプロイ完了後、Slack へ通知を送ります。

yaml# デプロイ完了通知
- name: Notify deployment
  uses: slackapi/slack-github-action@v1
  with:
    payload: |
      {
        "text": "本番環境へのデプロイが完了しました",
        "blocks": [
          {
            "type": "section",
            "text": {
              "type": "mrkdwn",
              "text": "✅ 本番環境へのデプロイが完了しました\n*URL*: https://${{ secrets.PRODUCTION_HOST }}"
            }
          }
        ]
      }
  env:
    SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK }}

ステップ 4: Environment Protection Rules の設定

GitHub リポジトリで本番環境の保護ルールを設定します。

  1. リポジトリの SettingsEnvironments へ移動
  2. New environment をクリックし、production という名前で作成
  3. Deployment protection rules で以下を設定
    • Required reviewers: デプロイを承認できるユーザーを指定
    • Wait timer: デプロイ前の待機時間(オプション)

これにより、main ブランチへのマージ後、指定されたレビュワーが承認するまでデプロイが実行されなくなります。

ステップ 5: テストファイルの作成

最後に、ワークフローで実行するテストファイルを作成します。まず、PHPUnit のユニットテストを作成しましょう。

php<?php
/**
 * テーマ関数のユニットテスト
 */

namespace Tests\Unit;

use PHPUnit\Framework\TestCase;

class ThemeFunctionsTest extends TestCase
{
    /**
     * カスタム関数が正しく動作するかテスト
     */
    public function test_custom_excerpt_length()
    {
        // WordPress のコア関数をモック
        $this->assertEquals(50, custom_excerpt_length(999));
    }
}

次に、Playwright を使った E2E テストを作成します。tests​/​e2e​/​home.spec.ts を作成しましょう。

typescriptimport { test, expect } from '@playwright/test';

// ホームページの表示テスト
test('ホームページが正しく表示される', async ({ page }) => {
  // ホームページへアクセス
  await page.goto(
    process.env.BASE_URL || 'http://localhost'
  );

  // タイトルが正しく表示されているか確認
  await expect(page).toHaveTitle(/サイト名/);

  // メインコンテンツが表示されているか確認
  const content = page.locator('main');
  await expect(content).toBeVisible();
});

このテストは、サイトのホームページが正しく表示されることを確認します。

記事詳細ページのテストも追加しましょう。

typescript// 記事詳細ページのテスト
test('記事詳細ページが正しく表示される', async ({
  page,
}) => {
  await page.goto(`${process.env.BASE_URL}/sample-post/`);

  // 記事タイトルが表示されているか
  const title = page.locator('h1.entry-title');
  await expect(title).toBeVisible();

  // 記事本文が表示されているか
  const content = page.locator('.entry-content');
  await expect(content).toBeVisible();

  // コメントフォームが表示されているか
  const commentForm = page.locator('#commentform');
  await expect(commentForm).toBeVisible();
});

エラー対処例

CI/CD パイプラインの運用中に発生しやすいエラーと解決方法を紹介します。

エラー 1: SSH 接続エラー

エラーコード: Permission denied (publickey)

エラーメッセージ:

javaPermission denied (publickey).
rsync: connection unexpectedly closed (0 bytes received so far) [sender]
rsync error: unexplained error (code 255) at io.c(235) [sender=3.2.3]

発生条件:

  • SSH 秘密鍵が GitHub Secrets に正しく登録されていない
  • サーバー側の ~​/​.ssh​/​authorized_keys に公開鍵が登録されていない
  • 秘密鍵のパーミッションが正しくない

解決方法:

  1. SSH キーペアを再生成する
bash# SSH キーペアを生成(パスフレーズなし)
ssh-keygen -t rsa -b 4096 -C "deploy@example.com" -f ~/.ssh/deploy_key -N ""
  1. 公開鍵をサーバーに登録する
bash# 公開鍵をサーバーにコピー
ssh-copy-id -i ~/.ssh/deploy_key.pub user@server.example.com
  1. 秘密鍵を GitHub Secrets に登録する
bash# 秘密鍵の内容を表示(これを GitHub Secrets にコピー)
cat ~/.ssh/deploy_key

GitHub リポジトリの SettingsSecrets and variablesActions から、STAGING_KEY または PRODUCTION_KEY という名前で秘密鍵を登録します。

エラー 2: PHPUnit テストの失敗

エラーコード: Error: Class 'WP_UnitTestCase' not found

エラーメッセージ:

vbnetPHP Fatal error:  Class 'WP_UnitTestCase' not found in /tests/unit/ThemeFunctionsTest.php on line 10

発生条件:

  • WordPress テスト環境がセットアップされていない
  • composer.json に WordPress テストライブラリが含まれていない

解決方法:

  1. composer.json に WordPress テストライブラリを追加する
json{
  "require-dev": {
    "phpunit/phpunit": "^9.0",
    "yoast/phpunit-polyfills": "^1.0",
    "wp-phpunit/wp-phpunit": "^6.0"
  }
}
  1. 依存関係をインストールする
bashcomposer install
  1. phpunit.xml を作成し、WordPress テスト環境を設定する
xml<?xml version="1.0"?>
<phpunit
    bootstrap="tests/bootstrap.php"
    colors="true">
    <testsuites>
        <testsuite name="unit">
            <directory>tests/unit</directory>
        </testsuite>
    </testsuites>
</phpunit>

エラー 3: Playwright テストのタイムアウト

エラーコード: Timeout 30000ms exceeded

エラーメッセージ:

markdownError: Timeout 30000ms exceeded.
=========================== logs ===========================
waiting for locator('h1.entry-title')
============================================================

発生条件:

  • サイトの読み込みが遅い
  • セレクタが間違っている
  • JavaScript エラーでページが正しくレンダリングされていない

解決方法:

  1. タイムアウト時間を延長する
typescript// テストファイルで個別にタイムアウトを設定
test('記事詳細ページが正しく表示される', async ({
  page,
}) => {
  // タイムアウトを 60 秒に設定
  test.setTimeout(60000);

  await page.goto(`${process.env.BASE_URL}/sample-post/`);
  // ...
});
  1. セレクタを確認する
typescript// より具体的なセレクタを使用
const title = page.locator('article h1.entry-title');
await expect(title).toBeVisible({ timeout: 10000 });
  1. ページの読み込みを待つ
typescript// ネットワークアイドルを待つ
await page.goto(`${process.env.BASE_URL}/sample-post/`, {
  waitUntil: 'networkidle',
});

運用のベストプラクティス

CI/CD パイプラインを効果的に運用するためのポイントをまとめます。

#項目推奨事項理由
1ブランチ戦略main(本番)、develop(ステージング)、feature​/​*(機能開発)環境ごとに明確に分離できる
2コミット頻度小さな単位で頻繁にコミット問題の特定が容易になる
3テストカバレッジ重要な機能は必ずテストを作成リグレッションを防げる
4デプロイタイミングステージング:自動、本番:手動承認後本番環境の安全性を確保
5バックアップデプロイ前に必ず実施ロールバックが可能
6監視デプロイ後のエラーログを確認問題の早期発見

まとめ

GitHub Actions を使った WordPress の CI/CD パイプラインは、開発効率と品質の両立を実現する強力な手法です。

この記事では、以下の内容を解説しました。

  • WordPress 開発における従来の課題と CI/CD の価値
  • GitHub Actions を使ったパイプラインの設計方法
  • ステージング環境と本番環境へのデプロイワークフロー
  • テストの自動化と Environment Protection Rules の活用
  • よくあるエラーとその対処方法

最初は設定が複雑に感じるかもしれませんが、一度構築してしまえば、コードの変更から本番反映までが自動化され、安心して開発に集中できます。小さなプロジェクトから始めて、徐々にテストや監視を追加していくのがおすすめです。

ぜひ、あなたの WordPress プロジェクトにも CI/CD を導入して、より安全で効率的な開発フローを実現してください。

関連リンク