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
タイトルでフォームをショートコードで設定できるようにする
この実装では以下のことを実現しています:
- フォームをソースコード(テンプレートファイル)で管理
- テーマ有効化時またはプラグイン有効化時に自動的にフォームを登録
- フォームIDではなくフォームタイトルでの参照により環境間の互換性を維持
- 開発環境ではテンプレートファイルの変更を自動反映
フォームの自動登録機能
<?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);
}
}
この関数は以下のタイミングで呼び出されます:
- プラグイン有効化時:
check_cf7_plugin_activation()
経由 - プラグイン初期化後:
check_cf7_dependencies()
経由 - フラグが立っているとき:
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を動的に検索
- フォームテンプレートの提供
// 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');
- フォーム名による参照
function get_contact_form_by_title($title) {
$forms = WPCF7_ContactForm::find(array('title' => $title));
if (!empty($forms)) {
return 'エラー: コンタクトフォームが見つかりません。
->id() . '" title="' . $title . '"]';
}
return '';
}
- テンプレートファイルでの呼び出し
// page-contact.php
<?php echo do_shortcode(get_contact_form_by_title('お問い合わせフォーム')); ?>
themes/your-theme/
├── inc/
│ └── contact-form-template.txt
└── functions.php
テーマユーザーへの配慮
- カスタマイザーでの設定項目追加
- フォームIDを簡単に変更できる
- スタイルのカスタマイズオプション
- 表示位置の調整機能
- ドキュメント整備のポイント
- プラグインのインストール手順
- フォーム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

-
検索
(例) debug search etc.. -
カテゴリー
-
mixhostでのWordPress利用について
更新日:2024/04/02
299 view
-
scrollHint
更新日:2024/03/13
250 view
-
XML Sitemap Generator for Google不具合のダウングレード対応、代替プラグイン
更新日:2024/06/13
236 view
-
【SnowMonkey】納品までのフローまとめ
更新日:2025/02/15
163 view
-
ワードプレスでフォントを変えたいとき、プラグインを使えば初心者でも簡単
更新日:2025/02/16
144 view
-
【Googleサーチコンソール】検索画面で表示させたくない「Googleのインデックス削除」
更新日:2024/06/07
130 view
-
【Snow Monkey】ショートコードで編集画面で任意の場所にHTMLファイルを挿入
更新日:2025/04/04
124 view
-
キーワード検索で上位表示させる方法【SEO】
更新日:2023/10/28
120 view
-
tailwindcss使い方
更新日:2024/03/13
120 view
-
Recline: GitHub Copilotで動作するClaude 3.5 Sonnet搭載の開発支援ツール
更新日:2025/01/20
110 view
-
WordPressプラグイン「All-in-One WP Migration」のトラブル
更新日:2022/03/31
84 view
-
ワードプレスセキュリティー対策まとめ【2025年】「site guard wordpress」「BackWPup バージョン5でUI変更!?」
更新日:2025/02/25
76 view
-
SSHを使用してGitHubのリポジトリをクローン、複数の接続元で公開鍵をディレクトリで区別する方法
更新日:2025/01/13
47 view
-
VSCodeで開発効率を劇的に向上させる!Roo-Clineプラグイン完全ガイド【Gemini API】
更新日:2025/02/08
43 view
-
Express、FastAPIを使用し、二重fetch構成のメリット
更新日:2025/03/28
41 view
-
「JSONスキーマ」と「Few-shot Learning」で実現する次世代生成AIソフトウェア開発の可能性
更新日:2025/02/12
40 view
-
WordPressの無料画像素材のおすすめダウンロードサイト!
更新日:2022/02/22
35 view
-
リファクタリング【VSCode Javasctipt Python】
更新日:2025/03/09
35 view
-
形態素解析とは?初心者でもわかるツールの使い方と実践例
更新日:2025/02/08
33 view
-
【Next.js AWS】音声文字起こし&要約、分析アプリケーション(S3)(Transcribe)(Amazon Bedrock)
更新日:2025/02/13
30 view