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 機能で管理します。各環境ごとに必要な変数を登録しましょう。
# | 変数名 | 説明 | 例 |
---|---|---|---|
1 | STAGING_HOST | ステージング環境のホスト名 | staging.example.com |
2 | STAGING_USER | SSH ユーザー名 | deploy-user |
3 | STAGING_KEY | SSH 秘密鍵 | (秘密鍵の内容) |
4 | PRODUCTION_HOST | 本番環境のホスト名 | example.com |
5 | PRODUCTION_USER | SSH ユーザー名 | deploy-user |
6 | PRODUCTION_KEY | SSH 秘密鍵 | (秘密鍵の内容) |
具体例
実際に 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 の動作に必要な mbstring
、xml
、mysqli
を含めます。
続いて、依存関係のインストールとコードチェックを実行します。
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 リポジトリで本番環境の保護ルールを設定します。
- リポジトリの Settings → Environments へ移動
- New environment をクリックし、
production
という名前で作成 - 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
に公開鍵が登録されていない - 秘密鍵のパーミッションが正しくない
解決方法:
- SSH キーペアを再生成する
bash# SSH キーペアを生成(パスフレーズなし)
ssh-keygen -t rsa -b 4096 -C "deploy@example.com" -f ~/.ssh/deploy_key -N ""
- 公開鍵をサーバーに登録する
bash# 公開鍵をサーバーにコピー
ssh-copy-id -i ~/.ssh/deploy_key.pub user@server.example.com
- 秘密鍵を GitHub Secrets に登録する
bash# 秘密鍵の内容を表示(これを GitHub Secrets にコピー)
cat ~/.ssh/deploy_key
GitHub リポジトリの Settings → Secrets and variables → Actions から、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 テストライブラリが含まれていない
解決方法:
composer.json
に WordPress テストライブラリを追加する
json{
"require-dev": {
"phpunit/phpunit": "^9.0",
"yoast/phpunit-polyfills": "^1.0",
"wp-phpunit/wp-phpunit": "^6.0"
}
}
- 依存関係をインストールする
bashcomposer install
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 エラーでページが正しくレンダリングされていない
解決方法:
- タイムアウト時間を延長する
typescript// テストファイルで個別にタイムアウトを設定
test('記事詳細ページが正しく表示される', async ({
page,
}) => {
// タイムアウトを 60 秒に設定
test.setTimeout(60000);
await page.goto(`${process.env.BASE_URL}/sample-post/`);
// ...
});
- セレクタを確認する
typescript// より具体的なセレクタを使用
const title = page.locator('article h1.entry-title');
await expect(title).toBeVisible({ timeout: 10000 });
- ページの読み込みを待つ
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 を導入して、より安全で効率的な開発フローを実現してください。
関連リンク
- article
CI/CD で更新を自動化:GitHub Actions と WordPress の安全デプロイ
- article
ホワイトスクリーン/500 エラーの解決:WordPress で最初に見る場所
- article
キャッシュ比較:WordPress で WP Rocket/LiteSpeed/W3TC を検証
- article
WordPress 情報設計:CPT/タクソノミー/メタデータの設計指針
- article
WordPress を Docker で最速構築:開発/本番の環境差分をなくす手順
- article
WordPress 技術ロードマップ 2025:ブロック × ヘッドレス二刀流の最前線
- article
CI/CD で更新を自動化:GitHub Actions と WordPress の安全デプロイ
- article
NestJS クリーンアーキテクチャ:UseCase/Domain/Adapter を疎結合に保つ設計術
- article
WebSocket プロトコル設計:バージョン交渉・機能フラグ・後方互換のパターン
- article
MySQL 読み書き分離設計:ProxySQL で一貫性とスループットを両立
- article
Motion(旧 Framer Motion)アニメオーケストレーション設計:timeline・遅延・相互依存の整理術
- article
WebRTC で遠隔支援:画面注釈・ポインタ共有・低遅延音声の実装事例
- blog
iPhone 17シリーズの発表!全モデルiPhone 16から進化したポイントを見やすく整理
- blog
Googleストアから訂正案内!Pixel 10ポイント有効期限「1年」表示は誤りだった
- blog
【2025年8月】Googleストア「ストアポイント」は1年表記はミス?2年ルールとの整合性を検証
- blog
Googleストアの注文キャンセルはなぜ起きる?Pixel 10購入前に知るべき注意点
- blog
Pixcel 10シリーズの発表!全モデル Pixcel 9 から進化したポイントを見やすく整理
- blog
フロントエンドエンジニアの成長戦略:コーチングで最速スキルアップする方法
- review
今の自分に満足していますか?『持たざる者の逆襲 まだ何者でもない君へ』溝口勇児
- review
ついに語られた業界の裏側!『フジテレビの正体』堀江貴文が描くテレビ局の本当の姿
- review
愛する勇気を持てば人生が変わる!『幸せになる勇気』岸見一郎・古賀史健のアドラー実践編で真の幸福を手に入れる
- review
週末を変えれば年収も変わる!『世界の一流は「休日」に何をしているのか』越川慎司の一流週末メソッド
- review
新しい自分に会いに行こう!『自分の変え方』村岡大樹の認知科学コーチングで人生リセット
- review
科学革命から AI 時代へ!『サピエンス全史 下巻』ユヴァル・ノア・ハラリが予見する人類の未来