【ステップ式Contact Form 7】Contact Form 7を使用したステップ式フォーム

過去にHTMLでjQueryを使用しないステップ式フォームの解説記事を書いたのですが、

WordPressプラグインの

Contact Form 7(コンタクトフォーム7)だとうまく動作しませんでした。

以下CF7と呼びます。

そこで動作しなかった原因と、コードに加えた変更点を記事にします。

dataなどの独自の属性を直接使うことができない

ポイントイメージ

元のコードでは、data-target-button 属性を使って、どの入力項目が変更された際にどのボタンを活性化するかを指定していました。

Contact Form 7 は独自のタグ構造のため、独自の属性を直接使うことができませんでした。

どうせ動かないと想定して作成してました。

そこで、JavaScript 側で Contact Form 7 の構造に合わせて修正を行いました。

今回使用したコード

JavaScript
const stepWrappers = document.querySelectorAll(".c-form-step__wrapper-box");
let currentStep = 0;

// 最初に表示するステップを設定
showStep(currentStep);

// 各input要素とselect要素にイベントリスナーを追加
document.querySelectorAll('.wpcf7-form-control:not([type="hidden"]):not([type="submit"])').forEach(input => {
  // input要素とselect要素でイベントの種類を分ける
  const eventType = input.tagName.toLowerCase() === 'input' ? 'input' : 'change';

  input.addEventListener(eventType, function () {
    // 入力値の検証
    const isValid = validateInput(this);

    // ボタンの活性/非活性制御
    const targetButton = this.closest('.c-form-step__wrapper-box').querySelector('.next-btn, input[type="submit"]');
    if (targetButton) {
      targetButton.classList.toggle('active', isValid);
    }
  });
});

function showStep(stepIndex) {
  if (stepIndex < 0 || stepIndex >= stepWrappers.length) {
    return;
  }

  stepWrappers.forEach((wrapper, index) => {
    wrapper.style.display = index === stepIndex ? "block" : "none";
  });

  currentStep = stepIndex;
  updateButtonState(currentStep); // ステップ変更時にボタンの状態を更新
}

function nextStep(button) {
  // 現在のステップの入力値を検証
  const currentInput = stepWrappers[currentStep].querySelector('.wpcf7-form-control:not([type="hidden"]):not([type="submit"])');
  const isValid = validateInput(currentInput);

  if (!isValid) {
    // 入力エラーの場合、アラートを出力
    alert(getErrorMessage(currentInput.id));
    return; // 処理を中断
  }

  // ボタンの活性/非活性制御
  button.classList.toggle('active', isValid);

  // 有効な入力値の場合のみ、次のステップへ進む
  if (isValid) {
    showStep(currentStep + 1);
  }
}

function prevStep() {
  showStep(currentStep - 1);
}

/**
 * 入力値の検証を行う関数
 * @param {HTMLInputElement|HTMLSelectElement} input 検証対象のinput要素またはselect要素
 * @returns {boolean} 検証結果(true: 有効、false: 無効)
 */
function validateInput(input) {
  if (!input) {
    return false; // input要素がない場合は無効とする
  }

  const value = input.tagName.toLowerCase() === 'input' ? input.value.trim() : input.value;
  const id = input.id;

  // 各入力項目ごとの検証ルール
  switch (id) {
    case 'name':
      return value !== ''; // 名前は空チェックのみ
    case 'post':
      return /^\d{7}$/.test(value); // 郵便番号は7桁の数字のみ
    case 'address':
      return true; // 住所は自由入力になったので常にtrue
    case 'tel':
      return /^\d{10,11}$/.test(value); // 電話番号は10桁または11桁の数字のみ
    case 'email':
      return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value); // メールアドレスは形式チェック
    // セレクトボックスの場合、空でない値を選択しているかチェック
    case 'time':
    case 'job-change':
      return value !== '';
    default:
      return true; // その他の項目はtrue
  }
}

/**
 * 入力項目ごとのエラーメッセージを返す関数
 * @param {string} inputId 入力項目のID
 * @returns {string} エラーメッセージ
 */
function getErrorMessage(inputId) {
  switch (inputId) {
    case 'name':
      return 'お名前を入力してください。';
    case 'post':
      return '郵便番号を正しく入力してください。';
    case 'address':
      return '住所を入力してください。';
    case 'tel':
      return '電話番号を正しく入力してください。';
    case 'email':
      return 'メールアドレスを正しく入力してください。';
    case 'time':
      return '連絡が取りやすい時間を選択してください。';
    case 'job-change':
      return '希望転職時期を選択してください。';
    default:
      return '入力内容を確認してください。';
  }
}

/**
* 指定されたステップのボタンの状態を更新する関数
* @param {number} stepIndex ボタンの状態を更新するステップのインデックス
*/
function updateButtonState(stepIndex) {
  const targetButton = stepWrappers[stepIndex].querySelector('.next-btn, input[type="submit"]');
  const currentInput = stepWrappers[stepIndex].querySelector('.wpcf7-form-control:not([type="hidden"]):not([type="submit"])');

  if (targetButton && currentInput) {
    const isValid = validateInput(currentInput);
    targetButton.classList.toggle('active', isValid);
  }
}

Contact Form 7 のクラス名を使って要素を取得

元のコードでは、querySelectorAll(‘.input-text, .input-select’) で入力項目を取得していました。これは、HTML の input 要素と select 要素を直接指定していました。

しかし、Contact Form 7 は独自のクラス名を使って入力項目を識別しています。そのため、querySelectorAll(‘.wpcf7-form-control:not([type=”hidden”]):not([type=”submit”])’) に変更しました。

  • wpcf7-form-control は、Contact Form 7 の入力項目全てに付与されるクラス名です。
  • :not([type=”hidden”]):not([type=”submit”]) は、 hidden タイプの入力項目や送信ボタンを除外するための CSS セレクターです。

これにより、Contact Form 7 の入力項目を正しく取得することができます。

ボタンを現在のステップ内から取得

元のコードでは、data-target-button 属性を使ってボタンを取得していました。しかし、Contact Form 7 では data-target-button を使用できません。

そこで、this.closest(‘.c-form-step__wrapper-box’).querySelector(‘.next-btn, input[type=”submit”]’) に変更しました。

  • this.closest(‘.c-form-step__wrapper-box’) は、イベントが発生した入力項目の親要素である .c-form-step__wrapper-box を取得します。
  • querySelector(‘.next-btn, input[type=”submit”]’) は、そのステップ内にある next-btn クラスを持つボタンか、submit タイプのボタンを取得します。

これにより、各ステップ内のボタンを正しく取得することができます。

nextStep 関数内の入力値取得を修正

元のコードでは、stepWrappers[currentStep].querySelector(‘.input-text, .input-select’) で現在のステップの入力項目を取得していました。

しかし、Contact Form 7 では入力項目が独自の構造を持っているため、stepWrappers[currentStep].querySelector(‘.wpcf7-form-control:not([type=”hidden”]):not([type=”submit”])’) に変更しました。

これにより、現在のステップの入力項目を Contact Form 7 の構造に合わせて取得することができます。

まとめ

これでCF7でも動作するステップ式フォームの完成です、

ランディングページに使うことが特に多いので、

WordPressでランディングページを作る人の参考になれば幸いです。