htmx と a-blog cms で作る「もっと見る」ボタンの実装方法

まず、実践的な実装方法の一つとして、標準的なページャー UI を Ajax を使用した動的コンテンツ読み込みに置き換える方法を紹介します。これを実現するために、htmx を利用します。



head に htmx のライブラリを読み込み

<script src="https://unpkg.com/htmx.org@1.9.10"></script>
<script src="https://unpkg.com/htmx.org/dist/ext/ajax-header.js"></script>

a-blog cmshtmx のバックエンドに利用する場合、ajax-header.js の読み込みが必要ですので、ご注意ください。

リスト表示のモジュールのページャーをカスタマイズ

リスト表示用のモジュールのページャーをカスタマイズします。以下の例では、次のページへのリンクをカスタマイズしています。

<!-- BEGIN pager:veil -->
<!-- BEGIN forwardLink -->
<form hx-post="" hx-ext="ajax-header" hx-trigger="click" hx-target="this" hx-swap="outerHTML" class="acms-text-center">
 <input type="hidden" name="bid" value="1">
 <input type="hidden" name="cid" value="7">
 <input type="hidden" name="tpl" value="/include/htmx/headline.html">
 <input type="hidden" name="page" value="{forwardPage}">
 <p class="acms-text-center">
  <input type="submit" name="ACMS_POST_2GET" value="次の{forwardNum}件へ"
  class="acms-btn acms-btn-primary acms-btn-large">
 </p>
</form><!-- END forwardLink -->
<!-- END pager:veil -->

tpl を利用する際の private/cofig.system.yaml 設定

設定を全体を解除する(非推奨)

forbid_tpl_url_context: off

設定を部分的に解除する(推奨)

forbid_tpl_url_context: on
allow_tpl_path: [include/htmx/headline.html]

テンプレートファイルの html チェック

拡張子が .html のファイルが HTML フォーマットでない場合に 404 エラーを返す設定を無効にします。これは、a-blog cms が部分的な HTML を読み込めるようにするために必要です。

html_format_validate: off

続きを読み込む際の HTML で気を付けること

モジュールを <ul><li>〜</li></ul> で読み込む設定をすると、複数の <ul> タグが生成されることがあります。<li>〜</li> 部分だけを読み込み、全体として1つの <ul> タグで済むようなマークアップを心がけましょう。

_top.html

<h2 class="section-heading acms-text-center">お知らせ</h2>
<div class="module-section">
	<ul class="headline headline-1col acms-list-group clearfix" aria-labelledby="layout-top_headline">
	@include("/include/htmx/headline.html")
	</ul>
</div>

include/htmx/headline.html

<!-- BEGIN_MODULE Entry_Headline id="headline_news" -->
@include("/admin/module/setting.html")
<!-- BEGIN entry:loop -->
  <li class="headline-item {entry:loop.class}">
   <!-- BEGIN url#front --><a href="{url}" class="acms-list-group-item headline-link"><!-- END url#front -->
   <time class="headline-dat" datetime="{date#Y}-{date#m}-{date#d}">{date#Y}年{date#m}月{date#d}日( {date#week} )</time>
   <!-- BEGIN category:veil --><span class="acms-label">{categoryName}</span><!-- END category:veil -->
   <span class="headline-title">{title}</span><!-- BEGIN new --><span class="acms-label acms-label-danger">NEW</span><!-- END new -->
   <!-- BEGIN url#rear --></a><!-- END url#rear -->
  </li><!-- END entry:loop -->
  <!-- BEGIN pager:veil -->
  <li>
   <!-- BEGIN forwardLink -->
   <form hx-post="" hx-ext="ajax-header" hx-trigger="click" hx-target="this" hx-swap="outerHTML"
    class="acms-text-center">
    <input type="hidden" name="bid" value="1">
    <input type="hidden" name="cid" value="7">
    <input type="hidden" name="tpl" value="/include/htmx/headline.html">
    <input type="hidden" name="page" value="{forwardPage}">
    <p class="acms-text-center">
     <input type="submit" name="ACMS_POST_2GET" value="次の{forwardNum}件へ"
      class="acms-btn acms-btn-primary acms-btn-large">
    </p>
   </form><!-- END forwardLink -->
  </li>
  <!-- END pager:veil -->
<!-- END_MODULE Entry_Headline -->

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 の処理が、htmxhx-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 が有効的に動作させることができます。

post_include を次のレベルへ! a-blog cms における htmx の活用法

ウェブサイトやブログをよりインタラクティブにするためには、革新的な技術の採用が欠かせません。特に a-blog cms を使用している皆さんにとって、post include 機能は、フォームの POSTメソッドを介したデータ送信に依存することで、コンテンツの動的な組み込みや更新を可能にする強力なツールとして知られています。しかし、この機能の利用シナリオが POSTメソッドに限定されていることは、その潜在能力を完全には引き出していないかもしれません。

そこで登場するのが htmx です。この軽量な JavaScriptライブラリは、HTML を直接拡張し、Ajax、CSS Transitions、WebSocketsなどを簡単に利用できるようにすることで、ウェブページにリッチなインタラクティビティをもたらします。htmx を使用することで、post include 機能を単なるフォーム送信の枠を超えて、ページ全体の非同期更新や動的コンテンツの表示に活用できるようになります。

本記事では、a-blog cms における post include 機能の基本から出発し、htmx を組み合わせることでどのようにその適用範囲を拡大し、サイトのユーザーエクスペリエンスを向上させることができるのかを掘り下げていきます。従来の使い方に慣れ親しんでいた方々も、htmx が開く新しい扉に驚くことでしょう。


a-blog cms の post include 機能とは

a-blog cms における post include 機能は、10年以上前から提供されている、Ajaxを利用したコンテンツの動的読み込み機能です。この機能は、特にフォームを介した POST メソッドのリクエストを介して、指定された HTMLテンプレートファイルの内容をページに非同期で挿入することができます。このプロセスは、ユーザーのページ遷移を発生させることなく、リッチなユーザーエクスペリエンスを提供します。

基本的な post include の実装方法

post include 機能の一般的な利用例としては、以下のようなフォームのコードが挙げられます。

<form action="" method="POST" class="js-post_include" target="#result">
  <input type="text" name="keyword" value="">
  <input type="hidden" name="tpl" value="result.html">
  <input type="submit" name="ACMS_POST_2GET" value="検索">
</form>
<div id="result">検索結果が表示されるエリア</div>

このコードは、検索ボタンがクリックされた後に、ページを遷移することなく result.html を読み込み、<div id="result">〜</div> を置き換えます。 class="js-post_include" が指定されたフォームは、この動的な読み込みをトリガーとする特別な役割を持っています。



js-post_include フォームの送信ボタンを押した後に実行する
js-post_include-ready ページを読み込んだら自動的に実行する
js-post_include-bottom ページの下部までスクロールしたら自動的に実行する
js-post_include-interval 一定時間ごとに自動的に実行する

また、result.html のコードは以下のように書かれています。

<!-- BEGIN_MODULE Entry_List -->
  <ul>
    <!-- BEGIN entry:loop -->
      <li><a href="{url}">{title}</a></li>
    <!-- END entry:loop -->
  </ul>
<!-- END_MODULE Entry_List -->

htmx とは

a-blog cms を利用している方に向けた分かりやすい紹介として、htmx は、post include のように、複雑な JavaScript を記述せずとも HTML属性を加えるだけで Ajax を用いたコンテンツの読み込みを可能にする JavaScriptライブラリです。

a-blog cmspost include(acms.js)に比べて軽量であり、POST メソッドだけでなく GET メソッドでのリクエスト設定も可能です。記事の一覧のリンクからでも、Ajax でコンテンツの読み込みができるようになったり、1つのエリアだけでなく複数の離れたエリアを同時に更新することも可能です。

post include から htmx に変更する

post include で実装したコードを htmx に置き換えると、以下のようになります。

<form action="" method="POST" hx-post="/" hx-trigger="click" hx-target="#result" hx-swap="outerHTML">
  <input type="text" name="keyword" value="">
  <input type="hidden" name="tpl" value="result.html">
  <input type="submit" name="ACMS_POST_2GET" value="検索">
</form>
<div id="result">検索結果が表示されるエリア</div>

<form> タグに htmx の属性を追加するだけで、同様の動作が実現できます。これであれば、post inculde でコンテンツを読み込む実装ができる方であれば、htmx を使えるようになることも難しくないのではないでしょうか。

<a href="result.html" hx-get="result.html" hx-trigger="click" hx-target="#result" hx-swap="outerHTML">クリック</a>
<div id="result">検索結果が表示されるエリア</div>

さらに、a-blog cmspost include で実現できない機能として、リンクに hx-get 属性を設定することで、htmx の実行が可能です。

<head> で読み込む JavaScript

<script src="https://unpkg.com/htmx.org@1.9.10"></script>
<script src="https://unpkg.com/htmx.org/dist/ext/ajax-header.js"></script>

a-blog cms のテンプレートの中で、htmx を呼ぶためには、hx-ext="ajax-header" を追加する必要があります。そして、これを利用するためには、<head> タグ内に以下のように htmx のライブラリとあわせて ajax-header.js も読み込みます。

今回は、CDN を利用していますが、テストではなく実運用するサイトでは、ダウンロードしてご自身のサイトに JavaScript を設置してご利用ください。

実践的な例

現在、htmx@site という名前で、site テーマの子テーマとして、htmx を活用したテーマの実験的な作成を進めています。

お知らせコンテンツのページャーを htmx 化

site テーマのトップページに配置された「お知らせ」セクションでは、htmx を用いて、続く「お知らせ」記事を読み込む機能を実装しています。


物件情報の検索機能を htmx 化

キャプチャ画像では詳細が伝わりにくいかもしれませんが、この機能により、ユーザーが物件を検索する際の画面遷移を排除し、結果の一覧と詳細ページをスムーズに更新できるようになっています。


このカスタマイズを施したテーマに関しては、後日このブログで詳細な解説と共に、テーマのダウンロードリンクを提供予定です。

まとめ

この記事を通じて、a-blog cmspost include 機能に既に精通している方々に、htmx の導入が難しくないことをお伝えしたいと思います。更に、htmx を利用することで、a-blog cms の開発者は、従来は実現困難だった新しいUI/UXを提案できるようになります。

htmx はページ遷移なしにコンテンツを簡単に読み込むことができるシンプルな仕組みを提供します。この軽量なライブラリと、デザインとロジックの分離を実現し、直感的で理解しやすいテンプレートを提供する CMS である a-blog cms との組み合わせは、非常に相性が良いです。

両者はシンプルでローコードなアプローチを共有しており、htmx の活用法を共有することが、a-blog cms の開発者にとって非常に有益であると考えています。

引き続き、htmx に関するカテゴリーを新たに追加しましたので、さらなる Tips を共有していきます。どうぞお楽しみに。

エントリ一覧をページリロードなしで表示する

次のページをその場で表示する

a-blog cmsにはポストインクルードというAJAXを簡単に扱う為の仕組みがあります。 その仕組みを使ってページリロードなしにどんどんエントリーを表示してみます。

まずは、Entry_Bodyを使いボタンを押す事により次のページを引っ張ってきます。

実装方法