• TOP
  • 記事一覧
  • WordPressテーマ制作者が押さえるべきContact Form 7の実装ポイント 納品時のポイント

WordPressテーマ制作者が押さえるべきContact Form 7の実装ポイント 納品時のポイント

更新日:2025/02/24

WordPressテーマを制作・納品する際、お問い合わせフォームの実装は重要なポイントとなります。今回は、環境に依存せずContact Form 7を確実に動作させるための実装方法をご紹介します。

なぜContact Form 7なのか?

WordPressのお問い合わせフォームプラグインとして、圧倒的なシェアを持つContact Form 7。無料で利用でき、カスタマイズ性も高いため、多くのテーマ制作者が採用しています。

WordPress自作テーマ納品時のContact Form 7実装術 – 環境非依存のアプローチ

問題点

Contact Form 7でフォームを作成すると、自動的にIDが割り振られます。例えば:

エラー: コンタクトフォームが見つかりません。

このIDは環境ごとに異なるため、開発環境で作ったフォームIDが本番環境で使えないことになります

Contact Form 7 のテンプレート書くの面倒問題
ファイルに記述した内容を Contact Form 7 のテンプレートとして利用できるように実装してみました。
https://qiita.com/k_h_b/items/67fcb47cbce45ccc017e

以下のコードを、フォームを表示したい WordPress のテンプレートファイル(page.php など)に埋め込みます。

上記のContact Form 7 のテンプレート書くの面倒問題を実装

<?php
// フォームのデータを取得
add_action('wpcf7_contact_form', function ($form) {
  $path = '{ テンプレートを記述したファイルへのパス }'; // フォームテンプレートのファイル
  ob_start();

  // 指定したテンプレートファイルを読み込む
  include $path;
  $template = ob_get_clean();

  $p = $form->get_properties();
  if ($p['form'] === $template) return $form; // 変更がなければそのまま

  $p['form'] = $template;
  $form->set_properties($p);
  $form->replace_all_form_tags();
  $form->save();
  return $form;
});

// 指定したフォームを取得して表示
$useform = array_shift(get_posts([
  'post_type' => 'wpcf7_contact_form',
  'posts_per_page' => 1,
  'name' => strtolower(urlencode('{ 利用するフォームのスラッグ }'))
]));

echo do_shortcode('

エラー: コンタクトフォームが見つかりません。

'); ?>

解決アプローチ1
タイトルでフォームをショートコードで設定できるようにする

この実装では以下のことを実現しています:

  1. フォームをソースコード(テンプレートファイル)で管理
  2. テーマ有効化時またはプラグイン有効化時に自動的にフォームを登録
  3. フォームIDではなくフォームタイトルでの参照により環境間の互換性を維持
  4. 開発環境ではテンプレートファイルの変更を自動反映

フォームの自動登録機能

<?php

/**
 * Contact Form 7統合機能
 * 
 * Contact Form 7の環境非依存実装とテンプレート自動登録機能を提供
 *
 * @package simple-form-theme
 */

if (!defined('ABSPATH')) {
    exit; // 直接アクセス禁止
}

/**
 * Contact Form 7のフォームテンプレートを更新する
 *
 * @param string $title フォームのタイトル
 * @param string $template_path テンプレートファイルのパス
 * @return bool|int 成功時はフォームID、失敗時はfalse
 */
function update_cf7_form_template($title, $template_path)
{
    if (!function_exists('wpcf7_get_contact_form_by_title')) {
        return false;
    }

    $form = wpcf7_get_contact_form_by_title($title);
    if (!$form) {
        return false;
    }

    $template = file_get_contents($template_path);
    if ($template === false) {
        return false;
    }

    $properties = $form->get_properties();
    $properties['form'] = $template;
    $form->set_properties($properties);
    return $form->save();
}

/**
 * タイトルからContact Form 7のショートコードを取得
 *
 * @param string $title フォームのタイトル
 * @return string ショートコード
 */
function get_contact_form_by_title($title)
{
    if (!function_exists('wpcf7_get_contact_form_by_title')) {
        return '';
    }

    $form = wpcf7_get_contact_form_by_title($title);
    if (!$form) {
        return '';
    }

    return '

エラー: コンタクトフォームが見つかりません。

'; } /** * カスタムショートコードを登録 */ function register_cf7_shortcode() { add_shortcode('cf7_form', function ($atts) { $atts = shortcode_atts(['title' => ''], $atts); return do_shortcode(get_contact_form_by_title($atts['title'])); }); } add_action('init', 'register_cf7_shortcode'); /** * テーマ有効化時にデフォルトのお問い合わせフォームを登録する */ function register_default_contact_form() { // Contact Form 7の必要な関数が利用可能か確認 if (!function_exists('wpcf7_contact_form')) { cf7_error_log('[CF7] Required function wpcf7_contact_form is not found'); return; } // フォームが既に存在するか確認 $form_title = 'お問い合わせフォーム'; $existing_forms = WPCF7_ContactForm::find(array('title' => $form_title)); if (empty($existing_forms)) { cf7_error_log('[CF7] Starting new form creation'); // フォームテンプレートの読み込み $template_path = get_template_directory() . '/inc/contact-form-template01.php'; if (!file_exists($template_path)) { cf7_error_log('[CF7] Template file not found: ' . $template_path); return; } try { $form_template = file_get_contents($template_path); if ($form_template === false) { cf7_error_log('[CF7] Failed to read template file'); return; } cf7_error_log('[CF7] Template loaded successfully'); // フォームの作成 $contact_form = WPCF7_ContactForm::get_template(); if (!$contact_form) { cf7_error_log('[CF7] Failed to get form template'); return; } $contact_form->set_title($form_title); $contact_form->set_properties(array( 'form' => $form_template, 'mail' => array( 'subject' => '[お問い合わせフォーム] お問い合わせがありました', 'sender' => '[your-name] <wordpress@' . $_SERVER['HTTP_HOST'] . '>', 'body' => "以下の内容でお問い合わせがありました。\n\n" . "お問い合わせ内容: [inquiry-type]\n" . "お名前: [your-name]\n" . "電話番号: [your-tel]\n" . "メールアドレス: [your-email]\n" . "備考:\n[your-message]", 'recipient' => get_option('admin_email'), 'additional_headers' => 'Reply-To: [your-email]', ), 'mail_2' => array( 'active' => true, 'subject' => 'お問い合わせありがとうございます', 'sender' => get_bloginfo('name') . ' <wordpress@' . $_SERVER['HTTP_HOST'] . '>', 'body' => "以下の内容でお問い合わせを受け付けました。\n\n" . "お問い合わせ内容: [inquiry-type]\n" . "お名前: [your-name]\n" . "電話番号: [your-tel]\n" . "メールアドレス: [your-email]\n" . "備考:\n[your-message]", 'recipient' => '[your-email]', ) )); $result = $contact_form->save(); cf7_error_log('[CF7] Form save result: ' . ($result ? 'Success' : 'Failed')); } catch (Exception $e) { cf7_error_log('[CF7] Form creation error: ' . $e->getMessage()); } } else { cf7_error_log('[CF7] Form already exists'); } } /** * フォームテンプレートの自動更新フック(開発モードの場合のみ) */ function maybe_update_cf7_templates($form) { // 開発モードの場合のみテンプレートを自動更新 if (defined('WP_DEBUG') && WP_DEBUG === true) { $form_title = $form->title(); if ($form_title === 'お問い合わせフォーム') { $template_path = get_template_directory() . '/inc/contact-form-template01.php'; if (file_exists($template_path)) { $template = file_get_contents($template_path); $properties = $form->get_properties(); if ($properties['form'] !== $template) { $properties['form'] = $template; $form->set_properties($properties); cf7_error_log('[CF7] Form template updated'); } } } } return $form; } add_filter('wpcf7_contact_form', 'maybe_update_cf7_templates'); /** * プラグイン有効化時のフック処理 */ function check_cf7_plugin_activation() { // アクティブなプラグインリストを取得 $active_plugins = get_option('active_plugins'); // Contact Form 7のプラグインが有効化されているか確認 $cf7_plugin = 'contact-form-7/wp-contact-form-7.php'; $cf7_active = in_array($cf7_plugin, $active_plugins); // 以前の状態を取得 $previous_state = get_option('cf7_plugin_state', 'not_set'); // プラグインが新たに有効化された場合 if ($cf7_active && $previous_state !== 'active') { // Contact Form 7が有効化されたので、デフォルトフォームを登録 register_default_contact_form(); // 状態を更新 update_option('cf7_plugin_state', 'active'); } elseif (!$cf7_active && $previous_state === 'active') { // プラグインが無効化された場合の処理(必要であれば) update_option('cf7_plugin_state', 'inactive'); } } add_action('admin_init', 'check_cf7_plugin_activation'); /** * プラグインが有効化されたときのフックに直接対応 * * @param string $plugin プラグインのパス */ function on_cf7_plugin_activation($plugin) { if ($plugin === 'contact-form-7/wp-contact-form-7.php') { // Contact Form 7が有効化されたタイミングで処理 // ただしこの時点では WPCF7_ContactForm クラスがまだロードされていない可能性があるため // 次回のページロード時に処理されるようにフラグを立てる update_option('cf7_needs_setup', 'yes'); } } add_action('activated_plugin', 'on_cf7_plugin_activation'); /** * フラグが立っている場合に初期設定を実行 */ function maybe_setup_cf7_forms() { if (get_option('cf7_needs_setup') === 'yes') { // 十分な時間が経過してContact Form 7のクラスがロードされているはず if (function_exists('WPCF7_ContactForm')) { register_default_contact_form(); // フラグを削除 delete_option('cf7_needs_setup'); } } } add_action('init', 'maybe_setup_cf7_forms', 20); // 優先度を低く設定してCF7がロードされた後に実行 /** * Contact Form 7プラグインが存在するか確認する関数 * * @return boolean プラグインがインストール・有効化されているか */ function is_cf7_active() { return class_exists('WPCF7_ContactForm') && function_exists('wpcf7_contact_form'); } /** * 管理画面でプラグイン未インストール時の通知を表示 */ function cf7_admin_notice() { // すでに通知を非表示にしていれば表示しない if (get_option('cf7_notice_dismissed')) { return; } // Contact Form 7が有効でない場合に通知を表示 if (!is_cf7_active()) { ?> <div class="notice notice-warning is-dismissible cf7-install-notice"> <p><?php _e('このテーマはContact Form 7プラグインと連携しています。お問い合わせフォーム機能を利用するには、Contact Form 7をインストールして有効化してください。', 'simple-form-theme'); ?></p> <p> <?php if (current_user_can('install_plugins')): ?> <a href="<?php echo admin_url('plugin-install.php?s=contact+form+7&tab=search&type=term'); ?>" class="button button-primary"> <?php _e('Contact Form 7をインストール', 'simple-form-theme'); ?> </a> <?php endif; ?> <a href="#" class="dismiss-notice button button-secondary"> <?php _e('通知を非表示にする', 'simple-form-theme'); ?> </a> </p> </div> <script> jQuery(document).ready(function($) { $('.cf7-install-notice .dismiss-notice').on('click', function(e) { e.preventDefault(); $.post(ajaxurl, { action: 'dismiss_cf7_notice' }); $('.cf7-install-notice').fadeOut(); }); }); </script> <?php } } add_action('admin_notices', 'cf7_admin_notice'); /** * 通知を非表示にするAJAXハンドラー */ function dismiss_cf7_notice_handler() { update_option('cf7_notice_dismissed', 1); wp_die(); } add_action('wp_ajax_dismiss_cf7_notice', 'dismiss_cf7_notice_handler'); // プラグインの読み込み確認をinitフックで行う function check_cf7_dependencies() { // プラグインのメインファイルが読み込まれているか確認 if (!defined('WPCF7_PLUGIN')) { cf7_error_log('[CF7] Contact Form 7 plugin is not loaded'); return; } // プラグインが初期化されているか確認 if (!did_action('wpcf7_init')) { cf7_error_log('[CF7] Contact Form 7 is not initialized yet'); return; } // プラグインが利用可能になってからフォームを登録 register_default_contact_form(); } // プラグインの初期化後に実行 add_action('init', 'check_cf7_dependencies', 20); // after_setup_theme フックは削除 remove_action('after_setup_theme', 'register_default_contact_form'); /** * エラーログ出力時にUTF-8でエンコード */ function cf7_error_log($message) { if (defined('WP_DEBUG') && WP_DEBUG === true) { if (mb_detect_encoding($message) !== 'UTF-8') { $message = mb_convert_encoding($message, 'UTF-8', mb_detect_encoding($message)); } error_log('[CF7] ' . $message); } }

この関数は以下のタイミングで呼び出されます:

  1. プラグイン有効化時:check_cf7_plugin_activation() 経由
  2. プラグイン初期化後:check_cf7_dependencies() 経由
  3. フラグが立っているとき:maybe_setup_cf7_forms() 経由

maybe_update_cf7_templates() 関数では、開発環境でテンプレートファイルが変更された場合に自動的にフォームを更新します:

inc/contact-form-template01.php

<div class="form">
    <div class="form-group">
        <label class="form__label">
            お問い合わせ内容
            <span class="required">必須</span>
        </label>
        <div class="form__radio-group">
            [radio inquiry-type use_label_element "まずは相談したい(無料)" "見積り希望(無料)" "採用について" "その他"]
        </div>
    </div>

    <div class="form-group">
        <label class="form__label">
            お名前
            <span class="required">必須</span>
        </label>
        [text* your-name placeholder "お名前"]
    </div>

    <div class="form-group">
        <label class="form__label">
            電話番号
            <span class="required">必須</span>
        </label>
        [tel* your-tel placeholder "電話番号"]
    </div>

    <div class="form-group">
        <label class="form__label">
            メールアドレス
            <span class="required">必須</span>
        </label>
        [email* your-email placeholder "メールアドレス"]
    </div>

    <div class="form-group">
        <label class="form__label">
            備考
        </label>
        [textarea your-message placeholder "備考欄"]
    </div>

    <div class="form-submit">
        [submit "送信する"]
    </div>
</div>
  • 「radio」は不要!* → radio だけでOK
  • ラジオボタンは元々必須項目として扱われる

テンプレートファイルでの表示

<?php
		// Contact Form 7が利用可能な場合のみ処理を実行
		if (defined('WPCF7_VERSION') && class_exists('WPCF7_ContactForm')) {
			// フォームの強制再登録(一時的に使用)
			if (defined('WP_DEBUG') && WP_DEBUG === true) {
				register_default_contact_form();
			}

			// タイトルベースでフォームのショートコードを取得して実行
			$shortcode = get_contact_form_by_title('お問い合わせフォーム');
			if ($shortcode) {
				echo do_shortcode($shortcode);
			} else {
				echo '<p>お問い合わせフォームの読み込みに失敗しました。</p>';
			}
		} else {
			echo '<p>Contact Form 7プラグインが有効化されていません。</p>';
		}
		?>

解決アプローチ2
Contact Form 7のAPIを使用して、タイトルからIDを動的に検索

  1. フォームテンプレートの提供
// functions.php
function register_default_contact_form() {
    if (function_exists('wpcf7_load_text_domain')) {
        $form_template = file_get_contents(get_template_directory() . '/inc/contact-form-template.txt');
        // フォームテンプレートを登録
    }
}
add_action('after_switch_theme', 'register_default_contact_form');
  1. フォーム名による参照
function get_contact_form_by_title($title) {
    $forms = WPCF7_ContactForm::find(array('title' => $title));
    if (!empty($forms)) {
        return '

エラー: コンタクトフォームが見つかりません。

->id() . '" title="' . $title . '"]'; } return ''; }
function get_contact_form_by_title($title) { ▶ フォームのタイトルを引数に受け取り、対応するショートコードを生成する関数 $forms = WPCF7_ContactForm::find(array(‘title’ => $title)); ▶ Contact Form 7のAPIを使用してフォームを検索 ▶ タイトルが一致するフォームの配列を取得 !empty($forms) return ‘

エラー: コンタクトフォームが見つかりません。

->id() . ‘” title=”‘ . $title . ‘”]’; ▶ 最初に見つかったフォームのIDを取得 ▶ フォームIDとタイトルを組み合わせてショートコードを生成 ▶ 環境に依存しないショートコードを動的に生成 return ”; フォームが見つからない場合 ポイント: 1. タイトルベースの検索で環境非依存を実現 2. 動的なショートコード生成で柔軟な対応が可能
  1. テンプレートファイルでの呼び出し
// page-contact.php
<?php echo do_shortcode(get_contact_form_by_title('お問い合わせフォーム')); ?>
themes/your-theme/
  ├── inc/
  │   └── contact-form-template.txt
  └── functions.php

開発環境 フォームID: 123 title: お問い合わせ テーマファイル contact-form-template.txt functions.php 本番環境 フォームID: 456 title: お問い合わせ 1. テーマにフォームテンプレートを同梱 2. タイトルベースでフォームを参照 3. 環境に応じたIDを自動取得 フォームIDに依存しない実装により、環境間の移行をスムーズに

テーマユーザーへの配慮

  1. カスタマイザーでの設定項目追加
  • フォームIDを簡単に変更できる
  • スタイルのカスタマイズオプション
  • 表示位置の調整機能
  1. ドキュメント整備のポイント
  • プラグインのインストール手順
  • フォームID確認方法の説明
  • カスタマイズ方法の解説

バリデーション

js\form-validation.js

document.addEventListener('DOMContentLoaded', function() {
    // フォームが読み込まれるまで少し待機
    setTimeout(function() {
        const form = document.querySelector('.wpcf7-form');
        if (!form) {
            console.log('フォームが見つかりません');
            return;
        }

        // ラジオボタン
        const radioButtons = form.querySelectorAll('input[name="inquiry-type"]');
        // テキスト入力(必須)
        const nameInput = form.querySelector('input[name="your-name"]');
        const telInput = form.querySelector('input[name="your-tel"]');
        const emailInput = form.querySelector('input[name="your-email"]');
        
        const submitButton = form.querySelector('.wpcf7-submit');
        const remainingCount = form.querySelector('.form__remaining');
        
        // 必須項目の状態を管理
        const validationState = {
            'inquiry-type': false,
            'your-name': false,
            'your-tel': false,
            'your-email': false
        };
        
        // 入力状態を更新する関数
        function updateValidationState() {
            // ラジオボタン
            validationState['inquiry-type'] = Array.from(radioButtons).some(radio => radio.checked);
            
            // テキスト入力
            if (nameInput) validationState['your-name'] = nameInput.value.trim().length > 0;
            if (telInput) validationState['your-tel'] = telInput.value.trim().length >= 10;
            if (emailInput) validationState['your-email'] = emailInput.value.includes('@');
            
            // コンソールに状態を出力
            console.log('更新した入力状態:', JSON.parse(JSON.stringify(validationState)));
            
            // UI更新
            updateUI();
        }
        
        // UIを更新する関数
        function updateUI() {
            const validCount = Object.values(validationState).filter(v => v).length;
            const totalCount = Object.keys(validationState).length;
            const remainingItems = totalCount - validCount;
            
            // 残り項目数の更新
            if (remainingCount) {
                remainingCount.textContent = `残りの必須項目:${remainingItems}/${totalCount}`;
            }
            
            // 送信ボタンの更新
            const isAllValid = remainingItems === 0;
            if (submitButton) {
                submitButton.disabled = !isAllValid;
                submitButton.value = isAllValid ? '送信する' : '入力が完了していません';
                submitButton.classList.toggle('is-active', isAllValid);
            }
        }
        
        // イベントリスナーの登録
        radioButtons.forEach(radio => {
            radio.addEventListener('change', updateValidationState);
        });
        
        if (nameInput) nameInput.addEventListener('input', updateValidationState);
        if (telInput) telInput.addEventListener('input', updateValidationState);
        if (emailInput) emailInput.addEventListener('input', updateValidationState);
        
        // 初期状態のチェック
        updateValidationState();
        
        // デバッグ情報
        console.log('監視対象要素:',
            '名前入力:', nameInput ? '✓' : '✗',
            '電話入力:', telInput ? '✓' : '✗',
            'メール入力:', emailInput ? '✓' : '✗',
            'ラジオボタン数:', radioButtons.length
        );
    }, 500); // フォームが完全に読み込まれるまで少し待機
});

Contact Form7で送信ボタンを押した時のみバリデーションメッセージを表示する方法
https://kikuchi-web.com/contactform7-submit-validation

人気記事ランキング
話題のキーワードから探す