本記事は、公式 WordPress Docker で 自作テーマ・プラグイン以外を git 管理外にしつつ快適に開発する(+ Claude Code 対応) の派生記事です。
サマリ
WordPress プロジェクトを git 管理したい場合、自作テーマ・プラグインだけを git 管理 するのが効率的です。
- WordPress サイトは全部 git で管理しない方が運用しやすい
- 自作テーマ(と自作プラグイン)だけを追跡対象にする
- 実現には、ホワイトリスト方式の
.gitignoreを書く(wp-content/*を一度全部除外して、必要なものだけ!pathで許可) - ホワイトリスト方式は 親ディレクトリを除外すると子ファイルを許可できない という罠があるので、書き順に注意
このレシピはサイトを長く運用する際の困りごとへの対策です。
WordPress サイトのディレクトリ構造
具体的な ignore 設計に入る前に、WordPress サイトのどこに何があるかを軽くおさらいします。すでに馴染みがあれば読み飛ばしてください。
wordpress/ ← ドキュメントルート
├── wp-admin/ ← 管理画面のコア(WP 公式パッケージ)
├── wp-includes/ ← コアライブラリ(WP 公式パッケージ)
├── index.php, wp-*.php, ... ← ブートストラップ用のコアファイル
├── wp-config.php ← DB 接続情報・認証ソルト(秘匿情報)
├── .htaccess ← パーマリンク等で WP が自動編集
└── wp-content/ ← サイト固有の領域
├── themes/ ← テーマ(公式 + 自作)
├── plugins/ ← プラグイン(公式 + 自作)
├── uploads/ ← 投稿画像(DB と紐づく "content")
├── cache/, upgrade/, ... ← サーバランタイムで生成
└── languages/ ← 多言語ファイル(自動 DL)
このうち「自分で書いたもの」は wp-content/themes/ wp-content/plugins/ の中の自作分だけで、それ以外は全部「公式パッケージ」「サーバが書き換えるもの」「DB と紐づくもの」のいずれかとなります。
サイト全体を git に乗せたらどうなるか
「サイトを丸ごと git に乗せる」やり方は手っ取り早く見えますが、運用に入ると問題が積み重なります。
コアだけで約 2,900 ファイル
WordPress 6.9.4 の標準インストールを測定するとこうなります:
| 領域 | ファイル数 | サイズ |
|---|---|---|
wp-admin/ |
573 | 11 MB |
wp-includes/ |
2,324 | 57 MB |
ルート直下 (wp-*.php, index.php 等) |
18 | < 1 MB |
| コア合計 | 約 2,915 | 約 68 MB |
これは「インストール直後・テーマもプラグインも入れていない」状態の数字です。実運用では:
-
標準テーマ(
twentytwentyfive等、テーマごとに数百ファイル単位) - 公式プラグイン(Jetpack のような大型のもので 1,000 ファイル超に達することもある)
- uploads(時間経過で確実に膨らむ)
がここに積み増され、コード索引としても役に立たない・git diff で何が変わったか追えない規模に到達します。
本体アップデート時に大量の diff が出る
WordPress 本体は定期的に更新されます。コアの 2,900 ファイルは更新のたびにごっそり書き換わるため、git に乗せていると:
-
git statusに数千ファイルの変更 -
git diffがほぼ無意味なボリューム - 自作テーマの編集中に本体更新が走ると、マージ衝突の解決が困難になります
これは WordPress 本体だけの話に留まりません。WordPress 6.3 から導入された「プラグインアップデート失敗時の自動ロールバック」機能は wp-content/upgrade-temp-backup/ に意図せず巨大なバックアップを作ります。管理画面からのプラグイン更新だけでこの種のディレクトリが増える、というのが「DigitalCube の解説」(末尾 参考[1])でも .gitignore の漏れによるリポジトリ肥大化の典型例として挙げられています。
uploads は時間経過で必ず肥大化する
wp-content/uploads/ は投稿時にアップロードされた画像の保存先です:
- 1 投稿あたり画像 1 枚 + WordPress が自動生成するサムネ・中・大の複数バリエーション
- 数ヶ月で数百 MB、年単位で GB 級に到達する事例も普通にあります
Tower Blog(末尾 参考[2])が指摘しているように、これらは DB と紐づく「コンテンツ」であって「コード」ではないので、git の対象にする意味がありません。
wp-config.php は流出が即アウト
wp-config.php には DB パスワードと認証ソルト が平文で書かれています。公開リポジトリに誤って push すれば、自動クロールするボットが数分で見つけてきます。
これは git 管理の話以前に、そもそもリポジトリに置かない のが原則です。
.htaccess は WP が勝手に編集する
パーマリンク設定の変更などで WordPress が .htaccess を自動編集します。git に乗せていると、サイト上で何か設定変更しただけで「ファイル変更検知」になり、自分で定義したものの管理がやりにくくなります。
サイトの本質は DB 側にある
WordPress の本質(投稿・設定・ユーザー情報)は DB の中 にあります。ファイルだけ git で追ってもサイトの状態は再現できません。サイト復元には DB ダンプの別系統バックアップが必須で、git の範疇外です。
まとめると
サイト全体を git に乗せた場合の被害:
| 観点 | 影響 |
|---|---|
| リポジトリサイズ | コアだけで 2,900 ファイル / 68 MB、長期運用で GB 単位へ |
| diff のノイズ | 本体更新のたび数千ファイルの変更が紛れ込む |
| マージ衝突 | 本体ファイルが自分の commit と衝突するリスク |
| セキュリティ |
wp-config.php 流出 = サイト乗っ取り |
| 復元可能性 | DB が無い時点でファイルだけでは再現不可 |
これらは 自作物以外を gitignore する ことで回避することができます。手間も .gitignore 1ファイルで済みます。
完成形 .gitignore(リポジトリルートに配置)
まずは全体像から。下記をリポジトリルート(wordpress/ の親)に配置するパターンです。
方針:自作物(mytheme テーマ等)だけを git 管理する。
wordpress/ ディレクトリは本番サーバから rsync 等で同期する運用も考えられるため、ignore ルールは本リポジトリルートに記載します。
# --- WordPress コア(WordPress本体は除外)-----------------
/wordpress/wp-admin/
/wordpress/wp-includes/
/wordpress/wp-*.php
/wordpress/index.php
/wordpress/xmlrpc.php
/wordpress/license.txt
/wordpress/readme.html
# --- プラグイン等自動生成ファイル除外(All in One SEO Pack 等)-----
/wordpress/sitemap.xml
/wordpress/sitemap.xsl
/wordpress/sitemap.xml.gz
/wordpress/sitemap-*.xml
/wordpress/robots.txt
# --- 秘密情報・ログ -----------------------------------------------
/wordpress/wp-config.php
*.log
# --- ランタイム生成・サーバが書き換えるファイル ---------------
/wordpress/.htaccess
/wordpress/wp-content/upgrade/
/wordpress/wp-content/upgrade-temp-backup/
/wordpress/wp-content/uploads/
/wordpress/wp-content/cache/
/wordpress/wp-content/backup*/
/wordpress/wp-content/languages/
# --- プラグイン(index.php だけは commit、自作物のみ追跡)-------------
/wordpress/wp-content/plugins/*
!/wordpress/wp-content/plugins/index.php
# 自作プラグインを管理する場合はここで個別に許可:
# !/wordpress/wp-content/plugins/custom-plugin/
# --- テーマ(標準テーマは除外。自作テーマだけ追跡)----------
/wordpress/wp-content/themes/*
!/wordpress/wp-content/themes/index.php
!/wordpress/wp-content/themes/mytheme/
/wordpress/ プレフィックスを外せば、リポジトリ直下に直接 WP を置く構成にも転用できます。
セクション別の意図
コア(wp-admin / wp-includes / wp-*.php)
WordPress本体そのもの。WordPress 本体のバージョンアップで全ファイルが入れ替わるので、追跡しても意味がありません。
/wordpress/wp-*.php は wp-load.php wp-settings.php wp-blog-header.php 等を一括除外するためのワイルドカード。/wordpress/index.php xmlrpc.php license.txt readme.html は名前が wp-* 形式でないので個別指定が必要です。
プラグイン自動生成ファイル
All in One SEO Pack 等の SEO プラグインは、ドキュメントルート直下に sitemap.xml robots.txt などを 書き出します。これらは設定変更のたびに上書きされるサーバ生成物なので、除外をしたいです。
秘密情報
wp-config.php は 絶対にコミットしないでください。DB パスワードと認証ソルトが入っており、セキュリティ上の大きな問題となります。誤って公開リポジトリに push すると、自動クロールするボットに見つけられてサイト乗っ取りなどの重大事故につながります。
*.log も同様の理由で除外(個人情報・パス情報が含まれる可能性)。
ランタイム生成
.htaccess は WordPress がパーマリンク変更などで自動編集します。手で書いたカスタム部分(IP 制限・リダイレクト等)を残したい場合は、別ファイルにメモするかテンプレートファイル化して管理する運用がおすすめです。
upgrade/ upgrade-temp-backup/ cache/ 等は WordPress が作業用に作るディレクトリ。
uploads/ は投稿画像等がアップロードされます。git 管理するとサイズが巨大になるため除外します。
バックアップはバックアッププラグインや、別の方法で取得してください。
languages/ は WordPress 多言語ファイル(.mo .po)。自動ダウンロードされるバイナリなので除外します。
プラグイン(ホワイトリスト方式)
/wordpress/wp-content/plugins/*
!/wordpress/wp-content/plugins/index.php
# !/wordpress/wp-content/plugins/custom-plugin/
plugins/* で 直下全て を一度除外。index.php だけ許可。
自作プラグインを書く場合は !/wordpress/wp-content/plugins/custom-plugin/ のような形で個別に許可を追加します。
テーマ(ホワイトリスト方式)
/wordpress/wp-content/themes/*
!/wordpress/wp-content/themes/index.php
!/wordpress/wp-content/themes/mytheme/
themes/* で全て除外、自作テーマ mytheme/ だけ許可。これで twentytwenty* 等の WordPress 標準テーマは追跡対象から外れます。
ホワイトリスト方式の罠
ホワイトリスト方式(* で全部除外して !path で許可)には、親ディレクトリが除外されていると、子ファイルを !path で許可しても効かない という罠があります。
たとえば下記は 動きません:
/wordpress/wp-content/
!/wordpress/wp-content/themes/mytheme/
→ wp-content/ 全体が除外されているので、その下の themes/mytheme/ も認識されない。git は再帰的に「親が ignore されていれば中も見ない」最適化をするため。
正しくは下記のように、階層ごとに /* で「中身を除外」しつつ親ディレクトリ自体は除外しない 書き方をする必要があります:
/wordpress/wp-content/plugins/*
!/wordpress/wp-content/plugins/index.php
/wordpress/wp-content/themes/*
!/wordpress/wp-content/themes/index.php
!/wordpress/wp-content/themes/mytheme/
plugins/* は「plugins ディレクトリの中身を除外」(末尾 * がポイント)。plugins/ 自体は除外しないので、その下の !path 許可ルールが効きます。
なぜ .gitignore をリポジトリルートに置くか
本構成は wordpress/ ディレクトリの中ではなく、リポジトリルート に .gitignore を置いています。理由は wordpress/ 配下を差し替えても ignore ルールが上書きで消えないように するためです。
repo-root/
├── .gitignore ← ここに集約
├── wordpress/ ← 丸ごと差し替えても壊れない
│ └── wp-content/
│ └── themes/mytheme/
wordpress/.gitignore に置いてしまうと、本番サーバからのファイル等を入れ替えた場合に .gitignore が上書き、または削除されるリスクがあります。
このため、リポジトリルートの .gitignore に記載しています。
まとめ
- WordPress サイトは 自作物だけ追跡、それ以外は全部 ignore
-
.gitignoreの記載は ホワイトリスト方式(*で全部除外、!pathで必要なものだけ許可)で書く - 親ディレクトリの除外/許可関係に注意
-
.gitignoreはリポジトリルートに集約(ファイル差し替えしても壊れないように)
この .gitignore 1 枚で、テーマ開発の git 履歴が綺麗になり、誤って本番のサーバ生成物や機密情報をコミットする事故も防げます。
参考
本文中で言及した記事と、関連する代表的な解説:
-
DigitalCube — WordPress サイト全体を Git で管理する際の注意点と運用ベストプラクティス
https://labworks.digitalcube.jp/technology/wordpress-git-management-best-practices/
WordPress 6.3 で導入されたupgrade-temp-backup/等、.gitignoreの漏れによる肥大化の典型例を解説 -
Tower Blog — Using Git with WordPress (Part 2)
https://www.git-tower.com/blog/git-wordpress-2
wp-content/uploads/を git で管理しない理由を「コンテンツ vs コード」の観点から論じています -
github/gitignore — WordPress.gitignore
https://github.com/github/gitignore/blob/main/WordPress.gitignore
GitHub 公式の curated テンプレ。本記事と異なりブラックリスト方式(コアだけ除外、テーマ・プラグインは基本追跡)を採用 -
Sal Ferrarello — .gitignore for WordPress
https://salferrarello.com/wordpress-gitignore/
本記事と同じホワイトリスト方式の代表例。長年保守されている -
Notes on Tech — The ultimate gitignore for WordPress projects
https://notesontech.com/wordpress-gitignore/
ホワイトリスト + プロジェクト prefix で複数の自作プラグインを一括追跡するパターン