【Contact Form 7】コピペOK!生年月日のプルダウンを動的に作成する

ContactForm7は、複雑なソースコードを触らずにメールフォームが作成できるWordPressサイトには欠かせないとても便利なプラグインです。

だからといってなんでもできるというわけではなく、こんなことやりたいなと思っても意外と標準の機能では再現できないことも多いですよね。

今回は、求人応募フォームなどで生年月日を入力してもらうとき、「年」の選択肢を決められた年齢の範囲(例えば18歳から65歳など)だけに絞り込みたい場合のドロップダウンメニューの作成方法をご紹介します。

こちらを標準の機能で作成してしまうと、毎年、「年」の選択肢を変更しなくてはなりません。

そうならないために現在の年を基準に、任意の範囲のドロップダウンメニューをJavaScriptで動的に生成します。

一度作成してしまえば、年が変わっても自動的に選択肢が切り替わるので楽チン。

この記事でわかること

  • ContactForm7で生年月日を入力するフォームを作成する
  • 現在の年を基準に動的なドロップダウンメニューを生成する
  • 必須チェックをする方法

完成形

まずは、これから解説するものの完成形。

「年」のドロップダウンの中身は、18歳から65歳の生まれ年のみになっています。

※ドロップダウンの見た目は、お使いのテーマなどによって異なります。




    ソースコード全体

    まず、結果のソースコードはこちら。

    JavaScript部分はちょっと長いので、後でブロックごとに説明しますね。

    Contact Form 7側の設定

    「フォーム」タブの記述

    <label> 生年月日 ※必須</label>
    <select id="birth-year" name="birth-year" required></select> 
    [select* birth-month "選択してください" "1月" "2月" "3月" "4月" "5月" "6月" "7月" "8月" "9月" "10月" "11月" "12月"] 
    [select* birth-day "選択してください" "1日" "2日" "3日" "4日" "5日" "6日" "7日" "8日" "9日" "10日" "11日" "12日" "13日" "14日" "15日" "16日" "17日" "18日" "19日" "20日" "21日" "22日" "23日" "24日" "25日" "26日" "27日" "28日" "29日" "30日" "31日"] 
    

    年の部分

    • 動的に生成するので、Contact Form 7の標準機能は使用せず、<select>タグのみを記述。
    • <select>タグにid="birth-year"name="birth-year" を指定。(必須の場合はrequiredも指定)

    月と日の部分

    • Contact Form 7の標準のタグ[select*]を使用。(必須の場合は*を付ける)
    • "選択してください"を初期値として設定。

    「メール」タブの記述

    生年月日:[birth-year]年[birth-month][birth-day]
    

    管理者および自動返信メールの本文には、上記のように記載。

    javascriptの記述

    footer.phpの</body>タグの直前か使用したいページで読み込まれているjsファイルに追記します。

    <script>
    document.addEventListener('DOMContentLoaded', function () {
        // 年のドロップダウンを生成する関数
        function populateYearDropdown() {
            const currentYear = new Date().getFullYear();
            const startYear = currentYear - 65; // 最大年齢
            const endYear = currentYear - 18;  // 最小年齢
            const yearDropdown = document.getElementById('birth-year');
    
            if (!yearDropdown) return; // ドロップダウンが存在しない場合は終了
    
            // 初期選択肢
            const defaultOption = document.createElement('option');
            defaultOption.value = '';
            defaultOption.textContent = '選択してください';
            yearDropdown.appendChild(defaultOption);
    
            // 年の範囲を追加
            for (let year = startYear; year <= endYear; year++) {
                const option = document.createElement('option');
                option.value = year; // 値を年の数値に設定
                option.textContent = `${year}年`;
                yearDropdown.appendChild(option);
            }
        }
    
        // エラーメッセージを表示する関数
        function showError(element, message) {
            const existingError = element.nextElementSibling;
            if (existingError && existingError.classList.contains('error-message')) {
                existingError.remove();
            }
    
            const error = document.createElement('div');
            error.className = 'error-message';
            error.textContent = message;
            error.style.color = 'red';
            error.style.marginTop = '5px';
            element.parentElement.insertBefore(error, element.nextSibling);
        }
    
        // エラーメッセージをクリアする関数
        function clearError(element) {
            const existingError = element.nextElementSibling;
            if (existingError && existingError.classList.contains('error-message')) {
                existingError.remove();
            }
        }
    
        // ドロップダウンの変更時にエラーをクリア
        function setupErrorClearOnChange(dropdown) {
            dropdown.addEventListener('change', function () {
                if (dropdown.value) {
                    clearError(dropdown);
                }
            });
        }
    
        // フォーム送信時のバリデーション
        function validateForm(event) {
            let isValid = true;
    
            // 年の必須チェック
            const yearDropdown = document.getElementById('birth-year');
            if (!yearDropdown.value || yearDropdown.value === '') {
                showError(yearDropdown, '年を選択してください。');
                isValid = false;
            } else {
                clearError(yearDropdown);
            }
    
            // 月の必須チェック
            const monthDropdown = document.querySelector('[name="birth-month"]');
            if (monthDropdown && (!monthDropdown.value || monthDropdown.value === '選択してください')) {
                showError(monthDropdown, '月を選択してください。');
                isValid = false;
            } else {
                clearError(monthDropdown);
            }
    
            // 日の必須チェック
            const dayDropdown = document.querySelector('[name="birth-day"]');
            if (dayDropdown && (!dayDropdown.value || dayDropdown.value === '選択してください')) {
                showError(dayDropdown, '日を選択してください。');
                isValid = false;
            } else {
                clearError(dayDropdown);
            }
    
            // バリデーション失敗時は送信を停止
            if (!isValid) {
                event.preventDefault();
            }
        }
    
        // 年のドロップダウンを生成
        populateYearDropdown();
    
        // エラークリアのイベントを設定
        const yearDropdown = document.getElementById('birth-year');
        if (yearDropdown) setupErrorClearOnChange(yearDropdown);
    
        const monthDropdown = document.querySelector('[name="birth-month"]');
        if (monthDropdown) setupErrorClearOnChange(monthDropdown);
    
        const dayDropdown = document.querySelector('[name="birth-day"]');
        if (dayDropdown) setupErrorClearOnChange(dayDropdown);
    
        // フォーム送信イベントをリッスン
        const form = document.querySelector('form.wpcf7-form');
        if (form) {
            form.addEventListener('submit', validateForm);
        }
    });
    </script>
    

    javascriptの説明

    冒頭

    document.addEventListener('DOMContentLoaded', function () {
    

    ページが完全に読み込まれた後にスクリプトを実行するための設定です。

    JavaScriptはHTMLの構造が読み込まれる前に実行される場合がありますが、この記述により、DOMツリー(HTMLの要素)が完全に構築されてからスクリプトが動作します。

    年のドロップダウンを生成する関数

    年齢の範囲を変更したい場合は、「最大年齢」と「最少年齢」の数字を変更します。

    function populateYearDropdown() {
        const currentYear = new Date().getFullYear();
        const startYear = currentYear - 65; // 最大年齢
        const endYear = currentYear - 18;  // 最小年齢
        const yearDropdown = document.getElementById('birth-year');
    
        if (!yearDropdown) return; // ドロップダウンが存在しない場合は終了
    
        // 初期選択肢
        const defaultOption = document.createElement('option');
        defaultOption.value = '';
        defaultOption.textContent = '選択してください';
        yearDropdown.appendChild(defaultOption);
    
        // 年の範囲を追加
        for (let year = startYear; year <= endYear; year++) {
            const option = document.createElement('option');
            option.value = year; // 値を年の数値に設定
            option.textContent = `${year}年`;
            yearDropdown.appendChild(option);
        }
    }
    
    1. new Date().getFullYear():現在の年を取得します(例: 2024年の場合、2024が返る)。
    2. startYearendYear:年齢の範囲を計算します(65歳以上や18歳未満を除外)。
    3. document.getElementById('birth-year')<select id="birth-year"> の要素を取得します。
    4. 初期選択肢の設定:「選択してください」という選択肢を最初に追加。
    5. ループで年の範囲を追加:startYearからendYearまでの数字を<option>として生成し、ドロップダウンに追加します。

    エラーメッセージを表示する関数

    それぞれ要素のすぐ後ろに未入力時などにエラーが表示されるようにします。

    function showError(element, message) {
        const existingError = element.nextElementSibling;
        if (existingError && existingError.classList.contains('error-message')) {
            existingError.remove();
        }
    
        const error = document.createElement('div');
        error.className = 'error-message';
        error.textContent = message;
        error.style.color = 'red';
        error.style.marginTop = '5px';
        element.parentElement.insertBefore(error, element.nextSibling);
    }
    
    1. element.nextElementSibling:対象の要素の次の兄弟要素を取得します。
    2. 既存のエラーメッセージを削除:すでにエラーメッセージが表示されている場合は削除します。
    3. 新しいエラーメッセージを作成:<div>タグを生成し、クラス名やテキストを設定します。
    4. エラーメッセージを挿入:対象の要素のすぐ後ろにエラーメッセージを追加します。

    エラーメッセージをクリアする関数

    エラー状態が解消された場合、残っているエラーメッセージを削除するための仕組みです。

    フォーム送信時や次項のドロップダウン切替時などエラーが解消されるあらゆる場面で使用します。

    function clearError(element) {
        const existingError = element.nextElementSibling;
        if (existingError && existingError.classList.contains('error-message')) {
            existingError.remove();
        }
    }
    
    1. 次の兄弟要素を取得:showErrorと同様に、エラーメッセージを特定します。
    2. 既存のエラーメッセージを削除:エラーメッセージが存在すれば削除します。

    ドロップダウンの変更時にエラーメッセージをクリア

    未入力のエラーメッセージが表示され続けると、ユーザーは「選択(入力)したのにエラーが解決されない」と誤解してしまう可能性があるので、値が選択されたらエラーを削除します。

    function setupErrorClearOnChange(dropdown) {
        dropdown.addEventListener('change', function () {
            if (dropdown.value) {
                clearError(dropdown);
            }
        });
    }
    
    1. ドロップダウンにchangeイベントを設定:ユーザーがドロップダウンを操作した際に呼び出されます。
    2. 値が選択されているか確認:ドロップダウンの値が空でなければエラーメッセージを削除します。

    フォーム送信時のバリデーション

    「月」と「日」は、ContactForm7の標準タグで作成したので、そちらのバリデーションが効いてくれると思ったのですが、なぜかうまくチェックしてくれず…。

    結局まとめてここですべて必須チェックすることにしました。

    function validateForm(event) {
        let isValid = true;
    
        // 年の必須チェック
        const yearDropdown = document.getElementById('birth-year');
        if (!yearDropdown.value || yearDropdown.value === '') {
            showError(yearDropdown, '年を選択してください。');
            isValid = false;
        } else {
            clearError(yearDropdown);
        }
    
        // 月の必須チェック
        const monthDropdown = document.querySelector('[name="birth-month"]');
        if (monthDropdown && (!monthDropdown.value || monthDropdown.value === '選択してください')) {
            showError(monthDropdown, '月を選択してください。');
            isValid = false;
        } else {
            clearError(monthDropdown);
        }
    
        // 日の必須チェック
        const dayDropdown = document.querySelector('[name="birth-day"]');
        if (dayDropdown && (!dayDropdown.value || dayDropdown.value === '選択してください')) {
            showError(dayDropdown, '日を選択してください。');
            isValid = false;
        } else {
            clearError(dayDropdown);
        }
    
        // バリデーション失敗時は送信を停止
        if (!isValid) {
            event.preventDefault();
        }
    }
    
    1. isValidフラグ:全体のバリデーションが成功しているかを示すフラグ。
    2. 年、月、日のそれぞれをチェック:値が空、または「選択してください」であればエラーメッセージを表示し、isValidfalseに設定。
    3. 送信を停止:バリデーションが失敗した場合、event.preventDefault()でフォーム送信をブロック。

    イベントリスナーの設定

    populateYearDropdown();
    
    const yearDropdown = document.getElementById('birth-year');
    if (yearDropdown) setupErrorClearOnChange(yearDropdown);
    
    const monthDropdown = document.querySelector('[name="birth-month"]');
    if (monthDropdown) setupErrorClearOnChange(monthDropdown);
    
    const dayDropdown = document.querySelector('[name="birth-day"]');
    if (dayDropdown) setupErrorClearOnChange(dayDropdown);
    
    const form = document.querySelector('form.wpcf7-form');
    if (form) {
        form.addEventListener('submit', validateForm);
    }
    
    1. 年のドロップダウンを生成:populateYearDropdownで動的に生成。
    2. 各ドロップダウンのchangeイベントにエラークリア処理を設定:ドロップダウンが操作された際にエラーを消します。
    3. フォーム送信時にバリデーションを実行:フォーム全体をチェックし、不備があれば送信を停止します。