複数のエリアを同時に更新する hx-swap-oob
a-blog cms の post include で出来なかった事で htmx を採用する事でできるようになる大きなところとして「複数のエリアを同時に更新」が可能になったところではないでしょうか。
上記は htmx を活用したサンプルサイトです。 合わせてご覧ください。
hx-swap-oob 属性とは
要素を置換する場所を指定するには、hx-target属性を使用します。一方で、hx-swap-oob(Out-Of-Band Swapの略)属性を使うことで、hx-targetで指定された要素以外にも、同時に他の部分を置換することができます。
更新前のページで事前準備
更新をかけたい <div>要素について名前をつけておく必要がありますので、id="main-contents" と id="topicpath" という属性を設定します。
一覧ページから詳細ページへのリンク
一覧ページから詳細ページへのリンクとしては以下のように記述します。複数箇所の更新の際にも呼び出し側の記述は特に変化はありません。通常の htmx の hx-get などの記述になります。
<a href="{url}"
hx-get="{url}/tpl/include/htmx/realestate-body.html"
hx-push-url="{url}"
hx-target="#main-contents"
hx-swap="innerHTML"
hx-ext="ajax-header"
class="card-link">呼び出されるテンプレート側の記述
呼ばれるテンプレートには、以下のような記述をします。hx-swap-oob="true" と一緒に書かれている id属性 の部分が置き換わる事になります。
<div id="main-contents" hx-swap-oob="true">
<!-- BEGIN_MODULE Entry_Body -->
(略)
<!-- END_MODULE Entry_Body -->
</div>
<div id="topicpath" hx-swap-oob="true">
<!-- BEGIN_MODULE Topicpath -->
(略)
<!-- END_MODULE Topicpath -->
</div>
<!-- BEGIN_MODULE Ogp -->
<title>htmx:{title}</title>
<!-- END_MODULE Ogp -->おまけ:タイトルタグの更新
上記では、id="main-contents" と id="topicpath" の更新をするように書いていましたが、おまけで <title> の更新もできるようにします。 <title> については、今回の hx-swap-oob とも関係なく読み込んだファイルに <title>タグがあれば上書きをする仕様とのことです。
a-blog cms の場合 Ogp モジュールで <title>を組み立てる処理がありますので、そちらを利用します。 また、テストで更新できたことを分かりやすいようにテスト用のサイトではタイトルタグに htmx: を前につけて htmx でコンテンツを更新したことが分かりやすいようにしています。
htmxで browser history API を活用する方法と a-blog cms 実装のポイント
htmx は標準で browser history API をサポートしており、属性に hx-push-url="true" を追加することで、これを簡単に利用できます。a-blog cms をバックエンドで使用する際の注意点をいくつか紹介します。
※(例)と書かれている部分は実際には動作しません。
hx-push-url 属性を設定して正しく動作する GET
<a>タグでの GETリクエストに対しては、htmx のドキュメントに従い、hx-get属性と hx-push-url属性を追加することを推奨します。
<a href="entry-1.html" hx-get="entry-1.html" hx-push-url="true">記事詳細</a>
hx-push-url 属性を設定しても正しく動作しない POST
POSTリクエストのケースでは、例えば a-blog cms でカスタムフィールド station を選択するための <select> を含むフォームを使用し、結果を表示するテンプレートとして include/htmx/result.html を指定する方法があります。
<form hx-post="" hx-push-url="true" hx-trigger="submit" hx-target="#search-result" hx-ext="ajax-header"> <select name="station"> <option value="Tokyo">Tokyo</option> <option value="Osaka">Osaka</option> <option value="Nagoya">Nagoya</option> </select> <input type="hidden" name="field[]" value="station"> <input type="hidden" name="tpl" value="include/htmx/result.html"> <input type="submit" name="ACMS_POST_2GET" value="検索" > </form> <div id="search-result">この部分に結果が表示されます</div>
a-blog cms の仕様として、<form> の POST 時 name="ACMS_POST_2GET" が送られてくると、検索条件( station = Nagoya )から URL を組み立て、その後リダイレクトされ GET に変換され、以下のような URL でアクセスした結果を取得できます。
https://example.com/htmx/result.html/field/station/Nagoya/
ここで問題が発生します。 上記の URL がブラウザに表示され履歴にも登録されますが、この URL にアクセスすると Ajax で追加される部分的な HTML になってしまいます。この検索結果で履歴に登録されて欲しい URLは、テンプレートファイル include/htmx/result.html のパスが無い以下の URL であって欲しいのです。
https://example.com/field/station/Nagoya/
hx-push-url 属性を設定しても正しく動作する POST 解決編
ここまでで a-blog cms POSTリクエスト後に URL を組み立てる ACMS_POST_2GET の処理が、htmx の hx-push-url と相性が悪い状況を解決する方法を考えてみました。
以下に示す JavaScriptコードを追加することで、hx-push-url 属性の動作を維持しつつ、希望する URL形式を browser history API に正しく渡すことができるようになります。
<script>
addEventListener('htmx:beforeHistoryUpdate', function (event) {
const proposedUrl = event.detail.history.path;
const customUrl = proposedUrl.replace(/\/include\/htmx\/.*\.html/, '');
event.detail.history.path = customUrl;
});
</script>処理としては htmx で History を更新する前の path を取得し、/include/htmx/ 〜 .html 部分を削除するという処理を追加しています。
一般的に a-blog cms の部分的なファイルは include ディレクトリに整理して保存するというルールが定着していますので、htmx で読み込むテンプレートファイルは、その include ディレクトリ内に htmx を用意し、その htmx ディレクトリ内で管理というルールでテーマを構築というルールにする事で上記の JavaScript が有効的に動作させることができます。
モジュールIDのキャッシュ
a-blog cms Ver.2.11.0よりモジュールIDのキャッシュ機能が使えるようになりました。a-blog cms のキャッシュ機能は基本的に、ページ単位でキャッシュを行う仕組みになっております。 そのため、URLが少しでも違うとキャッシュが利用されず、そのページにある全てのモジュールが動作してしまいます。ページを構成する要素はたくさんありますが、例えば「グローバルナビゲーション」や「フッター」の情報などは頻繁に変わるものではありません。 情報は変わっていないのに、そのページにある他の要素が更新されたことで、このような更新が少ないモジュールも毎回PHPが動作して生成しなおすのは、パフォーマンス的にあまりよろしくありません。
そこでVer.2.11.0からはページ単位以外に更新頻度が違うモジュールごとにキャッシュができる仕組みを導入しました。
設定方法
管理画面 > モジュール > 該当するモジュールIDに移動します。「条件設定」を開き「キャッシュ」に分単位で数値を設定します。 ここで設定した時間がキャッシュの有効期限となります。
モジュールキャッシュの削除タイミング
モジュールのキャッシュは以下のような条件で削除されるようになっています。
- 該当のモジュールIDが更新されたタイミング
- 該当のモジュールIDのキャッシュ時間の設定を経過したタイミング
なお、該当のモジュールIDのテンプレートが更新されたタイミングで別のキャッシュができますがキャッシュ自体が削除されるわけではないのでご注意ください。