静的HTMLサイトのフォームを動くようにする


9. お問い合わせフォームを実装する

a-blog cms では、フォーム機能が標準で備わっており、必要なファイルや処理の流れがあらかじめ用意されています。そのため、カスタマイズ済みのテンプレートを利用するだけで、「入力 → 確認 → 完了 → メール送信」までを実装できます。

お問い合わせフォームは、静的 HTML サイトにゼロから実装しようとすると、
入力画面・確認画面・完了画面の切り替え処理 や メール送信機能 をすべて自作する必要があり、難易度が高い部分です。

このチュートリアルでは「静的 HTML サイトのフォームを動かす」ことを目標としています。ただし、フォーム実装は初心者にはややハードルが高いため、基本的には beginner テーマに含まれるお問い合わせフォームのコードを流用 しながら、その仕組みを解説し、理解を深めていきます。


9-1. 基本のファイル構造を確認する

現在のファイル構成は次のとおりです。
_top.html にもフォームのマークアップがありますが、まずは contact ディレクトリ内で動作するフォーム を確認してから、最終的にトップページに移設していきます。

/themes/sample/
  ├── _top.html 
  ├── news/
  ├── service/
  ├── contact/
  │   ├── index.html   (お問い合わせフォーム:入力画面)
  │   ├── confirm.html (お問い合わせフォーム:確認画面)
  │   └── thanks.html  (お問い合わせフォーム:完了画面)
  ├── css/
  ├── images/
  └── admin/

ここに、beginner テーマの contact ディレクトリ を移設して利用します。
まずは beginner 側のファイル構成を見てみましょう。

/themes/beginner/
  └── contact/
      ├── index.html   (入力画面)
      ├── thanks.html  (完了画面)
      └── form/
          ├── main.html
          ├── confirm.html
          ├── input.html
          ├── step.html
          ├── adminbody.txt
          ├── adminsubject.txt
          ├── body.html
          ├── adminbody.html
          ├── body.txt
          └── subject.txt

この中で重要なのは contact/form ディレクトリ内のファイル群です。これらをまとめてコピーすることで、フォーム機能に必要なテンプレートが揃います。

index.html 内の @include("/contact/form/main.html") という記述です。ここで form/main.html を読み込むことで、入力 → 確認 → 完了画面の一連の流れとメール送信処理が動作します。

9-2. Form モジュールの基本構造

main.html には Form モジュール が書かれています。いくつかの step ブロックに分かれ表示内容が分岐するようになっています。

この仕組みによって、入力画面 → 確認画面 → 完了画面と画面を切り替えながら、ひとつのフォームを動作させることができます。

<!-- BEGIN_MODULE Form -->

  <!-- BEGIN step-->
  <!-- 初期画面 -->
  <h2>入力画面</h2>
  @include("/contact/form/input.html")
  <!-- END step -->

  <!-- BEGIN step#reapply -->
  <!-- 修正・エラー -->
  <h2>入力画面</h2>
  @include("/contact/form/input.html")
  <!-- END step#reapply -->

  <!-- BEGIN step#confirm -->
  <!-- 確認 -->
  <h2>確認画面</h2>
  @include("/contact/form/confirm.html")
  <!-- END step#confirm -->

  <!-- BEGIN step#result -->
  <!-- 完了 -->
  <h2>送信完了</h2>
  @include("/contact/form/confirm.html")
  <!-- END step#result -->

<!-- END_MODULE Form -->

各ステップの役割

  • step : フォームの初期表示(入力画面)

  • step#reapply : 入力内容にエラーがあった場合に戻る画面(再入力用)

  • step#confirm : 入力した内容を表示する確認画面

  • step#result : 送信完了画面(ここでメール送信処理が行われる)

各ファイルの役割

  • input.html : 入力用のフォーム部分の HTML(<input><textarea> などを配置)

  • confirm.html : 確認画面で入力内容を表示するための HTML

  • main.html : これらをまとめて呼び出し step ごとに分岐させる「制御役」

このように、main.html は「全体のまとめ役」、
input.htmlconfirm.html は「実際に画面に表示される部分を担当するファイル」 と考えると分かりやすいでしょう。

なお、ここで紹介したのはあくまでざっくりとした構造です。実際には <form> タグや送信処理に必要な隠しフィールド(hidden input など)が書かれています。詳しくは実際のファイルを開いて確認してください。

9-3. フォームID の設定を行う

これまで、各モジュールをテンプレートに貼り付けた際には、モジュールID を管理画面で設定していました。

Form モジュールも同じように使いますが、メール送信やバリデーションといった特別な仕組みを持つため、専用の「フォーム管理」画面で ID を設定 する必要があります。

この ID を設定しないと、フォームは動作しません。

Beginner テーマの場合

今回のチュートリアルは Beginner テーマがインストールされている状態からスタートしています。そのため、すでに「contactForm」というフォームIDがフォーム管理に登録されています。

つまり 新規作成は不要 で、そのまま利用することができます。ただし、メールの送信先アドレスや自動返信メールの内容は、環境に合わせて修正してください。

入力チェックの初期設定を削除する

a-blog cms では「管理画面側」と「テンプレート側」の両方にエラーチェック機能があります。ただし、今回のチュートリアルではテンプレートをカスタマイズしてフォーム項目を減らしていくため、初期状態の「入力チェック」設定が残っているとエラーで先に進めなくなる可能性があります。

そのため、管理画面の「入力チェック・変換」タブにあるすべての項目を一旦削除してください。これで、フォームのカスタマイズを自由に進められるようになります。

SCR-20250917-kecm

(↑ 入力チェック・変換の設定をすべて削除してください)

他のテーマから始めた場合

もし Beginner テーマをインストールしていない環境でフォームを実装する場合は、フォーム管理に何も登録されていない状態 から始まります。その場合は、新規作成を行い、以下のように設定してください。

  • フォームID : contactForm (テンプレートの hidden フィールドと一致させる必要があります)

  • フォーム名 : 管理画面でわかりやすい名前(例:「お問い合わせフォーム」)

  • 送信先メールアドレス(To) : 管理者が受け取るメールアドレス

  • 通知メールの設定 : 管理者通知メール・自動返信メールの件名や本文

  • 入力チェックの設定 : 必須項目や形式チェックのルール

設定後に保存し、フォームから実際に送信テストを行って動作を確認してください。

9-4. フォームの実装

ここまでフォームの仕組みを解説してきましたので、ここからは beginner テーマのフォームを sample テーマに移植して動かす 実作業を行います。

ファイルをコピーする

まずは beginner テーマにあるフォーム関連のファイル一式を、sample テーマに移植します。

/themes/beginner/contact/form ディレクトリを、/themes/sample/contact/ 配下にそのままコピーしてください。

最終的に sample テーマの構成は以下のようになります。

/themes/sample/contact/
  ├── index.html
  ├── confirm.html
  ├── thanks.html
  └── form/
      ├── main.html
      ├── confirm.html
      ├── input.html
      ├── step.html
      ├── adminbody.txt
      ├── adminsubject.txt
      ├── body.html
      ├── adminbody.html
      ├── body.txt
      └── subject.txt

補足

  • main.html がフォームの本体で、入力 → 確認 → 完了までの制御を行います。

  • .txt ファイルはメール送信用のテンプレートです。

  • body.html で HTMLメールも送信可能です。

index.html を編集する

次に sample テーマの contact/index.html を開き、Contact の見出しを含む <div> の下に以下を追記します。

@include("/contact/form/main.html")

修正後のイメージは以下の通りです。

<div class="border-b border-gray-200 pb-8 mb-12">
    <h1 class="text-3xl font-bold tracking-tight text-gray-900 sm:text-4xl">Contact</h1>
    <p class="mt-4 text-lg text-gray-600">サービスに関するご質問や、ケータリングのご相談など、お気軽にお問い合わせください。</p>
</div>

@include("/contact/form/main.html")

この時点で表示されるフォームは、当初の静的 HTML サイトにあったフォーム項目ではなく、Beginner テーマのサンプルフォーム です。
ただし、sample テーマの CSS とは統合されていないため、スタイルが適用されずレイアウトが崩れた状態になっています。

SCR-20250917-iyop

一方で、必須入力チェック などの処理はすでに動作しており、全ての項目を入力することで確認画面を表示することもできます。つまり、フォームの機能そのものは動いている状態 になっています。

9-5. ステップ部分を調整

Beginner テーマでは、フォームの進行状況を表す step.html がシンプルなリスト形式で実装されています。

<ol class="form-step">
  <li class="form-step-item is-current">内容の入力</li>
  <li class="form-step-item">内容の確認</li>
  <li class="form-step-item">送信完了</li>
</ol>

一方、sample テーマにはよりビジュアル的なステップ表示があり、番号付きの丸アイコンと線で区切るデザインが使われています。今回はこれを step.html に移植し、フォームの状態に応じて切り替わるように修正 します。

実装の考え方

  • 外側の構造は sample テーマのデザインをそのまま流用

  • 中の各ステップは Form モジュールの step, step#confirm, step#result などを利用して切り替える

修正後の例

<!-- BEGIN_MODULE Form -->
<div class="mt-12 mb-8">
    <div class="flex items-center justify-between px-8">
    
<!-- BEGIN step -->
( index.html を参考に )
<!-- END step -->

<!-- BEGIN step#reapply -->
( index.html を参考に )
<!-- END step#reapply -->

<!-- BEGIN step#confirm -->
( confirm.html を参考に )
<!-- END step#confirm -->

<!-- BEGIN step#result -->
( thanks.html を参考に )
<!-- END step#result -->

    </div>
</div>
<!-- END_MODULE Form -->

このようにすることで、sample テーマのデザインを維持しながら、フォームの進行状況が正しく反映されるステップ表示が完成します。

9-6. 入力フォーム input.html の調整

ここでは、input.html を実際のサイトの要件に合わせてシンプルな構成に修正していきます。項目は「お名前」「メールアドレス」「お問い合わせ内容」の 3 つに絞ります。

修正後の例

<div>
    <label for="name" class="block text-sm font-medium text-gray-700">お名前</label>
    <div class="mt-1">
        <input type="text" name="name" id="name" value="{name}" autocomplete="name" class="block w-full rounded-md border-gray-300 shadow-sm focus:border-sky-500 focus:ring-sky-500 sm:text-sm">
    </div>
</div>
<div>
    <label for="email" class="block text-sm font-medium text-gray-700">メールアドレス</label>
    <div class="mt-1">
        <input id="email" name="email" type="email" value="{email}" autocomplete="email" class="block w-full rounded-md border-gray-300 shadow-sm focus:border-sky-500 focus:ring-sky-500 sm:text-sm">
    </div>
</div>
<div>
    <label for="message" class="block text-sm font-medium text-gray-700">お問い合わせ内容</label>
    <div class="mt-1">
        <textarea id="message" name="message" rows="10" class="block w-full rounded-md border-gray-300 shadow-sm focus:border-sky-500 focus:ring-sky-500 sm:text-sm">
        {message}
        </textarea>
    </div>
</div>

ポイント

  • 入力値の保持:value="{name}"{message} のようにプレースホルダーを入れることで、確認画面やエラー時にも入力内容を保持できます。

  • name 属性と value の対応:フォームの項目は「カスタムフィールド」と同じ仕組みで、name 属性にフィールド名を指定し、その内容が value に反映されます。

  • シンプルに始める:必須チェックやエラー表示などの拡張は後から追加できるため、まずは基本の「入力 → 確認 → 完了」の流れを作ることを優先します。

これで、input.html は「お名前」「メールアドレス」「お問い合わせ内容」という最小限の入力項目を持った実用的なフォームになりました。

9-7. 確認画面 confirm.html の調整

次に、confirm.html を修正していきます。
ここでは、入力画面 (input.html) で受け取った値を確認画面に表示し、ユーザーが送信前に内容をチェックできるようにします。

修正後の例

<div>
    <label class="block text-sm font-medium text-gray-700">お名前</label>
    <div class="mt-1 p-3 bg-gray-100 rounded-md">
        <p>{name}</p>
    </div>
</div>
<div>
    <label class="block text-sm font-medium text-gray-700">メールアドレス</label>
    <div class="mt-1 p-3 bg-gray-100 rounded-md">
        <p>{email}</p>
    </div>
</div>
<div>
    <label class="block text-sm font-medium text-gray-700">お問い合わせ内容</label>
    <div class="mt-1 p-3 bg-gray-100 rounded-md">
        <p class="whitespace-pre-wrap">{message}</p>
    </div>
</div>

ポイント

  • 入力画面で入力された値を {name}, {email}, {message} で出力。

  • 今回 Tailwind CSS の class="whitespace-pre-wrap"<br> でなくても改行が有効になっているが、一般的には {message}[nl2br] として改行コードを <br> に置き換える事が一般的です。

9-8. フォーム全体の制御 main.html の調整

ここまでで入力 (input.html)、確認 (confirm.html)、のそれぞれのファイルを修正しました。 最後に、これらを切り替えて表示する フォーム全体の制御 を main.html に実装します。

入力画面の構造と hidden フィールドの役割

main.htmlstepstep#reapply のブロックの詳細を確認していきます。

<!-- BEGIN step -->
<!-- フォームステップ:初期 -->

@include("/contact/form/step.html")

<div class="mt-16 px-5">
  <form action="?step=reapply" method="post" class="space-y-6" enctype="multipart/form-data">
  
  @include("/contact/form/input.html")

  <div>
    <input type="hidden" name="step" value="confirm" />
    <input type="hidden" name="error" value="reapply" />
    <input type="hidden" name="id" value="contactForm" />
    <input type="submit" name="ACMS_POST_Form_Confirm" value="内容の確認へ" id="btnConfirm" class="w-full flex justify-center py-3 px-4 border border-transparent rounded-md shadow-sm text-base font-medium text-white bg-sky-600 hover:bg-sky-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-sky-500" />
  </div>

  </form>
</div>

<!-- END step -->

type="hidden" で設定されている 3つを確認していきます。

<input type="hidden" name="step" value="confirm" />

入力内容が正しく、エラーがなかった場合に step#confirm ブロックを表示させる。

<input type="hidden" name="error" value="reapply" />

入力チェックでエラーがあった場合に step#reapply ブロックを表示させる。

<input type="hidden" name="id" value="contactForm" />

フォームを識別するための フォームID の設定。同じページに複数のフォームを置く場合、この ID によってどのフォームの処理かを判別します。

確認画面の「戻る」と「送信」フォーム分岐

main.htmlconfirm のブロックの詳細を確認していきます。

<!-- BEGIN step#confirm -->
<!-- フォームステップ:確認画面 -->

@include("/contact/form/step.html")

<div class="mt-16 px-5">
  <div class="space-y-6">      
    
    @include("/contact/form/confirm.html")

    <div class="flex gap-x-4">

        <form action="" method="post" class="w-full" enctype="multipart/form-data">
          <input type="hidden" name="step" value="reapply" />
          <input type="hidden" name="takeover" value="{takeover}" />
          <input type="submit" name="ACMS_POST_Form_Chain" value="戻って修正する" class="w-full flex justify-center py-3 px-4 border border-gray-300 rounded-md shadow-sm text-base font-medium text-gray-700 bg-white hover:bg-gray-50" />
        </form>

        <form action="thanks.html" method="post" class="w-full" enctype="multipart/form-data">
          <input type="hidden" name="To[]" value="{email}" />
          <input type="hidden" name="AdminReply-To[]" value="{email}" />
          <input type="hidden" name="AdminFrom[]" value="{email}" />
          <input type="hidden" name="step" value="result" />
          <input type="hidden" name="takeover" value="{takeover}" />
          <input type="hidden" name="id" value="contactForm" />
          <input type="submit" name="ACMS_POST_Form_Submit" value="この内容で送信する" class="w-full flex justify-center py-3 px-4 border border-transparent rounded-md shadow-sm text-base font-medium text-white bg-sky-600 hover:bg-sky-700" />
        </form>
    </div>

  </div>
</div>

<!-- END step#confirm -->

ここでは、戻って入力画面を表示させる form と、実際に送信する画面の2つの form が用意されています。

戻るボタン側

この画面では、エラーチェックが済んでいる状態なので type="hidden" name="error" は必要なく、name="step" で step#reapply に戻るような記述になっています。

<input type="hidden" name="takeover" value="{takeover}" />

新しい name="takeover" というものが出てきましたが、これはこれまでに入力した情報を引き継ぐための設定です。これによって、戻った画面で再度入力し直す必要がなく、ユーザーが入力した情報を保持したまま表示できます。

送信ボタン側

送信完了後に thanks.html へ遷移しつつ、入力内容をメールで送信するための設定です。

メール送信関連

  • To[] : 送信先アドレス

  • AdminReply-To[] : 管理者が返信する際の返信先

  • AdminFrom[] : 管理者からの送信元

フォーム制御関連

  • step="result" : 完了画面(step#result)を表示

  • takeover="{takeover}" : 入力内容を引き継ぎ再入力を省略

  • id="contactForm" : 複数フォームを識別する ID

最後の submit ボタンを押すことで、a-blog cms のフォーム処理が実行され、入力内容がメール送信されます。

type="submit" に設定される POST モジュールの役割

a-blog cms では、フォームの送信ボタンには ACMS_POST_〜 という特別な属性が使われています。これによって、送信内容の処理や画面遷移が制御されます。

  • ACMS_POST_Form_Confirm : 入力内容をバリデーション(必須チェックなど)して、次のステップ(確認画面)へ遷移させる。

  • ACMS_POST_Form_Submit : 実際に送信処理を実行し、入力内容をメールで送信や、必要に応じてデータベースに保存する。

  • ACMS_POST_Form_Chain : バリデーションを行わずに次のステップへ遷移させる。主に「戻る」ボタンで利用され、入力内容を保持したまま入力画面に戻す処理に使われる。

confirm.html を削除

contact/confirm.html については index.html の Form モジュールで表示されるようになり、使われない事になりましたので削除します。

9-9. 送信完了画面 thanks.html の調整

最後に、送信完了画面を整えます。

この画面はフォームの送信処理が完了したあとに表示されるページで、ユーザーに「送信が成功したこと」を伝える重要な役割を持っています。

contact/thanks.html の必要な部分を step#result に移設します。

<!-- BEGIN step#result -->
<!-- フォームステップ:完了画面 -->

@include("/contact/form/step.html")

<div class="mt-16 text-center">
    <div class="mx-auto flex h-12 w-12 items-center justify-center rounded-full bg-green-100">
        <svg class="h-6 w-6 text-green-600" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" aria-hidden="true">
            <path stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5" />
        </svg>
    </div>
    <h2 class="mt-4 text-2xl font-bold tracking-tight text-gray-900">お問い合わせありがとうございます</h2>
    <p class="mt-4 text-lg leading-8 text-gray-600">
        ご入力いただいた内容でメッセージを送信しました。<br>
        内容を確認の上、担当者より3営業日以内にご連絡いたします。
    </p>
    <div class="mt-10">
        <a href="/" class="rounded-md bg-sky-600 px-5 py-3 text-base font-semibold text-white shadow-sm hover:bg-sky-700">
            トップページへ戻る
        </a>
    </div>
</div>
<!-- END step#result -->

また、contact/thanks.html のファイルの中身を全て削除し、以下のようにします。

@include("/contact/index.html")

9-10. トップページにフォームを設置する

http://localhost/contact/ でフォームが動作するようになったら、最後にトップページ下部にあるフォームも同様に調整します。

_top.html のフォームを差し替える

/themes/sample/_top.html を開き、既存の <form>...</form> のマークアップを削除し、次のように書き換えます

<!-- BEGIN_MODULE Form -->
<!-- BEGIN step -->
  <form action="/contact/" method="post" class="space-y-6" enctype="multipart/form-data">
  
  @include("/contact/form/input.html")

  <div>
    <input type="hidden" name="step" value="confirm" />
    <input type="hidden" name="error" value="reapply" />
    <input type="hidden" name="id" value="contactForm" />
    <input type="submit" name="ACMS_POST_Form_Confirm" value="内容の確認へ" id="btnConfirm" class="w-full flex justify-center py-3 px-4 border border-transparent rounded-md shadow-sm text-base font-medium text-white bg-sky-600 hover:bg-sky-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-sky-500" />
  </div>

  </form>
<!-- END step -->
<!-- END_MODULE Form -->

ポイント

  • お問い合わせページと同じフォームをトップページにも設置できるようにする。

  • @include("/contact/form/input.html") を使うことで、入力欄の定義を共通化。

  • action="/contact/" とすることで、実際の処理は /contact/ 側のフォームに委譲。

  • こうすることで「トップからも入力 → 確認 → 完了」の流れが同じ仕組みで動作する。

9-11. メールのテンプレート

a-blog cms のフォームでは、送信完了時にメールを自動で送信する仕組みが標準で備わっています。

これらのテンプレートは /contact/form/ ディレクトリ内に含まれており、必要に応じて編集することで、送信内容を自由にカスタマイズできます。

テンプレートファイルの種類

/themes/sample/contact/form/
  ├── adminbody.txt     (管理者宛メールの本文)
  ├── adminsubject.txt  (管理者宛メールの件名)
  ├── body.txt          (ユーザー宛メールの本文)
  ├── subject.txt       (ユーザー宛メールの件名)
  ├── adminbody.html    (管理者宛メールの HTML 版)
  └── body.html         (ユーザー宛メールの HTML 版)

使い分け

  • 管理者宛メール

    • adminsubject.txt : 管理者宛メールの件名

    • adminbody.txt : 管理者宛メールの本文

    • adminbody.html : HTML メール版(必要に応じて利用)

  • ユーザー宛(自動返信メール)

    • subject.txt : ユーザー宛メールの件名

    • body.txt : ユーザー宛メールの本文

    • body.html : HTML メール版

テンプレート内で利用できる変数

入力フォームの項目はそのまま変数として利用できます。
例えば input.html で name="email" と定義した場合は {email} で参照できます。

{ name } 様

この度はお問い合わせいただき、誠にありがとうございます。
以下の内容で承りました。

--------------------
お名前: {name}
メールアドレス: {email}
お問い合わせ内容:
{message}
--------------------

担当者より折り返しご連絡いたしますので、今しばらくお待ちください。

ポイント

  • 管理者宛メールとユーザー宛メールはテンプレートを分けて管理できる。

  • HTML メールを使う場合は .html 側を編集、テキストメールで良ければ .txt のみで十分。

  • フォーム項目名を変更した場合は、このテンプレート内の変数も合わせて修正する必要がある。

ここまでで、a-blog cms 標準のフォーム機能を利用し、入力 → 確認 → 完了 → メール送信 までを実装しました。静的 HTML サイトでは難しかった仕組みも、テンプレートと管理画面を組み合わせることで短時間で構築できることが体験できたと思います。今回の内容で、実務に必要な「お問い合わせフォーム」の基本が一通り揃いました。