トミケルの本音

日々の仕事や趣味で感じたことを綴るブログ

【Docker × WordPress】本番データを完全同期!画像をダウンロードせずにローカル開発環境を作る方法

WordPressのテーマ開発やカスタマイズを行うとき、ローカル(自分のパソコン)に開発環境を作るのはもはや必須です。 なかでもDockerを使った環境構築はとても便利ですが、本番サイトからデータベース(SQLファイル)を持ってきて移行しようとすると、こんな問題によくぶつかります。

  • URLが変わってしまい、ローカル(localhost)でサイトが表示されない、あるいは本番サイトに飛ばされる
  • 本番サイトにある大量 of 大量の画像(uploads)をダウンロードするのが重すぎる・容量が足りない
  • 画面上部にプラグインのNotice(警告メッセージ)がズラズラと出てデザイン確認の邪魔になる

今回は、これらの面倒な問題を「全自動」でスッキリ解決するプロの開発環境の作り方を解説します!

全体のフォルダ構成

今回構築する環境のフォルダ構成です。必要なファイルだけをマウント(同期)する、シンプルでクリーンな構成です。

my-wordpress-project/
├── .env                  # ポート番号やデータベース接続情報の変数ファイル
├── docker-compose.yml    # Dockerの設定ファイル
├── db_init/
│   └── init.sql          # 本番サイトからエクスポートしたSQLファイル(自動インポート用)
└── wp-content/           # Macとコンテナ間で同期するフォルダ
    ├── .htaccess         # 【今回のキモ!】画像の本番自動読み込みルール
    ├── themes/           # 自作テーマ
    └── plugins/          # プラグイン

1. docker-compose.yml で立ち上げ時にURLを全自動置換する

本番サイトのSQLデータをローカルにインポートすると、データベース内のURLが本番のまま(例: https://product.url/sub-dir)になっているため、そのまま起動するとリンク切れを起こしたり、本番サイトにリダイレクトされてしまいます。

これを解決するために、docker-compose.ymlwordpress サービスに「起動完了後、15秒待って裏側で自動的にURLを一括置換するスクリプト」を仕込みます。

以下が、今回使用する docker-compose.yml の完全な設定です。

version: "3.8"

services:
  db:
    image: mysql:8.0.45
    container_name: wp_db
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}
      MYSQL_DATABASE: ${DB_NAME}
      MYSQL_USER: ${DB_USER}
      MYSQL_PASSWORD: ${DB_PASSWORD}
    volumes:
      - db_data:/var/lib/mysql
      # 初回起動時にこのフォルダ内のSQLが自動でインポートされます
      - ./db_init:/docker-entrypoint-initdb.d

  wordpress:
    depends_on:
      - db
    image: wordpress:${WP_VERSION}-php${PHP_VERSION}-${WEB_SERVER}
    container_name: wp_app
    restart: always
    ports:
      - "${WP_PORT}:80"
    environment:
      WORDPRESS_DB_HOST: db:3306
      WORDPRESS_DB_USER: ${DB_USER}
      WORDPRESS_DB_PASSWORD: ${DB_PASSWORD}
      WORDPRESS_DB_NAME: ${DB_NAME}
      WORDPRESS_TABLE_PREFIX: ${DB_PREFIX}

      # 【デバッグ設定】
      WORDPRESS_DEBUG: 1          # 開発モードをONにする
      WORDPRESS_DEBUG_LOG: 1      # 警告などは裏のログファイル(debug.log)に保存する
      WORDPRESS_DEBUG_DISPLAY: 0  # 画面上のレイアウトを崩すので画面表示はOFFにする
    volumes:
      # wp-contentフォルダの中身だけをMacと直結(マウント)します
      - ./wp-content:/var/www/html/wp-content
    command:
      - /bin/bash
      - -c
      - |
        # 1. バックグラウンド(裏側)でデータベースの起動を待ち、URL置換を実行
        (
          echo "=== URL自動置換スクリプト起動 ==="
          sleep 15
          if [ ! -f wp-cli.phar ]; then
            curl -O [https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar](https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar)
            chmod +x wp-cli.phar
          fi
          echo "URLおよび本番ドメインの置換処理を実行中..."

          # サブディレクトリ付きの本番URLをローカルURLに置換
          php wp-cli.phar search-replace '[https://product.url/sub-dir](https://product.url/sub-dir)' 'http://localhost:8080' --allow-root

          # ドメイン単体(画像パスなど)も丸ごと置換
          php wp-cli.phar search-replace '[https://product.url](https://product.url)' 'http://localhost:8080' --allow-root

          # データベース内に残っている別ドメイン(初期ドメイン等)もすべて localhost に統一する
          php wp-cli.phar search-replace '[https://legacy.product.url/sub-dir](https://legacy.product.url/sub-dir)' 'http://localhost:8080' --allow-root
          php wp-cli.phar search-replace '[https://legacy.product.url](https://legacy.product.url)' 'http://localhost:8080' --allow-root

          echo "=== URL自動置換スクリプト完了 ==="
        ) &

        # 2. 本来のWordPress起動処理(Apache)を通常通り実行する
        exec docker-entrypoint.sh apache2-foreground

  phpmyadmin:
    depends_on:
      - db
    image: phpmyadmin/phpmyadmin
    container_name: wp_phpmyadmin
    restart: always
    ports:
      - "${PMA_PORT}:80"
    environment:
      PMA_HOST: db

volumes:
  db_data:

この設定のメリット

この設定をしておくことで、将来本番のデータベース(SQL)を新しくダウンロードし直してローカルを再構築するときも、人間がコンテナに入ってコマンドを打つことなく、立ち上げ時に全自動でURLがローカル用に書き換わります。

2. .htaccess を使って本番の画像を「ダウンロードなし」で表示させる

本番サイトの画像(wp-content/uploads/)は、数百MB〜数GBに膨らんでいることがよくあります。 これをローカル開発のためだけにいちいちダウンロードするのは時間もハードディスクの容量も無駄になってしまいます。

そこで、「ローカルに画像が存在しないときだけ、自動的に本番サイトの画像をHTTPS経由で表示させる」という .htaccess のリダイレクトの裏ワザを使います。

⚠️ Docker環境での重要な注意点

通常、.htaccess はWordPressのルートディレクトリ(wp-config.php がある場所)に置きます。 しかし、今回のDocker設定では wp-content フォルダだけをマウント しています。

Macのルート直下に .htaccess を置いても、コンテナ内のApacheサーバーからはそのファイルが見えない(物理的に存在しない)ため、ルールが無視されてしまいます。

💡 解決策

.htaccess は、マウントされている wp-content フォルダの直下に配置します。

wp-content/.htaccess を作成し、中身を以下のように記述します。

<IfModule mod_rewrite.c>
RewriteEngine On

# ローカル環境の wp-content/uploads に画像が存在しない場合
RewriteCond %{REQUEST_FILENAME} !-f

# 本番環境(さくら)の同名パスから画像を一時的にリダイレクトして取得・表示する
RewriteRule ^uploads/(.*)$ [https://product.url/sub-dir/wp-content/uploads/$1](https://product.url/sub-dir/wp-content/uploads/$1) [L,R=301]
</IfModule>

これにより、ローカルのフォルダは空っぽのままでも、ブラウザでサイトを開くとすべての画像が本番サーバーから自動的に引っ張られて綺麗に表示されるようになります!

3. 目障りなNotice警告を非表示にしてデザイン調整に集中する

ローカル環境を立ち上げたとき、画面の最上部に以下のような英語の警告文(Notice)が表示されることがあります。

Notice: 関数 WP_Scripts::add が誤って呼び出されました。ハンドル「wpcf7-recaptcha」のスクリプトは、未登録の依存関係とともにキューへ追加されました: google-recaptcha...

これは、あなたが書いたテーマではなく、外部プラグイン(この場合はContact Form 7)の内部的なちょっとした古い書き方の警告です。

開発中に自分で直せるものではないのに、この警告文が画面に出っ放しになると、HTML構造が崩れてCSSの表示確認やスライダーの動作確認に支障が出ます。

プロの開発現場では、これを以下のように切り替えます。

  • 画面(Display):OFF ➔ デザイン確認の邪魔をさせない
  • ログファイル(Log):ON ➔ エラー内容は裏のログファイルにしっかり記録しておく

docker-compose.yml に指定した以下の環境変数がその役割を果たしています。

      WORDPRESS_DEBUG: 1          # デバッグモード自体は有効
      WORDPRESS_DEBUG_LOG: 1      # wp-content/debug.log に記録を残す
      WORDPRESS_DEBUG_DISPLAY: 0  # 画面には出さない

これで、画面はピカピカに美しい状態を保ちつつ、本当に困ったバグが起きた時だけ裏側のログファイル(wp-content/debug.log)を確認するというスマートな開発スタイルが作れます。

⚠️ 実際に開発中にハマった!初心者が陥る4つの落とし穴と解決策

ここでは、今回の環境構築中に実際に発生した「リアルなエラーとつまずきポイント」を解説します。これから構築する方は、ぜひここを読んで予習しておいてください!

落とし穴①:ルート直下に置いた .htaccess が無視される

.htaccess を書いたのに本番から画像を取ってきてくれない!」と悩みました。 原因は、docker-compose.ymlwp-content フォルダしかマウント(同期)していなかったため。ルート直下に .htaccess を配置しても、Dockerコンテナ(Apache)側からはファイルが一切認識されていませんでした。

  • 対策: .htaccesswp-content/ の直下 に移動させ、記述も wp-content の親ディレクトリが省かれた uploads/(.*) 向けに書き換えることで解決しました。

落とし穴②:本番ドメインが「複数混在」していて一部画像が出ない

データベースを http://localhost:8080 に置換したものの、一部の画像がまだリンク切れになっていました。 確認したところ、本番環境には独自ドメイン(https://product.url)だけでなく、過去の移行前の初期ドメイン(https://legacy.product.url)でアップロードされた過去の画像やデータが混在していたのです。

  • 対策: 自動置換スクリプトに、以前のドメイン(legacy.product.url)も合わせてローカルURLに統合する置換コマンドを追記して、データベース全体をきれいにクレンジングしました。

落とし穴③:ブラウザの「301リダイレクト」キャッシュから抜け出せない

データベースのURL設定を完全にローカル向け(localhost:8080)に書き換えたはずなのに、何度アクセスしても古い本番のURL(localhost:8080/sub-dir/)へ強制リダイレクトされる現象に遭遇しました。 これはブラウザが「かつて行われた301転送ルール」を強力に記憶(キャッシュ)してしまっているため。

  • 対策: 開発中は、ブラウザのキャッシュを完全に無視する 「シークレットウィンドウ」 を使って確認するのが最も確実です。

落とし穴④:コンソールの「404エラー無限ループ」でフリーズ寸前に

ブラウザのデベロッパーツールのコンソールを開くと、同じ画像に対する 404(ファイルなし)エラーが、1秒間に数十回ものスピードで延々と出力され続けるループ現象が起きました。 原因は、カルーセルやスライダー(Swiperなど)のJavaScriptが、「読み込み失敗➔自動で再試行(リトライ)」をバックグラウンドで無限に高速ループさせていたこと。

  • 対策: .htaccess の転送先ドメインを1文字も間違えずに正確に記述して解決するか、もしくはローカルの uploads/ フォルダの中に 同名のダミー画像を物理的に置いてエラーを消去する と、ピタッとループが収まります。

5. よく使うDockerコマンド集

設定を変更したときに使う、これだけは覚えておきたい3つのコマンドです。 Docker Composeコマンドは優秀なので、テーマフォルダなどの「子フォルダ」に移動したままでも、自動で親フォルダの設定ファイルをさかのぼって探して実行してくれます。

コンテナの起動

初めて立ち上げる時や、設定ファイルを変更した後に実行します。

docker compose up -d

安全な再起動

「なんか挙動がおかしいな」と思ったときや、設定(.htaccess など)を綺麗に再読み込みさせたいときに使います。

docker compose down
docker compose up -d

データベースも含めた完全な初期化

本番の最新のSQLファイルを db_init/ に入れ直して、最初からすべてをまっさらに作り直したい場合のみ実行します。(※ローカルで投稿した下書きデータなどもすべて消えるので注意してください)

docker compose down -v
docker compose up -d

まとめ

Dockerを使ったWordPress開発環境は、少しの設定のコツを掴むだけで劇的に軽快で快適になります。

  1. command: を使ってURL一括置換を全自動化する
  2. wp-content/.htaccess で本番の画像をHTTPSでスマートに読み込む
  3. デバッグ設定を「画面は非表示、ログは保存」にしてCSS確認を快適にする

この3つのテクニックを組み合わせて、ストレスのない快適なローカルコーディングライフを送りましょう!