コーポレートサイトでの htmx 実装をデモサイトで試してみよう


2024年2月、JavaScriptライブラリ htmx の発見から始まり、短期間でその可能性に引き込まれ、以下の3つの記事を書きました。




この 3つの記事の投稿後、さらに3つのカスタマイズに関するブログの記事を a-blog cms 開発ブログ htmx に書き、実際に 2つのテーマ siteblog を元に htmx を使った実装を試みました。この記事では、その挑戦の結果と htmx を用いた具体的な利用事例を共有します。

a-blog cms で実現する htmx のバックエンド処理

a-blog cms は10年以上前から、htmx が提供する hx-post のような機能を持っています。(参考)このため、バックエンドの処理はほとんど意識する必要がなく、htmx が必要とする部分的な HTMLコンテンツを生成して送信するだけで済みます。

htmx は、JavaScript を記述することなく Ajax を用いてページ更新が可能です。しかし、バックエンドでは PHP のコードを都度準備する必要があるため、実装が必ずしも容易になるわけではありません。さらに、hx-push-url を利用する場合、htmx によって更新されない時に表示されるページも考慮する必要があり、CMS の積極的な利用が不可欠です。

a-blog cms では、hx-push-url によって更新される URL が検索条件となり、その URL に基づいて選ばれたテンプレートが特定の HTML を生成します。この HTML には、動作する PHPモジュールが記述されています。CMS の管理画面で設定を定義することで、カスタマイズはテンプレートのHTMLを記述するだけで済みます。

結果として、htmx を用いたフロントエンドの記述から、必要とされる HTML を生成するテンプレートまで、すべてがシンプルに処理されます。これにより、htmx のバックエンドとして a-blog cms を利用することで、開発者の負担が大幅に軽減されるのです。

ablogcms.io でhtmxテーマを試す

a-blog cms の可能性を直接体験していただくために、htmx@sitehtmx@blog のテーマを試せるインストール済みのサーバーを無料で 30日間提供するサービス ablogcms.io を用意しています。


このブログ記事の公開に合わせて、これらのテーマを選択して申し込むことが可能です。具体的な実装方法を理解したり、個々のニーズに合わせて実際に試すことができますので、ぜひこの機会に利用してみてください。


どのテーマで試すかを選択し送信することで、メールアドレスに ログイン情報と、SFTP 情報がメールで届きます。テーマファイルがどのような実装になっているのかご確認ください。


a-blog cms でhtmxを利用する方法


htmx を使用するためには、まず次のタグを HTML の <head> 部分に追加する必要があります。

<script src="https://unpkg.com/htmx.org@1.9.12"
integrity="sha384-ujb1lZYygJmzgSwoxRggbCHcjc0rB2XoQrxeTUQyRjrOnlCoYta87iKBWq3EsdM2"
crossorigin="anonymous"></script>

加えて、a-blog cms が Ajaxリクエストを認識できるようにするためには、ajax-header Extension の追加が必要です。この拡張機能は以下のスクリプトを利用して有効化します。

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

hx-gethx-post を使用する際には、hx-ext="ajax-header" の属性を追加することで、a-blog cmshtmx のバックエンドとして動作させることができます。

a-blog cms で hx-post と hx-push-url 利用する際の処理とルール

a-blog cms では、POSTリクエストを使用した検索機能がありますが、この機能は検索条件からURLを組み立てた後、そのURLにリダイレクトしてGETリクエストでページを表示します。

例えば、通常 a-blog cms だけの機能で「kubun=マンション」で検索すると、以下のようなURLになります。

https://example.com/realestate/field/kubun/マンション/

次に、htmx を利用して部分的にページを更新する際には、部分的なコンテンツを表示させるテンプレートを指定する必要があります。このため、以下のような HTMLタグを <form> のタグの中に追加することになります。

<input type="hidden" name="tpl" value="/include/htmx/realestate.html">

さらに hx-push-url="true" を指定し、再度「kubun=マンション」で検索すると

https://example.com/realestate/include/htmx/realestate.html/field/kubun/マンション/

表示されたページの内容には問題はありませんが、上記の URL でブラウザをリロードすると「404 Not Found」エラーが発生してしまいます。これを防ぐために、URLの履歴を更新する前に不要なパスを削除する JavaScript を追加することで対応することができました。

addEventListener('htmx:beforeHistoryUpdate', function (event) {
  const proposedUrl = event.detail.history.path;
  const customUrl = proposedUrl.replace(/\/include\/htmx\/.*\.html/, '');
  event.detail.history.path = customUrl;
});

この JavaScript処理により、/include/htmx/****.html の部分を取り除くことができ、hx-push-url属性を問題なく使用できるようになります。この設定は、a-blog cmshx-post を行う際に「使用するテンプレートファイルを /include/htmx ディレクトリに保管する」ことで効果を発揮します。

htmx 実行後の a-blog cms の JavaScript を実行

htmx による DOM の更新後に a-blog cms の JavaScript を再度実行するためには、次のコードが必要です。これにより、更新された要素に対して必要な JavaScript が適用されます。

addEventListener('htmx:afterSwap', function (event) {
  ACMS.Dispatch(event.target);
});

htmx@blogテーマの解説

a-blog cmsにおけるテンプレート設計では、通常「トップページ」「一覧ページ」「詳細ページ」の3種類のページテンプレートを指定しますが、今回のhtmx@blogテーマでは、すべてのページが共通のテンプレートファイル _entry.html を使用する設定になっています。

htmx の実行についての確認

サブカラムに a-blog cms のロゴが出ている時には、CMS でページ全体を生成し、htmx update! と表示している時には Ajax で部分的に更新しています。また、タイトルタグも cms: と htmx: をタイトルテキストの前に付加しています。



テンプレートファイルの構造

themes/htmx@blog/_entry.html

htmxと通常のCMSのテンプレートを共通化するための工夫として、_entry.html内で、次のように multi_swap オプションをオフに設定し、entry-body.htmlをインクルードしています。

@include("/include/htmx/entry-body.html", {"multi_swap": "off"})

これは、htmxのAjax機能を使用して複数のコンテンツ領域を同時に更新する機能を無効にする宣言です。

themes/htmx@blog/include/htmx/entry-body.html

このファイルは、htmxによるデータ取得の基本となります。以下のモジュールが含まれていますが、multi_swapがoffの場合、一部モジュールは表示されません。

<!-- BEGIN_MODULE Entry_Body -->
(略)
<!-- END_MODULE Entry_Body -->

<!-- BEGIN_IF [{{multi_swap}}/neq/off] -->

 <!-- BEGIN_MODULE Topicpath -->
 (略)
 <!-- END_MODULE Topicpath -->

 <!-- BEGIN_MODULE Ogp -->
 <title>htmx:{title}</title>
 <!-- END_MODULE Ogp -->

<!-- END_IF -->

リンクのカスタマイズ

元々の <a href="{url}"> タグを次のように変更して、htmx での動的コンテンツ更新を実装しています。

<a href="{url}"
hx-ext="ajax-header"
hx-get="{url}/tpl/include/htmx/entry-body.html"
hx-push-url="{url}"
hx-swap="innerHTML"
hx-target="#main-contents">

この設定により、クリックされた URL に基づいて、entry-body.html の内容だけを動的に更新し、主要なコンテンツエリアを書き換えます。hx-push-url は、適切なURL管理を保つため、{url}を直接指定しています。


赤枠の部分のリンク :hx は htmx が動作するリンクになっています。

htmx@site テーマの解説

htmx@site テーマでは、ブログテーマとは異なり、ページ更新のアプローチがより動的です。初回アクセス時には CMS がページ全体を生成しますが、その後のページ遷移では htmx を用いた更新を活用します。特にカテゴリーが変わる際には、CMS によって新たなカテゴリーのページ全体を再表示させます。一方で、同じカテゴリー内でのページ間の遷移は、htmxを使って部分的にコンテンツを更新する設定になっており、これによりユーザー体験がスムーズに保たれます。

htmx の実行についての確認

HOME ではサブカラムが無い 1カラムレイアウトになっていますので、グローバルメニューに a-blog cmshtmx の表示をしています。



a-blog cmsのテンプレート構造とカスタマイズ方法


a-blog cms では、カテゴリーごとに異なるレイアウトを実現するために、テーマディレクトリ内にカテゴリーコード名のディレクトリを設け、一覧ページ用の index.html と詳細ページ用の _entry.html を配置します。これにより、各カテゴリーに合わせたデザインや機能を独立して管理できるため、サイト全体の一貫性を保ちつつ、細かなカスタマイズが容易になります。

物件情報の検索(realestate)

物件情報カテゴリーでは、hx-post を利用してフォームから送信されたデータを URL 形式に変換し、その結果を表示する仕組みを採用しています。また、標準のページャー機能を htmx を使った Ajax 読み込み形式にカスタマイズし、よりスムーズなページ遷移を実現しています。


お問い合わせフォーム(contact)

a-blog cms の標準フォーム機能を利用して、確認画面や送信完了画面への遷移も Ajax を介して行われます。現在は確認画面に遷移した際にページ上部に自動スクロールしないため、ユーザーが何が起こったかを理解しにくいという課題があります。これを解消し、より良いユーザー体験を提供するために、次期アップデートで改善を図る予定です。


htmx と a-blog cms の効率的な組み合わせ

このシリーズを通じて、htmxa-blog cms を組み合わせることによる大きな利点を探求しました。htmx を使用すると、複雑な JavaScript コーディングをせずに、Ajax による動的な Webページの更新が可能になります。これにより開発手間が減少し、スムーズで反応性の高いウェブサイトを簡単に構築できます。

一方、a-blog cms はバックエンド処理の簡略化に寄与し、PHP のコーディングがほとんどまたは全く不要になるという利点があります。これは、htmx とのシナジーにより、開発者が面倒なバックエンドの設定を心配することなく、フロントエンドの UI/UX に集中できる環境を提供します。

この組み合わせにより、開発者にも最終的なユーザーにもより良い Web体験が提供されます。htmxa-blog cms を利用することで、私たちはより迅速かつ効率的にプロジェクトを進めることができ、技術的な障壁を低減しながら革新的なソリューションを実現できるようになります。

興味のある方は、ablogcms.ioで実装済みのテーマを自由に見ることができ、さらにはそれらをカスタマイズすることも可能です。このサイトでは、htmxa-blog cms を活用した具体的な例を直接体験し、自身のプロジェクトにどのように応用できるかを探ることができます。

この探求が他の開発者たちにインスピレーションを与え、新たな可能性へと導くことを願っています。


キーワード検索フォーム(全文検索フォーム)

a-blog cms でキーワード検索フォーム(キーワード検索は全文検索とも呼ばれます)を実装する方法を紹介します。

a-blog cms でキーワード検索フォームを実装するには、POST_2GET モジュールを利用して、keywordのURLコンテキストに検索したいキーワードを含んだURLのページに遷移するフォームのテンプレートを作成します。

そのため、検索結果のページのモジュールIDの設定には「キーワード(keyword)」の項目にチェックをつけ、URLコンテキストを優先させる必要があります。

以下、キーワード検索フォームのサンプルになります。 検索結果のページは、input type="hidden"name="tpl"を記述して、テンプレートを指定しています。

<form action="/search.html" method="post" name="searchForm" role="search" aria-label="検索フォーム">
    <input type="search" id="searchForm" name="keyword" value="%{KEYWORD}" size="15" class="search-form-input">
    <input type="hidden" name="query" value="keyword">
    <button type="submit" name="ACMS_POST_2GET" class="acms-btn btn-search">検索</button>
    <input type="hidden" name="tpl" value="/search.html">
    <input type="hidden" name="bid" value="%{BID}">
</form>

キーワード検索の仕様

a-blog cms が行うキーワード検索の仕様について説明します。

a-blog cms では、keywordのURLコンテキストに指定された文字列を利用してキーワード検索(全文検索)を行います。

キーワード指定方法について、いくつかオプションがあります。

複数キーワード検索

A B のように複数のキーワードを「スペース(空白文字)」でつなげることで、複数キーワードを含むページを検索することができます。

除外検索

A -B のように除外したいキーワードを「-」の後に指定することで、キーワードを除外したページを検索できます。

A -B -C のように、「スペース(空白文字)」でつなげること除外したいキーワードを複数指定することも可能です。

メンテナンス終了バージョンについて

いつもお世話になっております。 今回は a-blog cms のメンテナンスポリシーと現状のサポートバージョンについてお知らせいたします。

a-blog cms では、セマンティックバージョニング を採用しており、新しいマイナーバージョン(2桁目の数値)がリリースされた後でも、古いバージョンの不具合やセキュリティを修正したフィックスバージョンをリリースしています。

以下の表から、どのバージョンが現在(2024年05月時点)メンテナンスされているのか確認いただけます。



バージョン 最終バージョン マイナーバージョンリリース日 不具合修正(期限日) セキュリティ修正(期限日) 対応PHP
3.1 メンテナンス中 2023/09/14 2025/09/14 2027/09/14 7.3 - 8.3.x
3.0 セキュリティ修正のみ 2021/12/24 2023/12/24 2026/12/24 7.2.5 - 8.1.x
2.11 セキュリティ修正のみ 2019/12/17 2021/12/17
2022/12/17
2024/12/17 5.3.29 - 7.4.x
2.10 2.10.56 2019/02/28 2021/02/28 2024/02/28 5.3.3 - 7.3.x
2.9 2.9.45 2018/10/09 2020/10/09 2023/10/09 5.3.3 - 7.2.x
2.8 2.8.79 2018/03/26  2020/03/26  2023/03/26  5.3.3 - 7.2.x
2.7 2.7.34 2017/03/30 - - 5.3.3 - 7.0.x
2.6 2.6.1.4 2015/12/25 - - 5.3.3 - 5.6.x
2.5 2.5.1.3 2015/04/23 - - 5.3.3 - 5.5.x
2.1 2.1.1.4 2014/06/23 - - 5.3.3 - 5.4.x
2.0 2.0.1.1 2013/12/18 - - 5.3.3 - 5.3.x
1.7 1.7.0 2013/06/24 - - 5.3.3 - 5.3.x

メンテナンスポリシー

基本的には以下ポリシーに沿ってメンテナンス期間を設定しております。 例外はありますが、サポート期間が長くなることはあっても、短くなることはありません。

  • フィックスバージョンのリリース対応は Ver. 2.8 以上から
  • 不具合修正はマイナーバージョンリリース日から2年間行われます
  • セキュリティ修正はマイナーバージョンリリース日から5年間行われます
  • Ver. 2.11 の不具合修正期間は例外的に延長されています。(Ver. 3.0 のリリース期間が空いてしまったため)
  • PHP 7.4 対応については Ver. 2.11.15 以降のバージョンになります。
  • PHP 8.1 対応については Ver. 3.0.12 以降のバージョンになります。
  • PHP 8.2 及び PHP 8.3 対応については Ver. 3.1.14 以降のバージョンになります。

メンテナンス中のバージョン

* 2024年05月時点のものになります。

最新バージョンである「Ver. 3.1」は、不具合・セキュリティ修正ともにメンテナンス中になります。「Ver. 3.0」「Ver. 2.11」は、セキュリティ修正のみのメンテナンス中になります。

サポートを終了したバージョン

「Ver. 2.10」が「Ver. 2.10.56(2024/05/10リリース)」をもってセキュリティ修正を含めてサポート終了いたしました。

サポートを終了したバージョンであっても有償になってしまいますがパッチなどを作成することは可能ですのでお気軽にお問い合わせください。

情報確認

メンテナンスポリシーは、以下ページ(サポートページ)よりいつでも確認できるようになっております。

https://www.a-blogcms.jp/support/#maintenance-policy

サポート状況についてはこちらをご覧ください。

最後に

サポート終了バージョンをご利用の方はバージョンアップのご検討をお願いいたします。

今後もご報告いただいた内容に対して真摯に受け止め修正と改善を行ってまいります。 今後ともどうぞよろしくお願いいたします。

テキスト入力にインラインエディターを使用する

すでにテキストユニットに導入されているインラインエディタですが、このインターフェースはカスタマイズ次第でブログやカテゴリー、エントリーなどのカスタムフィールドとしても利用可能です。ここではその方法について、登録側(管理画面)と表示側に分けてご紹介します。

管理画面の記述

以下が、インラインエディターが実装された、カスタムフィールドのサンプルHTMLになります。

<table class="acms-admin-table-admin-edit">
  <tr>
    <th>インラインエディター</th>
    <td>
      <textarea name="sample_text" class="js-lite-editor-field acms-admin-form-width-full">{sample_text}</textarea>
      <input type="hidden" name="field[]" value="sample_text" />
    </td>
  </tr>
</table>

表示側の記述

表示したいインラインエディターの変数がsample_textであった場合、以下のように記述します。エントリーのカスタムフィールドで作成した場合はEntry系モジュールのentry:loop内に記述してください。校正せず、そのままのデータを出力する校正オプション[raw]を記述してください。

{sample_text}[raw]

ボタンの位置、クラス名、ボタンのオプションの変更

テキストユニットで導入されているインラインエディターとはオプションの指定方法が異なります。
a-blog cms Ver.2.11.40 の時点で LiteEditorFieldConf の設定がデフォルトで空になっているため、カスタムフィールドでLiteEditorを使用する場合は適用しているテーマ内にJavaScriptファイルを別途作成して設定ください。
ACMS.Config.LiteEditorFieldConf.xxxという記述で設定を下記のように適用します。

ACMS.Ready(function(){
  ACMS.Config.LiteEditorFieldConf.btnPosition = 'bottom';
  ACMS.Config.LiteEditorFieldConf.classNames = {
    LiteEditor: 'entryFormLiteEditor',
    LiteEditorBtnGroup: 'acms-admin-btn-group acms-admin-btn-group-inline',
    LiteEditorBtn: 'acms-admin-btn',
    LiteEditorBtnActive: 'acms-admin-btn acms-admin-btn-active',
    LiteEditorBtnClose: '',
    LiteEditorTooltipInput: 'acms-admin-form-width-full'
  };
  ACMS.Config.LiteEditorFieldConf.btnOptions = [
   { label: 'リンク', tag: 'a', className: '', sampleText: 'リンクテキスト' },
   { label: '強調', tag: 'em', className: '', sampleText: ' ' },
   { label: '重要', tag: 'strong', className: '', sampleText: ' ' }
  ];
});

LiteEditorのデフォルトボタンをそのまま維持したい場合はbtnOptionsを下記のように指定します。

ACMS.Config.LiteEditorFieldConf.btnOptions = [
  { label: '<span class="lite-editor-font-back"></span>', action: 'undo', group: 'action' },
  { label: '<span class="lite-editor-font-go"></span>', action: 'redo', group: 'action' },
  { label: '<span class="lite-editor-font-link"></span>', tag: 'a', className: '', group: 'mark' },
  { label: '<span class="lite-editor-font-bold"></span>', tag: 'strong', className: '', group: 'mark' },
  { label: '<span class="lite-editor-font-italic"></span>', tag: 'i', className: '', group: 'mark' },
  { label: '<span class="lite-editor-font-underline"></span>', tag: 'u', className: '', group: 'mark' }
];