Skip to content

日別記事 初期描画フロー ​

日別記事(daily_article)公開画面の初期描画フローを記録したドキュメントです。

プロジェクト構成(概要) の詳細です。ショートコードの一般的な MVC フローは ショートコードの処理の流れ を参照してください。

概要 ​

日別記事の公開画面は、次の 2 系統 × 3 段階 で構成されています。

段階系統 A: ページ全体(DailyArticleTemplate)系統 B: 日別記事結果(DailyArticleResult ショートコード)
1. PHP 同期Twig テンプレート + ナビ用 link_day_data(L1)+ 先頭ホール MailImage SSR(Issue #3609)。HTML 断片 Transient ヒット時に Twig/SC をスキップ(プレビュー以外。ログイン状態は問わない)。断片 HIT/MISS 後に遅延ブロック HTML を stitchプレースホルダー HTML + CSS/JS enqueue(ブロックキャッシュ HIT 時はページ側で完成 HTML に置換済み)
2. キャッシュ共有データは warm REST で L2/Hash Transient。初回 HTML は rendered HTML Transient(広告は未展開)。遅延ブロックは block HTML Transient + POST /async-warm-block-htmlランキング等は UI REST でも block HTML を get/set
3. JS 非同期L2 warm と block-html warm と残 MailImage バッチを並列 → L2 warm 後に IntersectionObserver で断片(PH 0 件なら REST スキップ)ランキング・ヒートマップ・末尾等も同様に IO 遅延 REST

設計の要点

  • 初回 HTML では initialize_navigation() により 前日・翌日・前年リンク用の link_day_data を同期取得する(HTML 断片ヒット時はスキップ)。
  • HTML 断片(daily_article_html_v2_)は Content → DailyArticleTemplateFrontendRenderer の最外周。ヒット時は遅延ブロック stitch →(変更があれば断片 Transient を更新)→ DailyArticleSingularAssetEnqueuer で orchestrator / nonce / MailImage 等を enqueue し、広告ショートコードのみ do_shortcode。鮮度は記事保存・日付クリア・HashInvalidator・有料記事の公開/Twitter 更新・機種表示マッピング更新・デプロイ時の全体世代更新の明示クリアが正(TTL 12h は安全網)。
  • 遅延ブロック HTML(daily_article_block_html_v1_)は UI REST の完成 HTML をブロック単位で保存し、次回ページ GET でプレースホルダを置換する。ヒートマップ簡易は pc / sp キーを分離し、当面 stitch / warm は PC キーのみ(SP 表示は #2828 のまま非表示)。POST /async-warm-block-html が MailImage / MoveDayHall / 関連日 / kishu_count_delta / ランキング / 末尾 / ヒートマップ簡易(PC)を埋める(kishudata は UI REST 経由。既存 L2 warm とは別。UI REST ゲートに使わない)。
  • 先頭ホールの MailImage のみ MailImageController::execute() で同期描画する(失敗時はプレースホルダへフォールバック。アーカイブは最大 2 フレーム)。他ホールの MailImage・関連日・MoveDayHall・日別記事結果は プレースホルダ + REST(ブロックキャッシュ HIT 時はプレースホルダ無し)。
  • daily_article_orchestrator.js が L2 warm・block-html warm・残 MailImage バッチを並列し、L2 warm 完了後に残りの UI REST を開始する(.mail-image-placeholder が 0 件なら MailImage バッチはスキップ。stitch 済みで PH 0 件なら該当 REST もスキップ)。
  • 共有データ(主に 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 断片・ブロック HTML を無効化する。

キャッシュ優先順位

  1. HTML 断片(ヒットならテンプレ組み立てをしない。続けてブロック HTML stitch)
  2. 遅延ブロック完成 HTML(ページ stitch / UI REST HIT)
  3. L2 DTO(warm / UI REST)
  4. 考察 the_content Transient(ミス経路)
  5. 日付→投稿ID(パーマリンク)

同期 / 遅延の境界 ​

同期(初回 HTML に含める) ​

要素データ源備考
記事タイトルpost meta現状どおり
前日・翌日テキストリンクinitialize_navigation()Twig 上部ナビでは link_day_data.previous_day / next_day のみ表示。last_year はナビには出さず、MoveDayHallService 内で前年リンク生成(prev_year_post_data)に利用される。1 クエリ
先頭ホール MailImageMailImageController::execute()Issue #3609。hall_names[0] のみ。成功時は完成 HTML(mail-image-placeholder なし)+ mail_image.css / mail_image.js を SC-007 と同様に enqueue。失敗時はプレースホルダ
月別リンク[MonthlyLinkByYear]既存 ShortCode(共有 warm とは独立)
考察・広告等既存 ShortCode同期は維持

遅延(DOMContentLoaded 以降) ​

要素REST備考
共有データ warmPOST /async-warm-template-dataHTML なし、L2/Hash 生成
遅延ブロック HTML warmPOST /async-warm-block-htmlHTML なし。対象ブロックを Transient に埋める(L2 warm / UI REST と並列)
関連日 + 日別カレンダーGET /async-relational-dayホール数分
MoveDayHallGET /async-move-day-hall-batch全ホール 1 リクエスト(失敗ホールは単体 GET でリトライ)
MailImage(2 ホール目〜)GET /async-mail-image-batchプレースホルダがあるホールのみ(先頭 SSR 成功分は除外。失敗ホールは単体 GET)
ランキング等API-001-1, 3, 9 等DailyArticleResult 系

既存投稿本文に直書きされた [MailImage] ショートコードは 従来どおり同期のまま(テンプレート先頭ホール SSR とは別経路。二重定義しない)。詳細は SC-007 を参照。

関連ファイル ​

役割パス
テンプレート入口core_src/Template/daily_article_template/components/DailyArticleTemplateContent.php
テンプレート Controllercore_src/Controller/daily_article_template_controller/DailyArticleTemplateController.php
実行 Servicecore_src/Service/daily_article_template_execution_service/DailyArticleTemplateExecutionService.php
共通データ Servicecore_src/Service/daily_article_template_data_service/DailyArticleTemplateDataService.php
Twig テンプレートcore_src/View/templates/daily_article_template/daily_article_template.twig
日別記事結果 ShortCodecore_src/short_code/daily_article_result/daily_article_result_short_code/DailyArticleResultShortCode.php
日別記事結果 Controllercore_src/Controller/daily_article_result_controller/DailyArticleResultController.php
非同期 JScore_src/View/templates/daily_article_result/daily_article_orchestrator.js
REST Handlercore_src/Handler/async_loading_handler/AsyncLoadingHandler.php
API 一覧docs/design/一覧/API-一覧.md

図 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 のフォールバックから呼ばれます。

キャッシュ層の定義 ​

層実装格納内容有効範囲
ナビ L1static $navigation_link_day_dataLinkDayData(前日・翌日・前年 URL)同一 HTTP リクエスト内のみ(initialize_navigation)
L1(Shared)static $cached_dataDailyArticleTemplateDataPresentationDto同一 HTTP リクエスト内のみ
L2(Shared)WordPress Transients['dto' => DTO, 'data_hash' => string]リクエスト間(TTL 300 秒)
Hash TransientWordPress Transients(日付単位)SHA-256 ハッシュ文字列リクエスト間(デフォルト TTL 300 秒。フィルター slot_kouryaku_daily_article_template_hash_transient_expiration で変更可)

Transient TTL / cleanup 運用設計 ​

項目設計
L2 Transient TTL300 秒(DailyArticleTemplateDataService::TRANSIENT_EXPIRATION)。date + halls ごとに 1 キー。
Hash Transient TTL300 秒(DailyArticleTemplateDataService::HASH_TRANSIENT_EXPIRATION、フィルターで変更可)。date ごとに 1 キー。
想定エントリ数同時滞留キーは概ね「直近 TTL 区間でアクセスされた date + halls 件数 + date 件数」。TTL 経過で期限切れ化。
定期掃除期限切れ transient は 保守クリーンアップバッチ で掃除する。
多重実行対策定期掃除側の排他制御は 保守クリーンアップバッチ を参照する。

この設計により、期限切れ transient の残存は短TTL + 定期 cleanup で収束し、wp_options 肥大化リスクを抑える。

分岐パス一覧 ​

パスDB アクセス備考
NAV_L1_HITなしナビ用 link_day_data を static から利用
NAV_FETCHfetch_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 と照合します。Hash Transient が有効な間(デフォルト最大 300 秒)は DB 変更を即時検知しません。link_day の URL/event 更新は push 型無効化で検知します。


図 3: JS orchestrator シーケンス ​

daily_article_orchestrator.js が DOMContentLoaded 後に warm と MailImage バッチを並列開始し、warm 完了後に残りの UI REST を呼び出す流れです。

orchestrator のルール ​

  1. 残 MailImage バッチは warm と並列開始(.mail-image-placeholder のみ。先頭ホール SSR 成功ノードは除外。PH 0 件なら投入しない。可視があれば優先度 0)— 共有 L2 に依存しないためスタンピードを増やさない
  2. それ以外の UI REST は warm 完了(または失敗待機)後に並列発火 — キャッシュスタンピード防止。MoveDayHall も全ホールバッチ 1 本
  3. warm 中は(先行した MailImage バッチ以外)プレースホルダ表示のまま
  4. warm 失敗時も UI REST をそのまま並列発火(各 Handler が必要に応じて warm_shared_template_data で個別フォールバック。MailImage はフォールバック不要)
  5. UI REST のレスポンスは生 HTML ではなく JSON(バッチは items + 共通 assets。単体は html)。失敗ホールは単体 GET でリトライ
  6. 二重取得は isAsyncLoadStarted / バッチ enqueue フラグで抑止する

REST エンドポイント ​

ベース URL: /wp-json/daily-article/v1/(dailyArticleAsync.restUrl 経由)

コードパスmethodトリガー用途
API-001-10/async-warm-template-dataPOSTページ読み込み直後(MailImage バッチ・block-html warm と並列)共有データ L2 warm(HTML なし)
API-001-18/async-warm-block-htmlPOSTページ読み込み直後(L2 warm 完了を待たない。UI ゲートなし)遅延ブロック HTML warm(HTML なし)
API-001-11/async-relational-dayGETwarm 後・IO(rootMargin 100px)関連日 + 日別カレンダー
API-001-17/async-move-day-hall-batchGETwarm 後・全ホール 1 本(プール優先度 1/2)MoveDayHall バッチ(単体はリトライ用)
API-001-16/async-mail-image-batchGETwarm と並列・全ホール 1 本(可視あれば優先度 0)MailImage バッチ(L2 warm なし)
API-001-12/async-move-day-hallGETバッチ失敗ホールのリトライMoveDayHall 単体
API-001-13/async-mail-imageGETバッチ失敗ホールのリトライMailImage 単体(L2 warm なし)
API-001-9/async-heatmap-simpleGETwarm 後・IO(rootMargin 100px、デスクトップのみ)ヒートマップ簡易
API-001-1/async-rankingGETwarm 後・IO(rootMargin 100px)ランキング
API-001-3/async-end-numberGETwarm 後・IO(rootMargin 100px)末尾データ
API-001-2/async-heatmap-detailGET詳細ボタン初回クリックヒートマップ詳細
API-001-4/async-kishu-searchGET検索ボタンクリック機種指定データ検索
API-001-14/async-kishudataGETwarm 後・IO(rootMargin 100px)機種データ(SC-009)

権限: 上記 Async 系は nonce + IP レート制限(読み取り系 60 秒 300 回、warm 系 60 秒 60 回)。詳細は API-一覧.md を参照。

PHP → JS データ受け渡し ​

core_src/View/templates/daily_article_result/index.php が wp_localize_script で以下を渡します。

キー内容
restUrlrest_url('daily-article/v1/')
noncewp_create_nonce('wp_rest')
msgRankingFailed 等非同期エラー文言

Twig ルート要素 .daily-article-template の data-warm-date / data-warm-halls が warm リクエストの入力です。


Twig プレースホルダ ​

daily_article_template.twig では次のプレースホルダを使用します。

要素CSS クラスdata 属性(例)
MailImagemail-image-placeholderdata-hall, data-date(先頭ホール SSR 成功時はクラス無しの完成 HTML。バッチ対象外)
MoveDayHallmove-day-hall-placeholderdata-hall, data-date, data-preday, data-nextday
RelationalDayrelational-day-placeholderdata-hall, data-date(固定シェル=見出し・pending・カレンダー骨格を SSR 先行表示。失敗時は .relational-day-placeholder__pending 内のみエラー)
DailyArticleResult既存プレースホルダクラスdata-hall, data-date 等

CSS 責務 ​

  • 枠・主要レイアウト: daily_article_template.css でも最終 BEM(.mail-image__content / .move-day-hall / .relational-day-result-section / .daily-result-calendar-wrapper 等)に載せる。 成功パスで *-placeholder を外してもスタイルが切れない。
  • *-placeholder: 読込中セマンティクスのみ(aria-busy と組む状態、予約 min-height、pending スピナー、screen-reader フォールバック等)。
  • component CSS(mail_image.css / move_day_hall.css / daily_result_calendar.css): ショートコード単独・詳細スタイルの正本。first-paint と同値のプロパティは template CSS と同期する。
  • 配信: 日別記事では daily_article_template.css を head preload。component CSS は REST assets 経由で差し替え前に注入。

関連ドキュメント ​