【WordPress】apartment morningを支える設計判断、4つ



小説サイト「apartment morning」を今回フルリニューアルしたのですが、地味に工夫したポイントがいくつもあります。今回はその中から、設計判断にまつわる4つを紹介します。
JSが無くても機能する「読み方」切り替え
apartment morningには「交互/僕だけ/私だけ」という3つの読み方モードがあります。それぞれのモードの前後リンクは、全部サーバー側(PHP)で計算して、最初から全部DOMに出力してしまっています。JS側はモードごとの表示・非表示をCSSの属性セレクタで切り替えるだけです。
[data-am-mode="boku"] .am-nav__pair[data-mode="boku"] {
display: flex;
}
この作り方だと、JSが無効な環境でもただのリンクとして機能します。いわゆる「プログレッシブ・エンハンスメント」という考え方で、JSは「あったら便利」を追加するだけ、なくても最低限は動く、という状態を保っています。
ダークテーマがちらつかない工夫(FOUC対策)
ダークテーマ・読み方モード・文字サイズの設定はlocalStorageに保存しています。これをbodyの後や外部JSファイルで読み込んで反映すると、ページ遷移のたびに一瞬ライトテーマが見えてからダークに切り替わる、という「FOUC(Flash of Unstyled Content)」が起きてしまいます。
これを避けるために、wp_head()より前、<head>冒頭に同期的なインラインスクリプトを置いて、<html>タグにdata-am-themeなどを先に設定してしまいます。
<head>
<script>
(function () {
var theme = localStorage.getItem('am-theme');
if (theme) document.documentElement.setAttribute('data-am-theme', theme);
})();
</script>
<?php wp_head(); ?>
</head>
CSSの描画が始まる前に属性がついているので、ちらつきなくダークテーマで表示されます。
2つの違うデータモデルを、1つのフラグで完全並行実装
1作目は章ごとに視点が交互に変わる構成、2作目は1話の中に二人の声が同居する構成です。読み方モードの語彙からして別物で(1作目はalt/boku/watashi、2作目はboth/katari/nikki)、無理に共通化はしていません。
カスタムフィールド_am_formatに'pov'(視点交互)か'voice'(二声同居)かを持たせて、テンプレートの一番手前(single-am_episode.phpなど)で処理を完全に分岐させています。本当に共通しているパーツ(上部バーのマークアップなど)だけを引数化して使い回す、という方針です。
表示番号は保存せず、毎回その場で計算する
篇の「01」「02」という通し番号は、実はDBには保存していません。post_status=publishかつ現在の読み方モードでフィルタした配列の「位置」から、表示するたびに算出しています。
この方式にしておくと、予約投稿中の未来の篇は自動的に採番から除外されますし、後から話数を1話挿入しても、リナンバリング用のスクリプトを別に用意する必要がありません。番号は「保存する情報」ではなく「その場で導き出す情報」にしておく、という考え方です。
さいごに
今回は設計判断にまつわる4つを紹介しました。次回は、実装していく中で実際にハマった落とし穴の話をまとめます。





