Appearance
日別記事 初期描画フロー
日別記事(daily_article)公開画面の初期描画フローを記録したドキュメントです。
プロジェクト構成(概要) の詳細です。ショートコードの一般的な MVC フローは ショートコードの処理の流れ を参照してください。
概要
日別記事の公開画面は、次の 2 系統 × 3 段階 で構成されています。
| 段階 | 系統 A: ページ全体(DailyArticleTemplate) | 系統 B: 日別記事結果(DailyArticleResult ショートコード) |
|---|---|---|
| 1. PHP 同期 | Twig テンプレート + ナビ用 link_day_data のみ(L1) | プレースホルダー HTML + CSS/JS enqueue |
| 2. キャッシュ | 共有データは warm REST で L2/Hash Transient を生成 | なし(ランキング等は REST 側で別キャッシュ) |
| 3. JS 非同期 | warm → RelationalDay / MoveDayHall / MailImage 等を並列取得 | ランキング・ヒートマップ・末尾等を REST で取得 |
設計の要点
- 初回 HTML では
initialize_navigation()により 前日・翌日・前年リンク用の link_day_data を同期取得する(Issue #2182 Phase 1)。 - 関連日・MoveDayHall・MailImage・日別記事結果は プレースホルダ + REST で遅延描画する。
daily_article_orchestrator.jsが warm(POST)→ UI REST 並列 の順で制御する(Issue #2183 / #2185)。- 共有データ(主に
daily_link_list+daily_data_kishu_list、加えてlink_day_dataも DTO に含む)の L2/Hash はwarm_shared_template_data()で生成する。Shared L1($cached_data)は PHP static のため HTTP リクエストをまたいでは共有されない。warm_shared_template_data()は warm REST 内でも L1 に DTO を載せるが、後続の HTTP リクエスト(UI REST 等)へ引き継がれる永続化は L2/Hash Transient のみである。後続 UI REST では L2_HIT 時に同一リクエスト内で L1 に復元する。L2 ヒット時のハッシュ検証はcompute_lightweight_data_hash()で行う。Hash Transient のデフォルト TTL は 300 秒(HASH_TRANSIENT_EXPIRATION、L2 Transient TTL と揃える。フィルターslot_kouryaku_daily_article_template_hash_transient_expirationで変更可)。link_day の insert/update/delete 時は push 型で対象日の L2 + Hash Transient を無効化する。
同期 / 遅延の境界
同期(初回 HTML に含める)
| 要素 | データ源 | 備考 |
|---|---|---|
| 記事タイトル | post meta | 現状どおり |
| 前日・翌日テキストリンク | initialize_navigation() | Twig 上部ナビでは link_day_data.previous_day / next_day のみ表示。last_year はナビには出さず、MoveDayHallService 内で前年リンク生成(prev_year_post_data)に利用される。1 クエリ |
| 月別リンク | [MonthlyLinkByYear] | 既存 ShortCode(共有 warm とは独立) |
| 考察・広告等 | 既存 ShortCode | 同期は維持 |
遅延(DOMContentLoaded 以降)
| 要素 | REST | 備考 |
|---|---|---|
| 共有データ warm | POST /async-warm-template-data | HTML なし、L2/Hash 生成 |
| 関連日 + 日別カレンダー | GET /async-relational-day | ホール数分 |
| MoveDayHall | GET /async-move-day-hall | ホール数分(サムネ含む) |
| MailImage | GET /async-mail-image | ホール数分 |
| ランキング等 | API-001-1, 3, 9 等 | DailyArticleResult 系 |
既存投稿本文に直書きされた [MailImage] ショートコードは同期のまま(テンプレート経路のみ非同期)。詳細は SC-007 を参照。
関連ファイル
図 1: 全体俯瞰シーケンス
Browser から HTML 受信後、orchestrator が warm → UI REST を開始するまでの時系列です。
補足
- 系統 A はページ全体を Twig で描画します。RelationalDay / MoveDayHall / MailImage は Twig 内のプレースホルダ div です。Twig 内の
[CustomCode_CreateDailyArticleResult ...]等はdo_shortcode()で展開されます。 - 系統 B の初回 HTML はプレースホルダーです。ランキング・ヒートマップ・末尾データの実データは orchestrator 経由の REST で後から取得します。
DailyArticleResultController.build_presentation()は REST 非同期用(service->execute()+ ヒートマップレイアウト取得)であり、ショートコード初回 HTML では使われません。DailyArticleTemplateDataService.initialize()はinitialize_navigation()+warm_shared_template_data()の一括実行用(deprecated)。初回 HTML ではinitialize_navigation()のみ呼ばれます。
図 2: warm_shared_template_data() キャッシュ分岐
共有データ(daily_link_list + daily_data_kishu_list + link_day_data)の取得経路です。POST /async-warm-template-data または各 UI REST Handler のフォールバックから呼ばれます。
キャッシュ層の定義
| 層 | 実装 | 格納内容 | 有効範囲 |
|---|---|---|---|
| ナビ L1 | static $navigation_link_day_data | LinkDayData(前日・翌日・前年 URL) | 同一 HTTP リクエスト内のみ(initialize_navigation) |
| L1(Shared) | static $cached_data | DailyArticleTemplateDataPresentationDto | 同一 HTTP リクエスト内のみ |
| L2(Shared) | WordPress Transients | ['dto' => DTO, 'data_hash' => string] | リクエスト間(TTL 300 秒) |
| Hash Transient | WordPress Transients(日付単位) | SHA-256 ハッシュ文字列 | リクエスト間(デフォルト TTL 300 秒。フィルター slot_kouryaku_daily_article_template_hash_transient_expiration で変更可) |
Transient TTL / cleanup 運用設計(Issue #2046)
| 項目 | 設計 |
|---|---|
| L2 Transient TTL | 300 秒(DailyArticleTemplateDataService::TRANSIENT_EXPIRATION)。date + halls ごとに 1 キー。 |
| Hash Transient TTL | 300 秒(DailyArticleTemplateDataService::HASH_TRANSIENT_EXPIRATION、フィルターで変更可)。date ごとに 1 キー。 |
| 想定エントリ数 | 同時滞留キーは概ね「直近 TTL 区間でアクセスされた date + halls 件数 + date 件数」。TTL 経過で期限切れ化。 |
| 定期掃除 | TransientCleanupScheduler が daily cron(slot_kouryaku_daily_transient_cleanup)で delete_expired_transients( true ) を実行。 |
| 多重実行対策 | slot_kouryaku_transient_cleanup_lock(1時間TTL)で二重実行を抑止。stale / 不正ロックは回収して再試行。 |
この設計により、期限切れ transient の残存は短TTL + 定期 cleanup で収束し、wp_options 肥大化リスクを抑える。
分岐パス一覧
| パス | DB アクセス | 備考 |
|---|---|---|
| NAV_L1_HIT | なし | ナビ用 link_day_data を static から利用 |
| NAV_FETCH | fetch_link_day_data 1 本 | 初回 HTML 同期時 |
| L1_HIT(Shared) | なし | static 変数から DTO をそのまま利用 |
| L2_HIT | 原則なし(Hash Transient ミス時のみ集約 stats 2 本) | Transient から DTO 復元 → L1 に載せ替え |
| L2_HASH_MISMATCH | あり(DB_FETCH へ) | L2・Hash Transient を削除 |
| L2_MISS / L2_INVALID | あり(DB_FETCH へ) | 古い L2 を削除して下へ |
| DB_FETCH | フル取得 | link 一覧、機種サマリ、link_day → L1/L2/Hash Transient 保存 |
ハッシュ検証の目的
L2 は 5 分 TTL のため、phpMyAdmin 等の DB 直接変更を Transient 期限だけでは検知できません。compute_lightweight_data_hash() / compute_data_hash_from_fetched_data() で SHA-256 ハッシュを計算し、L2 に保存した data_hash と照合します(Issue #2175 / #2170)。Hash Transient が有効な間(デフォルト最大 300 秒)は DB 変更を即時検知しません。link_day の URL/event 更新は push 型無効化で検知します。
図 3: JS orchestrator シーケンス
daily_article_orchestrator.js が DOMContentLoaded 後に warm → UI REST を呼び出す流れです。
orchestrator のルール
- warm 完了(または失敗待機)後に UI REST を並列発火 — キャッシュスタンピード防止
- warm 中はプレースホルダ表示のまま
- warm 失敗時も UI REST をそのまま並列発火(各 Handler が
warm_shared_template_dataで個別フォールバック) - UI REST のレスポンスは生 HTML ではなく JSON(
parseJsonResponse()→data.htmlを DOM に反映。テンプレート断片系はdata.assetsも読み込む)
REST エンドポイント
ベース URL: /wp-json/daily-article/v1/(dailyArticleAsync.restUrl 経由)
| コード | パス | method | トリガー | 用途 |
|---|---|---|---|---|
| API-001-10 | /async-warm-template-data | POST | ページ読み込み直後 | 共有データ L2 warm(HTML なし) |
| API-001-11 | /async-relational-day | GET | ページ読み込み直後 | 関連日 + 日別カレンダー |
| API-001-12 | /async-move-day-hall | GET | ページ読み込み直後 | MoveDayHall |
| API-001-13 | /async-mail-image | GET | ページ読み込み直後 | MailImage |
| API-001-9 | /async-heatmap-simple | GET | ページ読み込み直後 | ヒートマップ簡易 |
| API-001-1 | /async-ranking | GET | ページ読み込み直後 | ランキング |
| API-001-3 | /async-end-number | GET | ページ読み込み直後 | 末尾データ |
| API-001-2 | /async-heatmap-detail | GET | 詳細ボタン初回クリック | ヒートマップ詳細 |
| API-001-4 | /async-kishu-search | GET | 検索ボタンクリック | 機種指定データ検索 |
| API-001-14 | /async-kishudata | GET | ページ読み込み直後 | 機種データ(SC-009) |
権限: 上記 Async 系は nonce + IP レート制限(60 秒 10 回)。詳細は API-一覧.md を参照。
PHP → JS データ受け渡し
core_src/View/templates/daily_article_result/index.php が wp_localize_script で以下を渡します。
| キー | 内容 |
|---|---|
restUrl | rest_url('daily-article/v1/') |
nonce | wp_create_nonce('wp_rest') |
msgRankingFailed 等 | 非同期エラー文言 |
Twig ルート要素 .daily-article-template の data-warm-date / data-warm-halls が warm リクエストの入力です。
Twig プレースホルダ
daily_article_template.twig では次のプレースホルダを使用します。
| 要素 | CSS クラス | data 属性(例) |
|---|---|---|
| MailImage | mail-image-placeholder | data-hall, data-date |
| MoveDayHall | move-day-hall-placeholder | data-hall, data-date, data-preday, data-nextday |
| RelationalDay | relational-day-placeholder | data-hall, data-date |
| DailyArticleResult | 既存プレースホルダクラス | data-hall, data-date 等 |