記事をSSH越しにWP-CLIで本番デプロイする|全サイト移行より安全な1本ずつ反映

2026.07.08 約 10 分で読めます
ノートPCのターミナル画面から記事カードが点線を辿ってサーバーへ運ばれ、SSH・WP-CLI・Deploy と手書きされたノートが並ぶ、WordPress記事を本番へ1本ずつデプロイする様子を表した手描き線画のアイキャッチ

記事を1本足したいだけなのに、本番のデータベースをまるごと入れ替える。これが、地味にこわい作業です。手が滑れば公開中の記事も設定も巻き込みます。そこでこのブログでは、テーマと記事でデプロイの経路を分けました。記事はSSH越しにWP-CLIで1本ずつ足す方式です。実際に本番へ流している運用スクリプトごと、その手順を書きます。

結論:テーマはGit、記事はWP-CLI。本番デプロイの経路を分ける

答えはシンプルで、変更の性質でルートを2つに割ります。テーマ(PHPやCSS)はGitで管理してGitHub Actionsから自動配布。記事(DBの中身)はGitに載らないので、SSH+WP-CLIで個別に足す。全サイトを毎回コピーするのではなく、増えた記事だけを本番に「追記」するイメージです。これで既存の公開記事や設定に触れずに済みます。

デプロイを2経路に分ける図。テーマはgit push→GitHub Actions→rsyncで本番テーマへ自動配布、記事はSSH→WP-CLIのwp post createで本番DBへ1本ずつ反映する
テーマは自動(Git)、記事は手動(SSH+WP-CLI)。DBはGitに載らないので経路を分ける

なぜ全サイト移行(db import)を毎回やらないのか

ローカルと本番を同期する定番は、DBをまるごと書き出して取り込み、URLを置換する方法です。初回の移行ならこれで正解でした。ただ、すでに公開して運用が回っているサイトに毎回これをやるのは、リスクが釣り合いません。

本番のDBには、ローカルには無いものが増えていきます。あとから直した誤字、コメント、各種プラグインが書き込んだ設定。ローカルのDBで上書きすると、それらが吹き飛びます。wp search-replace でのURL置換もサイト全体に及ぶので、1箇所ミスれば影響は全ページです。記事を1本足すだけなら、その記事だけを触るのが素直でした。ここは慎重にいきたいところです。

実装①:SSHで本番に入りWP-CLIを叩く

まず本番サーバーにSSHで入ります。鍵認証にしておくと、無人のスクリプトからも呼べます。ホスト名やユーザー名は各自の環境のものに置き換えてください(以下はマスクした例です)。

# 鍵認証でSSH(ポートはXserverの標準 10022)
ssh -i ~/.ssh/deploy_key -p 10022 xsXXXXX@your-server.xsrv.jp

# サーバー側でWP-CLIが通るか確認
cd ~/your-site/public_html
wp core version   # 例: 7.0

共有サーバーだと wp にパスが通っていないことがあります。その場合は ~/bin/wp のようにフルパスで呼ぶか、エイリアスを張っておくと楽でした。

実装②:記事を冪等にpublishする(slug存在チェック)

本番デプロイのスクリプトで一番大事にしたのが「何度流しても二重作成しない」ことです。バッチが途中で失敗して流し直すことは、普通に起きます。そこで wp post create の前に、同じ slug の記事が本番にあるか必ず確認し、あればスキップします。実際の関数がこれです。

publish() { # $1=slug $2=title $3=date $4=tags $5=本文html $6=featured
  local existing
  existing=$(wp post list --post_type=post --post_status=any 
             --name="$1" --field=ID)
  if [ -n "$existing" ]; then
    echo "SKIP $1 (既に本番に存在 ID=$existing)"; return 0   # ← 冪等の要
  fi

  local id
  id=$(wp post create "$5" --post_type=post --post_status=publish 
        --post_title="$2" --post_name="$1" --post_date="$3" 
        --tags_input="$4" --porcelain)
  id=$(echo "$id" | tr -cd '0-9')            # porcelainのIDだけ取り出す

  wp post term set "$id" category wordpress  # カテゴリを設定
  wp media import "$6" --post_id="$id" --featured_image  # アイキャッチ
  echo "PUBLISHED $1 -> ID $id"
}

--porcelain を付けると、作成した投稿IDだけが返ります。そのIDにカテゴリを結び付け、アイキャッチを wp media import --featured_image で登録するところまでを1つの関数にまとめました。流れを図にするとこうです。

記事を冪等に本番へ足すフロー図。slug存在チェックで既存ならSKIP、無ければwp post create→カテゴリ設定→画像配置→media importでアイキャッチ→rewrite flush→curl確認の順
slug があればスキップ。無いときだけ作成→カテゴリ→画像→アイキャッチ→確認と進む

実装③:画像の配置とローカルURLの相対化

本文に画像を含む記事では、2つ下ごしらえが要ります。1つは本文中のURL。ローカルの http://*.local のまま送ると本番で画像が割れます。転送前に、本文のURLをルート相対(/wp-content/uploads/…)に直しておきました。

もう1つは画像ファイルそのもの。uploads の年月フォルダに実ファイルを置きます。スクリプトでは、転送済みの画像を正規パスへコピーしてから記事を作りました。

place_img() { # $1=srcfile $2=dest-rel-path
  dest="wp-content/uploads/$2"
  mkdir -p "$(dirname "$dest")"
  cp -f "$1" "$dest"
}
place_img "$IMG/diagram_01.png" "2026/07/diagram_01.png"

ちなみにアイキャッチは wp media import がメディアライブラリに登録してくれますが、本文中の画像は「実ファイルの配置+本文のURL」を自分でそろえる必要があります。ここを混同すると画像が割れるので、地味ですが分けて考えると安全でした。

公開後の検証とロールバック

本番デプロイは、流して終わりにしません。公開直後に curl でページを取り、ステータスと中身を確認します。

# HTTP 200 か、タイトル・画像が出ているか
curl -sI https://example.com/wordpress/your-slug/ | head -1
curl -s  https://example.com/wordpress/your-slug/ | grep -o '<h1[^>]*>[^<]*' | head -1
wp rewrite flush   # パーマリンクを最後にもう一度確定

問題があったときの戻し方も、経路ごとに決めておきました。テーマの不具合はGitで git revert すればActionsが正しい状態を配り直します。記事のほうは、作った投稿を wp post delete --force で消すか、いったん下書きに落として直します。全DBを触っていないので、戻す範囲もその記事だけです。

この方法が向かない場合

この「1本ずつ」方式にも、向かない場面があります。

  • 初回のまるごと移行:ローカルで作り込んだサイトを一気に本番化するなら、素直にDB export/import + search-replace のほうが速いです
  • 大量の既存記事を一括で直す:全記事の文字列を置換するような作業は、wp search-replace の出番です。1本ずつ足す方式とは目的が違います
  • WordPress管理画面で書く運用:本番で直接書いているなら、そもそもデプロイという発想が要りません

逆に、ローカルで検証してから本番へ小さく足していく運用には、この方式が合っています。同じテーマでの実装はオリジナルテーマを自作する記事セキュリティ対策の記事に、ほかの実装は爆速開発・環境構築のカテゴリにまとめています。

まとめ

  • 本番デプロイは、テーマ(Git+Actions)と記事(SSH+WP-CLI)で経路を分ける
  • 稼働中サイトに db import を毎回やらない。記事は wp post create で1本ずつ足す
  • slug の存在チェックで冪等化し、流し直しても二重作成しない
  • 本文URLはルート相対化、画像は uploads へ配置、最後に rewrite flush
  • 公開後は curl で確認。戻すのもその記事だけで済む

本番デプロイは、経路を分けて小さく安全にするだけで、日々の更新がぐっと気楽になります。こうした公開・運用のフローづくりを企業サイトで設計・構築する仕事は、運営元のNEORIVAでも承っています。手作業の本番反映に不安がある方は、気軽に相談してください。参考にした公式ドキュメントは wp post createwp media importwp search-replace です。

こま

こま

元SE × AI開発 × 業務自動化の実践者

SE 4年 + プログラミング歴 8年。業務自動化と AI 組み込み開発を仕事にしながら、現場で使えるものだけを書いています。 最新のAIの現場を発信中!!