Skip to content

ステージング環境デプロイ(www.staging.slotkouryaku.com) ​

概要 ​

開発環境(core_src)からビルドした成果物(core_YYYYMMDD_HHMMSS)を、ステージング環境(https://www.staging.slotkouryaku.com)へデプロイする手順です。本番デプロイと同じビルド成果物を、別ターゲット(ステージング用のテーマパス)に SCP でアップロードします。

前提条件 ​

  • ステージング用 WordPress がステージング用 DB で稼働していること(ConoHa WING の「+WordPress」で staging.slotkouryaku.com を追加した場合、ステージング用 DB とドキュメントルートは自動作成されます)
  • ステージングのドキュメントルートに、本番と同様にテーマ cocoon-child-master/myCustom が存在するパスがあること
  • デプロイ設定ファイルの準備(config/staging.env)
  • ./bin/deploy-staging.sh や ./bin/activate-staging.sh を 個別実行する場合 は、事前にローカルで ./bin/build.sh を実行し、ビルド済みの core_YYYYMMDD_HHMMSS が存在していること(./bin/deploy-all-staging.sh による一括実行時はビルド処理も含まれるためこの前提は不要)
  • WP_ENVIRONMENT_TYPE: テーマのデプロイ(config/staging.env / デプロイスクリプト)は WordPress の環境タイプを設定しない。ステージングの wp-config.php(またはサーバー環境変数)で define( 'WP_ENVIRONMENT_TYPE', 'staging' ); とすること。絶対に local にしない(local だと一部 REST の権限チェックがバイパスされる)。詳細は ホスティング運用セキュリティチェックリスト の「WP_ENVIRONMENT_TYPE」を参照

設定手順 ​

1. config/staging.env の作成 ​

bash
cp config/staging.env.example config/staging.env
nano config/staging.env

2. 設定する項目 ​

変数説明
DEPLOY_HOSTステージングサーバーのホスト名または IP(本番と同一サーバーの場合は本番と同じ値)
DEPLOY_PORTSSH ポート(省略時は 22)
DEPLOY_USERSSH ログインユーザー名
DEPLOY_SSH_KEY秘密鍵のパス(例: ~/.ssh/your-private-key.pem)
DEPLOY_REMOTE_PATHステージングのテーマ直下のフルパス(core_* を置くディレクトリ)

本番と同一サーバー(同一 ConoHa WING)の場合: DEPLOY_HOST / DEPLOY_USER / DEPLOY_SSH_KEY は本番の config/local.env と同じでよく、DEPLOY_REMOTE_PATH のみステージング用に変更します。

DEPLOY_REMOTE_PATH の例(ConoHa WING で staging.slotkouryaku.com に WordPress を追加した場合):

/home/conoha/public_html/staging.slotkouryaku.com/wp-content/themes/cocoon-child-master/myCustom

3. パーミッション ​

bash
chmod 600 config/staging.env

デプロイ手順 ​

一括実行(推奨):

bash
./bin/deploy-all-staging.sh

./bin/build.sh(deploy-all-staging 内で実行)は npm run build により Chart.js 等のフロントバンドル(hall-samai-graph.js / period-kishu-samai-ranking.js 等、.gitignore 対象)を生成してから core_src を _build/core_* にコピーします。バンドル未生成のまま PHP のみデプロイすると、グラフ系ショートコードは error_log のみで画面に JS が載りません。ビルド時は本番と同じく config/local.env の LEGAL_OPERATOR_NAME / LEGAL_PUBLIC_CONTACT_EMAIL が必須です(未設定だと build.sh が失敗します)。ローカル _src で法務ページを出したい場合は ./bin/generate-legal-operator-local.sh も実行します。

個別実行(部分再実行や確認しながら進めたい場合):

  1. ビルド(未実行の場合)

    bash
    ./bin/build.sh
  2. ステージングへアップロード

    bash
    ./bin/deploy-staging.sh

    またはバージョン(タイムスタンプ)を指定する場合:

    bash
    ./bin/deploy-staging.sh 20250120_143022

    バージョンを省略した場合: 実行ログに表示されるバージョン名か、以下のコマンドで _build ディレクトリ一覧から最新を確認して、次の activate-staging.sh に渡してください。

    bash
    ls -1 _build/core_* | sort | tail -n 1 | sed 's|.*/core_||'
  3. VERSION 切り替え&キャッシュ削除

    bash
    ./bin/activate-staging.sh 20250120_143022

    このスクリプトは SSH でステージングサーバーに接続し、connector.php の VERSION 定数を指定したタイムスタンプに更新したうえで、PHP-DI コンパイル済みコンテナキャッシュを削除します。次回リクエスト時にキャッシュが新しい core_* から再生成されます。

    connector.php: 通常の deploy は core_* のみ。connector.php はサーバー上で固定し、activate-staging.sh が VERSION 定数だけを書き換えます。WP-CLI コマンド登録は CliServiceProvider(core_* 内)のため、新コマンド追加後も connector の再アップロードは不要です。CliServiceProvider 導入時など、connector 本文の変更が必要な場合のみ手動で 1 回同期してください。

    注意: deploy-staging.sh 実行後、WordPress 管理画面で connector.php を編集しようとすると、古いキャッシュが原因でエラーになる場合があります。その場合も activate-staging.sh で切り替えてください。

SSH が使えない場合の FTPS zip デプロイ ​

SSH 接続が利用できない場合の暫定ルートとして、ステージングにも FTPS zip デプロイを使用できます。config/staging.env に次を追加します。

bash
DEPLOY_FTPS_URL=ftp://your-ftp-host/public_html/staging.slotkouryaku.com/wp-content/themes/cocoon-child-master/myCustom
DEPLOY_FTPS_USER=your-ftp-username
DEPLOY_FTPS_PASS=your-ftp-password
DEPLOY_FTPS_PUBLIC_URL=https://www.staging.slotkouryaku.com/wp-content/themes/cocoon-child-master/myCustom
STAGING_SITE_URL=https://www.staging.slotkouryaku.com

一括実行:

bash
./bin/deploy-all-ftps-zip-staging.sh

ビルド済みバージョンを指定して実行:

bash
./bin/deploy-ftps-zip-staging.sh 20260713_120000

動作仕様は本番の FTPS zip デプロイと同じです。zip には core_YYYYMMDD_HHMMSS に加えて、存在する場合は myTemplate/ と scripts/(.DS_Store / *.bak 除外)も含めます。サーバー側では一時 PHP レシーバーがトークン検証後に展開し、connector.php の VERSION を最後に切り替え、PHP-DI キャッシュを削除します。myTemplate/ は上書きマージ、scripts/ は削除同期されます。

注意:

  • SFTP ではなく FTPS を使用します。SFTP は SSH 接続に依存します。
  • 成功時に前回失敗で残った .deploy-stage-* / deploy-receiver-*.php / core_*.zip を掃除します。
  • 成功時に古い core_* を tiered 方針(最新5件常時保持・最大10件・2日超は6件目以降削除)で削除します。
  • scripts/ はリモート側を一度削除してから配置します。リモートで手動追加した一時ファイルも削除されます。
  • 一時レシーバーは Web 公開領域に置かれるため、実行後に自動削除されます。失敗時は myCustom/deploy-receiver-*.php が残っていないか確認し、残っていれば削除してください。
  • 通常の SSH デプロイが復旧したら、./bin/deploy-all-staging.sh を優先してください。

GitHub Actions からのデプロイ(Deploy App) ​

Actions の Deploy App(.github/workflows/deploy-app.yml)から FTPS zip でステージングへ反映できます。workflow_dispatch のみで、品質ゲートとは別ワークフローです。

Secrets / Environments の初回設定は 本番デプロイ > GitHub Actions からのデプロイ を参照し、Environment staging 側に FTPS 用 Secrets と SITE_URL を入れてください。法務埋め込み用の LEGAL_* は Repository secrets です。

実行: Actions → Deploy App → Run workflow で target=staging を選ぶ(本番用の confirm チェックは不要)。

Actions 経路は FTPS のみです。Environment に SSH 用 Secrets を置かないでください。ローカル SSH の正本は ./bin/deploy-all-staging.sh です。

本番データの部分同期 ​

staging の日別記事やリンクが本番と違うと、デプロイ後チェック(前日・翌日・前年のホール移動リンクなど)が正しくできない。scripts/sync-staging-data-from-production.sh で、本番の直近のデータだけを staging に取り込む(Issue #3951 / #3952)。DB 全体はコピーしない。

取り込むもの ​

対象範囲
db2023、db_daily_article_kishu_single_day_summary、db_daily_article_kishu_count_delta対象期間
日別記事(wp_posts / wp_postmeta / db_daily_article_consideration)、db_Link_day対象期間と、前年同日の前日〜翌日
ヒートマップのレイアウト(db_heatmap_layout)適用期間(start_date〜end_date)が、対象期間か前年同日の前日〜翌日と重なる行
P-WORLD サムネ(pworld_hall_day_thumbnail)article_target_date が対象期間か前年同日の前日〜翌日
有料記事(wp_posts / wp_postmeta。post_type = 'paid_article')公開済みの記事を post_date の新しい順に N 件(既定 3 件)
マスタ(db_kishu_master / db_kishu_display_mapping / db_maker_master / db_event_master)全件

取り込まないもの: ユーザー、アプリケーションパスワード、会員・購入、メールログ、wp_options、AI 相談履歴、uploads(添付ファイルの実体)、コメント、ターム。P-WORLD メールアーカイブ(pworld_mail_archive / pworld_mail_image_ref)と db_Link_month は、取り込むかどうかを #3952 で決めるまで入れない。

codoc のアカウントの確認 ​

有料記事を取り込む前に、本番と staging の wp_options の codoc_usercode(codoc のアカウント)を SELECT で読んで比べる。取り込んだ有料記事を staging の編集画面で保存すると、codoc プラグインが staging の codoc 設定で新しい codoc 記事を作るため、staging の設定が本番と同じアカウントのままだと本番の codoc アカウントに記事(有料部分を含む)が登録されてしまう。

staging の codoc_usercode動作
空有料記事を取り込む
本番と違う有料記事を取り込む
本番と同じ何も書き込まずに中止する
取得できない(クエリの失敗)判断できないので、何も書き込まずに中止する

中止したときは、staging の管理画面「設定 → codoc」でアカウントを別のものにするか空にしてから実行し直すか、--paid-articles=0 で有料記事を入れずに実行する。dry-run でも判定結果を表示し、本番と同じならエラーで終わる(staging には書き込まない)。この確認は確認プロンプトの前と、書き込む直前の 2 回行う。アカウントの値そのものは表示しない。

有料記事で持ち込まないもの ​

有料記事は記事本文(wp_posts)と記事の post meta だけを入れる。購入者などの個人情報に関わる次のものは入れない。

持ち込まないもの理由
db_paid_article_purchase購入者(user_id)・決済の取引 ID・購入日時
db_member_subscription / db_member_plan_master会員の契約状態。プランマスタは購入画面の確認に要るまで入れない
コメント(wp_comments / wp_commentmeta)投稿者名・メールアドレス・IP。コメントメタには有料読者かどうかのフラグ(_paid_article_commenter_viewed_paid)がある
db_paid_article_ai_chat_message編集画面の AI 相談履歴(非公開)
リビジョン編集途中の本文。staging の同じ ID の有料記事のリビジョンは削除する
post meta の _edit_lock / _edit_last本番のユーザー ID を指す編集ロック。staging のユーザーとは対応しない
post meta のうち codoc_ で始まるもの(codoc_entry_code / codoc_shortcode_evacuations など)本番の codoc 記事との紐付けと、有料部分から抜き出したショートコード。紐付けを残すと staging で記事を保存したときに codoc プラグインがその記事コードで本番の codoc 記事を書き換える

wp_posts.post_author は本番のユーザー ID のまま入る。staging に同じ ID のユーザーがいなければ投稿者は空、いれば別の人の名前で表示される。wp_posts.comment_count も本番の件数のままなので、コメント欄は空なのに件数だけ出ることがある。有料記事の編集画面用のホールの選択肢(db_paid_article_hall_master)も入れない。

post meta の _thumbnail_id(アイキャッチ)は本番の添付 ID のまま入る。

有料部分の本文も staging の DB に入る。staging には購入記録が無いので、公開画面では未購入として表示される(無料配信の記事を除く)が、staging の管理者・編集者は本番と同じく全文を読める。

前提 ​

  • config/local.env に本番 DB(PROD_DB_*)と SSH(DEPLOY_*)が設定されていること
  • config/staging.env に STAGING_DB_NAME / STAGING_DB_USER / STAGING_DB_PASS / STAGING_DB_HOST と STAGING_SITE_URL=https://www.staging.slotkouryaku.com を設定すること(値は config/staging.env.example を参照)
  • DEPLOY_HOST が本番と staging で同じであること。ダンプとインポートは同じサーバー上で行い、データはローカルに落とさない
  • staging に対象テーブルのスキーマがあること
  • 初回は本番で SELECT @@version; を確かめる。MariaDB なら問題ない。GTID が有効な MySQL だと、ダンプに入る GTID_PURGED の行で取り込みが止まる(データは巻き戻る)ので、その場合はスクリプトに --set-gtid-purged=OFF を足す

実行 ​

bash
# まず dry-run。対象テーブル・本番の行数・削除する staging の日別記事と有料記事・ID の衝突・
# codoc のアカウントの判定・P-WORLD サムネの添付 ID が staging にあるか(取り込まない行)・WP-CLI の有無を表示する
./scripts/sync-staging-data-from-production.sh --dry-run

# 直近 30 日(既定)を取り込む
./scripts/sync-staging-data-from-production.sh

# 期間を変える
./scripts/sync-staging-data-from-production.sh --days=14
./scripts/sync-staging-data-from-production.sh --from 2026-09-01 --to 2026-09-30

# 前年同日を取り込まない
./scripts/sync-staging-data-from-production.sh --no-prev-year

# 有料記事の件数を変える(0〜20。0 で取り込まない)
./scripts/sync-staging-data-from-production.sh --paid-articles=5
./scripts/sync-staging-data-from-production.sh --paid-articles=0

動作 ​

  1. 本番に対しては SELECT と mysqldump --single-transaction だけを行う。本番 DB には書き込まない
  2. staging DB の home が STAGING_SITE_URL と一致しないときは、何も書き込まずに中止する
  3. staging の対象期間の日別記事(リビジョン・ターム紐付けを含む)・リンク・台データ・集計・P-WORLD サムネ、期間が重なるヒートマップのレイアウトと、前年同日の日別記事・リンク・サムネを消してから、本番の行を入れる。有料記事は、本番から入れる記事と同じ ID の staging の有料記事(リビジョン・ターム紐付けを含む)だけを消す。マスタは staging 側を全件入れ替える。削除と取り込みは 1 つのトランザクションで行う(巻き戻せるのは InnoDB のテーブルだけ)
  4. 投稿 ID とマスタの ID は本番のまま入れる。それ以外のテーブル(リンク・集計・レイアウト・サムネ・post meta など)は自動採番の id を振り直し、期間外の staging の行を上書きしない
  5. 本番から入れる投稿 ID を、staging の別の投稿(日別記事なら対象期間の日別記事、有料記事なら同じ ID の有料記事と、それぞれのリビジョン以外。下書き・添付も含む)が使っている場合は、何も書き込まずに中止する。この検査は確認プロンプトの前と、書き込む直前の 2 回行う。有料記事は、書き込む直前に集め直した ID が確認プロンプトの前に表示した一覧と違えば中止する。ダンプも post_status = 'publish' の記事に絞る
  6. wp search-replace で本番 URL(https://www.slotkouryaku.com など)を STAGING_SITE_URL に置き換える。対象は db_Link_day / wp_posts / wp_postmeta だけで、wp_options は触らない。staging サーバーに WP-CLI が無いときは db_Link_day.url だけを SQL で置き換える
  7. staging の PHP-DI キャッシュを削除する

URL の置き換えは取り込みをコミットしたあとに行う。置き換えで失敗したときは、同じコマンドをもう一度実行すればよい(同じ範囲を消して入れ直すので、何度実行しても結果は同じ)。JSON の中でエスケープされた URL(https:\/\/...)は置き換わらない。

注意 ​

  • staging で手作業で作った日別記事は、対象期間内なら本番の記事に置き換わる。P-WORLD サムネも、対象期間に当たる staging の行は本番の行に置き換わる
  • ヒートマップのレイアウトは、適用期間が対象期間(前年同日の前日〜翌日を含む)と 1 日でも重なる staging の行をまるごと消して、本番の重なる行に入れ替える。たとえば staging に 2024-01-01〜2099-12-31 の行があると、その行ごと消えるので、対象期間外の日付(例: 2024 年)の島図も本番の行の内容になるか、本番に当たる行が無ければ無くなる
  • staging で作った有料記事は、本番から入れる記事と ID が同じときだけ置き換わる。対象月と号数が同じ staging の有料記事が別にあると、/paid-article/{YYYY-MM}-{号数}/ がどちらを開くか分からなくなるので、dry-run の一覧と staging の有料記事を見比べる
  • 添付ファイルは同期しないので、アイキャッチや P-WORLD サムネなどの画像は表示されないことがある。P-WORLD サムネの attachment_id と有料記事のアイキャッチ(_thumbnail_id)は本番の添付 ID のまま入るので、staging に同じ ID の添付があると別の画像が出る(dry-run で件数を表示するのはサムネだけ)
  • staging の自動生成サムネ(_pworld_hall_day_thumbnail_auto_generated が付いた添付)と同じ ID を指すサムネの行は取り込まない。サムネを撮り直す・自動生成し直すと、前の attachment_id の添付に自動生成の印があれば添付ごと削除されるため、取り込むと staging の別の添付が消えてしまう。staging の対象期間の行は消すので、取り込まなかった日付・ホールはサムネが無い状態になる(staging で撮り直せる)。行を取り込まずに続ける方にしたのは、書き込みを止めると staging で自動生成が動いている限り同期そのものができなくなるため
  • staging に WP-CLI が無いときは object cache を消せない。永続 object cache を入れている場合、ヒートマップのレイアウトは最大 1 時間、P-WORLD サムネは最大 10 分、前の内容が出ることがある。ヒートマップは staging の管理画面「アプリキャッシュ管理」で「ヒートマップ島図」を消せる。サムネは「アプリキャッシュ管理」の対象に無いので、時間が過ぎるのを待つ
  • 取り込み後は デプロイ後チェックリスト の日別記事と、前日・翌日・前年リンクが https://www.staging.slotkouryaku.com を指すことを確認する
  • 本番 → ローカルの同期は データベース同期 を参照

パーティション付きテーブルの一時テーブル ​

自動採番の id を振り直すテーブルは、本番の行をいったん一時テーブルに入れてから本テーブルへ移す。パーティションの無いテーブルは CREATE TEMPORARY TABLE ... LIKE で一時テーブルを作る。

パーティション付きのテーブル(wp_db2023 など)は LIKE だと ERROR 1562 (Cannot create temporary table with partitions) になるため、staging の information_schema.COLUMNS から一時テーブルを作る。

  • 残るもの: 列の型・文字セット・照合順序・NULL 可否
  • 付けないもの: パーティション・索引・既定値・自動採番・生成式・CHECK 制約・コメント
  • 本番と staging で列名が揃っていないとき、または生成列があるときは、何も書き込まずに中止する(既定値が無いため、本番に無い列には既定値ではなく 0 や '' が入ってしまう)

この作り方は、ローカルの MySQL の使い捨てデータベースで次のように確かめられる。1 つのセッションで流す(ファイルで流すときは mysql --force)。ERROR 1562 が出るのは 2 行目だけで、残りは通る。

sql
CREATE TABLE sst_part_src (id BIGINT NOT NULL AUTO_INCREMENT, day DATE NOT NULL, name VARCHAR(20) NULL, PRIMARY KEY (id, day)) PARTITION BY RANGE (YEAR(day)) (PARTITION p2026 VALUES LESS THAN (2027), PARTITION p_future VALUES LESS THAN MAXVALUE);
CREATE TEMPORARY TABLE sst_tmp_like LIKE sst_part_src;
CREATE TEMPORARY TABLE sst_tmp (`id` bigint NOT NULL, `day` date NOT NULL, `name` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL);
INSERT INTO sst_tmp (`id`, `day`, `name`) VALUES (1, '2026-10-01', 'a');
INSERT INTO sst_part_src (`day`, `name`) SELECT `day`, `name` FROM sst_tmp;
DROP TABLE sst_part_src;

キャッシュのみ削除したい場合 ​

VERSION の切り替えは不要でキャッシュだけ削除したい場合(DI 定義の変更を反映したい、不具合調査でキャッシュを外したいなど)は、clear-staging-cache.sh を使用します。

bash
./bin/clear-staging-cache.sh

古いビルドを削除したい場合 ​

ステージングサーバーの DEPLOY_REMOTE_PATH 配下に蓄積した core_YYYYMMDD_HHMMSS を削除できます。

bash
# 一覧表示
./bin/clean-remote-builds-staging.sh --list

# 削除対象確認のみ
./bin/clean-remote-builds-staging.sh --keep 3 --dry-run

# 最新3件を残して削除
./bin/clean-remote-builds-staging.sh --keep 3

指定バージョンのみ削除する場合:

bash
./bin/clean-remote-builds-staging.sh --version 20250120_143022

注意: 現在 connector.php が参照しているアクティブバージョンを削除すると、サイトが動作しなくなる可能性があります。削除前に必ず利用中バージョンを確認してください。

管理画面から古いビルドを削除したい場合 ​

ステージング環境の WordPress 管理画面で ツール > ビルド管理 を開くと、サーバー上の core_* ディレクトリ一覧を確認し、不要なバージョンを削除できます。

  • 稼働中のバージョンは削除できません
  • チェックボックスで選択したビルドを削除できます(「最新 N 件を残す」一括削除には未対応)
  • 「最新 N 件を残す」一括削除を行いたい場合は CLI の ./bin/clean-remote-builds-staging.sh を使用してください

トラブルシューティング: ランキング・末尾データが表示されない場合 ​

日次結果ページで「ランキング」「末尾データ」が「エラー: ランキングの取得に失敗しました。」等と表示される場合、REST API が HTML を返している可能性があります。以下を確認してください。

確認項目手順
REST URL該当ページの HTML ソースで dailyArticleAsync.restUrl を確認。同一オリジンの https://www.staging.slotkouryaku.com/wp-json/daily-article/v1/ に近い形か。
エンドポイント直接アクセスブラウザで {restUrl}async-ranking?hall=アイランド秋葉原&date=YYYY-MM-DD を開く。JSON が返るか、HTML(404 等)が返るか。
WP_HOME / WP_SITEURLステージングの wp-config.php または DB の siteurl / home が正しいか。誤っていると rest_url() が別ドメインになり HTML が返る原因になる。
パーマリンクWordPress 管理画面「設定 → パーマリンク」で「変更を保存」を実行し、REST 用リライトを再生成する。
PHP-DI キャッシュwp-content/cache/php-di/CompiledContainer.php を削除して再アクセス。DI 定義変更後にキャッシュが残っているとルートが登録されない場合がある。

関連ドキュメント ​