Appearance
ステージング環境デプロイ(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.env2. 設定する項目
| 変数 | 説明 |
|---|---|
| DEPLOY_HOST | ステージングサーバーのホスト名または IP(本番と同一サーバーの場合は本番と同じ値) |
| DEPLOY_PORT | SSH ポート(省略時は 22) |
| DEPLOY_USER | SSH ログインユーザー名 |
| 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/myCustom3. パーミッション
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 も実行します。
個別実行(部分再実行や確認しながら進めたい場合):
ビルド(未実行の場合)
bash./bin/build.shステージングへアップロード
bash./bin/deploy-staging.shまたはバージョン(タイムスタンプ)を指定する場合:
bash./bin/deploy-staging.sh 20250120_143022バージョンを省略した場合: 実行ログに表示されるバージョン名か、以下のコマンドで
_buildディレクトリ一覧から最新を確認して、次のactivate-staging.shに渡してください。bashls -1 _build/core_* | sort | tail -n 1 | sed 's|.*/core_||'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動作
- 本番に対しては SELECT と
mysqldump --single-transactionだけを行う。本番 DB には書き込まない - staging DB の
homeがSTAGING_SITE_URLと一致しないときは、何も書き込まずに中止する - staging の対象期間の日別記事(リビジョン・ターム紐付けを含む)・リンク・台データ・集計・P-WORLD サムネ、期間が重なるヒートマップのレイアウトと、前年同日の日別記事・リンク・サムネを消してから、本番の行を入れる。有料記事は、本番から入れる記事と同じ ID の staging の有料記事(リビジョン・ターム紐付けを含む)だけを消す。マスタは staging 側を全件入れ替える。削除と取り込みは 1 つのトランザクションで行う(巻き戻せるのは InnoDB のテーブルだけ)
- 投稿 ID とマスタの ID は本番のまま入れる。それ以外のテーブル(リンク・集計・レイアウト・サムネ・post meta など)は自動採番の
idを振り直し、期間外の staging の行を上書きしない - 本番から入れる投稿 ID を、staging の別の投稿(日別記事なら対象期間の日別記事、有料記事なら同じ ID の有料記事と、それぞれのリビジョン以外。下書き・添付も含む)が使っている場合は、何も書き込まずに中止する。この検査は確認プロンプトの前と、書き込む直前の 2 回行う。有料記事は、書き込む直前に集め直した ID が確認プロンプトの前に表示した一覧と違えば中止する。ダンプも
post_status = 'publish'の記事に絞る 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 で置き換える- 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 定義変更後にキャッシュが残っているとルートが登録されない場合がある。 |
関連ドキュメント
- デプロイ後チェックリスト: デプロイ後テスター向けの確認項目(公開ページ・API・管理画面・インポートフロー)
- 本番環境デプロイ: 本番へのデプロイ手順
- PHPバージョンの更新: ConoHa WING での PHP バージョン・php.ini の設定(ステージングはドメイン個別設定に注意)
- 本番環境への接続方法: ConoHa WING の接続情報の取得方法(ステージングも同一サーバーなら同じ情報を利用)