【プラグイン無し】Contact Form 7での確認画面とサンクスページ(送信完了)をJavaScriptで自作する

Contact Form 7はデフォルトでは確認画面とサンクスページ(送信完了)が無く、多くの方はプラグイン「Contact Form 7 Multi-Step Forms」を使用するでしょう。
この記事でも以前に、「Contact Form 7で確認画面を作る方法【Multi-Step Formsの使い方】」という記事を書いてますが、
- 500文字以上の長文を送信できない
- ファイル添付ができない
- 1ページに複数フォームがある時に対応できない
こういった制約がありました。
今回紹介する方法は、Contact Form 7の確認画面とサンクスページをJavaScriptで自作するので、余計なプラグインも必要ないし、制約も何もありません。Web制作の実案件では確認画面の実装は非常によくあるため、この機会に自分のものにしておきましょう。

この記事を書いたのは
しょーご(@samurabrass)
当ブログ「しょーごログ」の運営者。2018年からWeb制作・フロントエンドエンジニアとして主にWordPressでのサイト制作やシステム開発のフロントエンドを担当。2024年からは外資のWeb系企業でディレクター業も兼務。月数万PVのブログとYouTubeで情報発信を行っている。駆け出しエンジニアのコーディング課題添削も行い、スクール講師を4年以上している経験を活かした分かりやすい記事制作を心がけている。
\現役エンジニアのレビュー付き/
実践レベルのコーディング課題公開中

- デザインカンプからのコーディングを経験したい
- 現役エンジニアのレビューを受けてみたい
- 即戦力級のポートフォリオを用意したい
2024年にデザインを完全リニューアルしています!
2025年には「8日以内提出」という納期と「修正10箇所以内」という品質項目が課された、模擬案件編も追加
コーディングに自信をつけるにはプロからのレビューを貰うのが必須なため、制作会社も利用するレビューツールで添削をしています。

Web制作学習ロードマップにも取り入れているため、学習終了まで迷わず進むことが可能です。コーディングを本気で仕事したい方はぜひご活用ください!
\無料の入門編から本格企業サイトまで/
Contact Form 7の前準備

❶Contact Form 7に対応したHTMLを組んでおく
まず前提として、Contact Form 7が出力するHTML/CSSを先回りしたコーディングをしているのが重要です。
特にラジオボタンとチェックボックスは曲者です。
まだ理解できていない人は、以下の記事で勉強しておいてください。
❷サンクスページを用意しておく
今回は確認画面は別途用意する必要は無いですが、サンクスページは必要です。
よって、固定ページでサンクスページを作っておいてください。
Contact Form 7の動作イメージ確認
やりたいことを確認します。まずはContact Form 7を使用して以下のようなオリジナルデザインのフォームを準備します。
入力必須の項目を埋めないと、確認ボタンは押せません。

必須を全部埋めると、確認ボタンのdisabledが外れ、押せるようになります。

確認画面については遷移させる必要が無いので、「入力ページと同一ページ」にして、JSでページ内容を書き替えて表示します。
確認画面で入力内容が反映されているのが分かります。

「戻るボタン」「送信ボタン」の2つがあります。送信ボタンを押すと、サンクスページにリダイレクトさせます。

自動返信メールもファイルが添付されていることが確認できます。

サンクスページをわざわざ作る意味は、コンバージョン計測がしやすいからです。
広告のコンバージョン計測はサンクスページのアクセスで計測するので、結構必要なことが多いです。
Contact Form 7で確認画面を実装する流れ
❶HTML/CSSで作ったフォームをCF7タグに置き換える
まずデザインカンプ通りにHTML/CSSで組んだフォームをCF7で動くようにするため、
CF7のエディター内で各種inputやtextarea、ラジオボタン、チェックボックスなどをCF7のタグに置き換えましょう。
idやname、入力必須項目は必須は必ず付与してください。

あらかじめ「Contact Form 7で確認画面を作る方法【Multi-Step Formsの使い方】」で構築された方はタグに置き換えても表示崩れは無いかと思います。
表示が崩れた人は、CF7が吐き出すHTMLをよくみて再構築してみてください。
ラジオボタンとチェックボックスが特に注意です。
❷HTML/CSSを調整する
今回は確認画面も同一のページで出すので、確認画面のHTMLを書き足しておきます。
また、確認画面側の要素にはconfirm_〇〇という対応したクラス名をつけておきます。
一応HTMLを全部載せます。
- 確認画面ではinputなど入力部分をspanに変えている
- 送信ボタンは確認画面の方に置く
- CSSで確認画面はデフォルトでは非表示にしておく
<div class="Form">
<!-- 会社名input -->
<div class="Form-Item">
<p class="Form-Item-Label">
<span class="Form-Item-Label-Required">必須</span>会社名
</p>
[text* company_name id:company_name placeholder "例)株式会社令和"]
</div>
<!-- 名前input -->
<div class="Form-Item">
<p class="Form-Item-Label"><span class="Form-Item-Label-Required">必須</span>氏名</p>
[text* your_name id:your_name placeholder "例)山田太郎"]
</div>
<!-- 電話番号input -->
<div class="Form-Item">
<p class="Form-Item-Label"><span class="Form-Item-Label-Required">必須</span>電話番号</p>
[tel* tel id:tel placeholder "例)000-0000-0000"]
</div>
<!-- メールアドレスinput -->
<div class="Form-Item">
<p class="Form-Item-Label"><span class="Form-Item-Label-Required">必須</span>メールアドレス</p>
[email* email id:email placeholder "例)example@gmail.com"]
</div>
<!-- ラジオボタン -->
<div class="Form-Item">
<p class="Form-Item-Label"><span class="Form-Item-Label-Required">必須</span>ラジオボタン</p>
[radio radio id:radio default:1 "選択肢❶" "選択肢❷" "選択肢❸"]
</div>
<!-- チェックボックス -->
<div class="Form-Item">
<p class="Form-Item-Label"><span class="Form-Item-Label-Required">必須</span>チェックボックス</p>[checkbox* checkbox id:checkbox "選択肢1" "選択肢2" "選択肢3"]
</div>
<div class="Form-Item">
<p class="Form-Item-Label isMsg"><span class="Form-Item-Label-Required">必須</span>お問い合わせ内容</p>
[textarea* textarea id:textarea]
</div>
<!-- File添付 -->
<div class="Form-Item">
<p class="Form-Item-Label">ファイル添付</p>
[file file-670 id:file class:file]
</div>
<div class="button-wrap">
<input type="button" class="confirm_button" value="確認する" disabled>
</div>
</div>
<!-- 確認画面 -->
<div class="confirm_area">
<h2>入力内容確認</h2>
<p>以下の内容でよろしいですか?</p>
<!-- 会社名input -->
<div class="Form-Item">
<p class="Form-Item-Label">
<span class="Form-Item-Label-Required">必須</span>会社名
</p>
<span class="confirm_company_name"></span>
</div>
<!-- 名前input -->
<div class="Form-Item">
<p class="Form-Item-Label"><span class="Form-Item-Label-Required">必須</span>氏名</p>
<span class="confirm_your_name"></span>
</div>
<!-- 電話番号input -->
<div class="Form-Item">
<p class="Form-Item-Label"><span class="Form-Item-Label-Required">必須</span>電話番号</p>
<span class="confirm_tel"></span>
</div>
<!-- メールアドレスinput -->
<div class="Form-Item">
<p class="Form-Item-Label"><span class="Form-Item-Label-Required">必須</span>メールアドレス</p>
<span class="confirm_email"></span>
</div>
<!-- ラジオボタン -->
<div class="Form-Item">
<p class="Form-Item-Label"><span class="Form-Item-Label-Required">必須</span>ラジオボタン</p>
<span class="confirm_radio"></span>
</div>
<!-- チェックボックス -->
<div class="Form-Item">
<p class="Form-Item-Label"><span class="Form-Item-Label-Required">必須</span>チェックボックス</p><span class="confirm_checkbox"></span>
</div>
<div class="Form-Item">
<p class="Form-Item-Label isMsg"><span class="Form-Item-Label-Required">必須</span>お問い合わせ内容</p>
<span class="confirm_textarea"></span>
</div>
<!-- File添付 -->
<div class="Form-Item">
<p class="Form-Item-Label">ファイル添付</p>
<span class="confirm_file"></span>
</div>
<div class="button-wrap">
[submit "送信"]
<input type="button" class="back_button" value="戻る">
</div>
</div>
<!-- 完了画面 -->
<div class="thanks_area">
<h2>送信完了</h2>
<p>お問合せいただきありがとうございました。<br>
2営業日以内に担当者よりご返信差し上げます。</p>
</div>/*確認画面と完了画面を非表示*/
.confirm_area,
.thanks_area {
display: none;
}
/*デフォルトのサンクスメッセージを非表示*/
.wpcf7-response-output{
display: none;
}❸JavaScriptを書く
さてここからが最重要ポイントで、最難関ポイントです。
一旦JSを全部載せますので、コピペしてもらって構いません。
document.addEventListener('DOMContentLoaded', () => {
// 入力内容を格納するための変数
let val;
// 入力フィールドのタイプを格納するための変数
let type;
// ラジオボタンの選択値を格納するための変数
let radio;
// チェックボックスの選択値を格納するための変数
let check;
// ラジオボタンの初期値を取得し、確認画面に反映させる
const radioButtons = document.querySelectorAll('[type="radio"]:checked');
radioButtons.forEach(button => {
// ラジオボタンの選択値を取得
radio = button.value;
// ラジオボタンの親要素からidを取得
const id = button.closest('[id]').id;
// 取得したidをクラス名に追加し、確認画面の値を設定
document.querySelector(`.confirm_${id}`).textContent = radio;
});
// 入力フィールドの内容が変更された場合の処理
const formInputs = document.querySelectorAll('.Form-Item input, .Form-Item select, .Form-Item textarea');
formInputs.forEach(input => {
input.addEventListener('change', function () {
// 入力内容を取得
val = this.value;
// 入力フィールドのタイプを取得
type = this.getAttribute("type");
// ラジオボタンの場合の処理
if (type === "radio") {
// ラジオボタンの選択値を取得
radio = this.value;
// ラジオボタンの親要素からidを取得
const id = this.closest("[id]").id;
// 取得したidをクラス名に追加し、確認画面の値を設定
document.querySelector(`.confirm_${id}`).textContent = radio;
}// チェックボックスの場合の処理
else if (type === "checkbox") {
// チェックボックスの選択値を取得
check = this.value;
// チェックボックスの親要素からidを取得
const id = this.closest("[id]").id;
// 取得したidをクラス名に追加し、確認画面の値を設定
document.querySelector(`.confirm_${id}`).textContent += check + " / ";
}// その他の場合の処理
else {
// 入力フィールドのidを取得
const id = this.id;
// 取得したidをクラス名に追加し、確認画面の値を設定
document.querySelector(`.confirm_${id}`).textContent = val;
}
});
});
// 確認ボタンをクリックした場合の処理
const confirmButton = document.querySelector(".confirm_button");
confirmButton.addEventListener('click', () => {
document.querySelector(".Form").style.display = 'none';
document.querySelector(".confirm_area").style.display = 'block';
window.scrollTo(0, document.querySelector('#navi').getBoundingClientRect().top);
});
// 戻るボタンをクリックした場合の処理
const backButton = document.querySelector(".back_button");
backButton.addEventListener('click', () => {
document.querySelector(".Form").style.display = 'block';
document.querySelector(".confirm_area").style.display = 'none';
window.scrollTo(0, document.querySelector('#navi').getBoundingClientRect().top);
});
// 必須項目が変更された場合の処理
const requiredInputs = document.querySelectorAll('[aria-required="true"]');
requiredInputs.forEach(input => {
input.addEventListener('input', () => {
// フラグ
let flag = true;
// 必須項目をループで確認
requiredInputs.forEach(requiredInput => {
if (requiredInput.value === "") {
flag = false;
}
});
// フラグに基づいて確認ボタンを有効化/無効化
confirmButton.disabled = !flag;
});
});
// 送信ボタンをクリックした場合の処理
document.addEventListener('wpcf7mailsent', (event) => {
location = 'https://〇〇.com/thanks/';
}, false);
});
以下簡単な解説です。
初期値の設定
const radioButtons = document.querySelectorAll('[type="radio"]:checked');
radioButtons.forEach(button => {
// ここに初期値の設定処理が含まれています
});
ラジオボタンの初期値を取得して、確認画面に反映させます。
querySelectorAllを使用して、チェックされたラジオボタンをすべて選択し、それぞれのラジオボタンの値と ID を取得し、確認画面に表示します。
入力フィールドの変更イベントのリスナーの追加
const formInputs = document.querySelectorAll('.Form-Item input, .Form-Item select, .Form-Item textarea');
formInputs.forEach(input => {
input.addEventListener('change', function () {
// ここに入力フィールドの変更時の処理が含まれています
});
});
入力フィールド(input、select、textarea)の内容が変更されたときに実行される処理を追加します。
changeイベントが発生するたびに、入力された値が取得され、それに応じて確認画面の表示が更新されます。
確認ボタンのクリックイベントのリスナーの追加
const confirmButton = document.querySelector(".confirm_button");
confirmButton.addEventListener('click', () => {
// ここに確認ボタンがクリックされたときの処理が含まれています
});
確認ボタンがクリックされたときに実行される処理を追加します。この場合、入力フォームが非表示になり、確認画面が表示されるようになります。
戻るボタンのクリックイベントのリスナーの追加
const backButton = document.querySelector(".back_button");
backButton.addEventListener('click', () => {
// ここに戻るボタンがクリックされたときの処理が含まれています
});
戻るボタンがクリックされたときに実行される処理を追加します。この場合、確認画面が非表示になり、入力フォームが再び表示されるようになります。
必須項目の変更イベントのリスナーの追加
const requiredInputs = document.querySelectorAll('[aria-required="true"]');
requiredInputs.forEach(input => {
input.addEventListener('input', () => {
// ここに必須項目が変更されたときの処理が含まれています
});
});
必須項目の内容が変更されたときに実行される処理を追加します。
これにより、必須項目がすべて入力されているかどうかを確認し、確認ボタンの有効性を制御します。
送信ボタンのクリックイベントのリスナーの追加
document.addEventListener('wpcf7mailsent', (event) => {
// ここに送信ボタンがクリックされたときの処理が含まれています
}, false);
送信ボタンがクリックされたときに実行される処理を追加します。
この場合、フォームが正常に送信された後、指定された場所にリダイレクトされるようになります。
❹JavaScriptのクラス名を自分のHTMLのに合わせる
ここから自分のHTMLに合わせてJavaScriptを書き換えます。
と言っても、クラス名とサンクスページのリダイレクト先を書き換えるだけです。
まず以下の確認ボタンと戻るボタン処理のクラス名部分は、自分のに変えてください。
// 確認ボタンをクリックした場合の処理
const confirmButton = document.querySelector(".confirm_button");
confirmButton.addEventListener('click', () => {
document.querySelector(".Form").style.display = 'none';
document.querySelector(".confirm_area").style.display = 'block';
window.scrollTo(0, document.querySelector('#navi').getBoundingClientRect().top);
});
// 戻るボタンをクリックした場合の処理
const backButton = document.querySelector(".back_button");
backButton.addEventListener('click', () => {
document.querySelector(".Form").style.display = 'block';
document.querySelector(".confirm_area").style.display = 'none';
window.scrollTo(0, document.querySelector('#navi').getBoundingClientRect().top);
});ここのクラス名も同様です。
// 入力フィールドの内容が変更された場合の処理
const formInputs = document.querySelectorAll('.Form-Item input, .Form-Item select, .Form-Item textarea');送信後のサンクスページURLも自分のものに変えてください。
// 送信ボタンをクリックした場合の処理
document.addEventListener('wpcf7mailsent', (event) => {
location = 'https://〇〇.com/thanks/';
}, false);❺メール設定
最後にメール設定をプラグイン設定ページより行ってください。
メールタグの名前はnameと紐づいているので、人によって異なります。
これをいれることで、メール内容に反映されます。

❻動作確認
最後に動作確認をして終了です。
- 戻るボタンが機能している
- 確認画面で全てのデータが反映されている
- 送信してリダイレクトする
- メールが届く(ファイル含め)
確認画面実装でバグが出た場合
上記のコードをAIにレビューさせた所、以下の改善点が指摘されました。上手く動作しない場合、AIでリファクタリングをお願いします。
- チェックボックスの値が増殖する:changeのたびに追記しているため、付け外しで同じ値が何度も表示される。毎回「checkedを集計して上書き」にする。
- radioのID取得が不安定:
closest("[id]")は構造依存でズレやすい。idではなくnameでグループ判定する方が安全。 - 初期値が確認画面に反映されない:DOMContentLoaded時にradio以外は未反映。自動入力・戻る操作でズレるため、初回に全項目を描画する処理が必要。
- changeイベントのみで反映が遅い:text・textareaは
input、radio・checkboxはchangeを使い分けるとUXが向上。 - 必須チェックが不十分:radio・checkboxの未選択を検知できない。
checked判定やtrim()を含めたチェックが必要。 - fileの確認表示が不安定:
valueではなくfiles[0].nameを表示し、ファイル名のみに限定する。 - スクロール処理がズレる可能性:
getBoundingClientRect().top直接指定は危険。scrollIntoView()の方が安全。 - 確認画面更新ロジックが分散している:フィールドごとの個別更新ではなく、まとめて再描画する構造にすると保守性が上がる。
- 送信後遷移の書き方が古い:
location =よりlocation.href =の方が一般的で可読性が高い。
よって、バグが出る場合は以下のコードに差し替えてみてください。
document.addEventListener('DOMContentLoaded', () => {
const form = document.querySelector('.Form');
const confirmArea = document.querySelector('.confirm_area');
const confirmButton = document.querySelector('.confirm_button');
const backButton = document.querySelector('.back_button');
if (!form || !confirmArea || !confirmButton) return;
// スクロール先:存在すればそこへ、無ければフォーム先頭へ(#navi依存で落とさない)
const scrollTarget = document.querySelector('#navi') || form;
const scrollToTop = () => scrollTarget.scrollIntoView({ behavior: 'smooth' });
// ── 確認画面の描画:押した瞬間に全項目を読み直して上書き ──
// これにより「値の増殖」「初期値の未反映」「戻る操作でのズレ」を一括で回避
const renderConfirm = () => {
confirmArea.querySelectorAll('[class*="confirm_"]').forEach((span) => {
const cls = [...span.classList].find((c) => c.startsWith('confirm_'));
if (!cls) return;
// .confirm_company_name → id="company_name" を探す(CF7の id: と対応)
const key = cls.replace('confirm_', '');
const target = document.getElementById(key);
if (!target) return;
// ラジオ/チェックボックス:id はCF7のラッパーspanに付くので中の :checked を集計
const group = target.querySelectorAll('input[type="radio"], input[type="checkbox"]');
if (group.length) {
span.textContent = [...group]
.filter((el) => el.checked)
.map((el) => el.value)
.join(' / ');
return;
}
// ファイル:value は fakepath になるのでファイル名のみ表示
if (target.type === 'file') {
span.textContent = target.files.length ? target.files[0].name : '';
return;
}
// text / email / tel / textarea / select
span.textContent = target.value;
});
};
// ── 必須チェック:テキスト系と選択系を分けて判定 ──
const validate = () => {
let ok = true;
// テキスト系(radio/checkbox は下で処理するので除外)
form.querySelectorAll('input[aria-required="true"], textarea[aria-required="true"]')
.forEach((el) => {
if (el.type === 'radio' || el.type === 'checkbox') return;
if (el.value.trim() === '') ok = false;
});
// 選択系:CF7の必須ラッパー内に :checked が1つも無ければNG
form.querySelectorAll('.wpcf7-validates-as-required').forEach((wrap) => {
const g = wrap.querySelectorAll('input[type="radio"], input[type="checkbox"]');
if (g.length && ![...g].some((el) => el.checked)) ok = false;
});
confirmButton.disabled = !ok;
};
// 入力中も選択時も再判定(初期状態も一度走らせる)
form.addEventListener('input', validate);
form.addEventListener('change', validate);
validate();
// ── 確認ボタン ──
confirmButton.addEventListener('click', () => {
renderConfirm(); // 最新値で描画してから切り替え
form.style.display = 'none';
confirmArea.style.display = 'block';
scrollToTop();
});
// ── 戻るボタン(display は '' でCSS側の指定に戻す) ──
if (backButton) {
backButton.addEventListener('click', () => {
confirmArea.style.display = 'none';
form.style.display = '';
scrollToTop();
});
}
// ── 送信完了後のリダイレクト ──
document.addEventListener('wpcf7mailsent', () => {
window.location.href = 'https://〇〇.com/thanks/';
}, false);
});1ページに複数フォームがある場合
ここまでのコードは、1ページに1つのフォームがある前提でした。
しかし実案件では「1ページに複数のお問い合わせフォームを設置したい」というケースもあります。この場合、これまでのコードだと最初の1つのフォームしか動かないので、少しだけ書き換えが必要です。
やることは大きく2つだけです。
- JavaScriptを「フォームごとに処理する」形に書き換える
- サンクスページのURLを、フォームごとにHTML側で指定する
❶サンクスページURLをHTMLで指定する
複数フォームだと遷移先も別々になることが多いので、リダイレクト先はJavaScriptに直書きせず、HTML側に持たせます。
各フォームの完了画面(thanks_area)に、data-thanks-urlという属性でサンクスページのURLを書いてください。
1つ目のフォーム:
<!-- 完了画面 -->
<div class="thanks_area" data-thanks-url="https://〇〇.com/thanks-a/">
<h2>送信完了</h2>
<p>お問合せいただきありがとうございました。<br>
2営業日以内に担当者よりご返信差し上げます。</p>
</div>2つ目のフォーム:
<!-- 完了画面 -->
<div class="thanks_area" data-thanks-url="https://〇〇.com/thanks-b/">
<h2>送信完了</h2>
<p>お問合せいただきありがとうございました。<br>
2営業日以内に担当者よりご返信差し上げます。</p>
</div>このように、フォームごとにdata-thanks-urlの値を変えるだけで、遷移先を分けられます。
すべて同じサンクスページでよい場合は、同じURLを入れておけばOKです。
❷idの重複に注意する
CF7のid:と、確認画面側のconfirm_クラスは、フォームごとに別の名前にしておくのがおすすめです。
たとえば1つ目のフォームがid:company_nameなら、2つ目はid:company_name2にして、確認画面側もconfirm_company_name2に合わせます。
<!-- 1つ目のフォーム -->
[text* company_name id:company_name placeholder "例)株式会社令和"]
<span class="confirm_company_name"></span>
<!-- 2つ目のフォーム -->
[text* company_name2 id:company_name2 placeholder "例)株式会社令和"]
<span class="confirm_company_name2"></span>同じidをページ内で使い回すのはHTMLのルール違反で、思わぬ不具合の原因になります。少し面倒でも、フォームごとに名前を分けておきましょう。
❸複数フォーム対応のJavaScript
下のコードをそのまま貼り付けてください。
単一フォーム版との違いは「form.wpcf7-formごとに処理する」ようにした点だけです。各フォームの中だけを見て動くので、複数フォームが並んでいても互いに干渉しません。
document.addEventListener('DOMContentLoaded', () => {
// 各CF7フォームは form.wpcf7-form 単位でスコープする(idが重複しても衝突しない)
document.querySelectorAll('form.wpcf7-form').forEach((cf7Form) => {
const form = cf7Form.querySelector('.Form');
const confirmArea = cf7Form.querySelector('.confirm_area');
const confirmButton = cf7Form.querySelector('.confirm_button');
const backButton = cf7Form.querySelector('.back_button');
// 確認画面を使わない通常フォームはスキップ
if (!form || !confirmArea || !confirmButton) return;
const scrollToTop = () => form.scrollIntoView({ behavior: 'smooth' });
// ── 確認画面の描画:押した瞬間にこのフォーム内の全項目を読み直して上書き ──
const renderConfirm = () => {
confirmArea.querySelectorAll('[class*="confirm_"]').forEach((span) => {
const cls = [...span.classList].find((c) => c.startsWith('confirm_'));
if (!cls) return;
// .confirm_company_name → このフォーム内の id="company_name" を探す
const key = cls.replace('confirm_', '');
const target = cf7Form.querySelector(`[id="${key}"]`);
if (!target) return;
// ラジオ/チェックボックス:ラッパー内の :checked を集計
const group = target.querySelectorAll('input[type="radio"], input[type="checkbox"]');
if (group.length) {
span.textContent = [...group]
.filter((el) => el.checked)
.map((el) => el.value)
.join(' / ');
return;
}
// ファイル:ファイル名のみ
if (target.type === 'file') {
span.textContent = target.files.length ? target.files[0].name : '';
return;
}
// text / email / tel / textarea / select
span.textContent = target.value;
});
};
// ── 必須チェック(このフォーム内だけで判定) ──
const validate = () => {
let ok = true;
form.querySelectorAll('input[aria-required="true"], textarea[aria-required="true"]')
.forEach((el) => {
if (el.type === 'radio' || el.type === 'checkbox') return;
if (el.value.trim() === '') ok = false;
});
form.querySelectorAll('.wpcf7-validates-as-required').forEach((wrap) => {
const g = wrap.querySelectorAll('input[type="radio"], input[type="checkbox"]');
if (g.length && ![...g].some((el) => el.checked)) ok = false;
});
confirmButton.disabled = !ok;
};
form.addEventListener('input', validate);
form.addEventListener('change', validate);
validate();
// ── 確認ボタン ──
confirmButton.addEventListener('click', () => {
renderConfirm();
form.style.display = 'none';
confirmArea.style.display = 'block';
scrollToTop();
});
// ── 戻るボタン ──
if (backButton) {
backButton.addEventListener('click', () => {
confirmArea.style.display = 'none';
form.style.display = '';
scrollToTop();
});
}
});
// ── 送信完了後のリダイレクト(フォームごとに data-thanks-url を読む) ──
// 発火元(送信されたフォームのラッパー)から、そのフォーム専用のURLを取得
document.addEventListener('wpcf7mailsent', (event) => {
const el = event.target.querySelector?.('[data-thanks-url]');
const url = el?.dataset.thanksUrl;
if (url) window.location.href = url;
}, false);
});これで、1ページに何個フォームを置いても、それぞれ独立して確認画面・サンクスページが動作します。
複数フォームの実装は少しだけ難易度が上がりますが、やっていることは「フォームごとに処理を分けているだけ」です。焦らず1つずつ確認しながら進めてみてください。
プラグインを使いContact Form 7で確認画面とサンクスページを実装する場合
なお、コードを書かずに確認画面を実装したい方には、無料プラグイン「Frontierline Forms for Contact Form 7」もあります。
かなり新しいプラグインとなっており、Contact Form 7 に確認画面・完了画面・マルチステップフォームを追加でき、送信データのDB保存・CSV出力まで無料で使えます。

WordPress.org 公式ディレクトリに掲載されており、管理画面・フロントとも日本語UIなので、コードのメンテナンスを避けたい案件でも導入しやすい選択肢です。
- 公式(そのままインストール):https://ja.wordpress.org/plugins/frontierline-forms/
- 製品ページ・使い方ドキュメント:https://frontierline.co.jp/plugins/frontierline-forms/
今後の開発ロードマップも意欲的で、期待できるプラグインだと思います。選択肢の一つとして脳内に入れておくのもいいと思います。
制限の無いお問い合わせフォームへ

今回はContact Form 7の確認画面をプラグイン無しで実装する方法を紹介しました。
ほとんどどんなお問い合わせフォームでも対応可能なため、Web制作を独学している方、デイトラなどのWeb制作スクールに通っている方もぜひ参考にしてください。
JavaScriptの部分が難関かと思いますが、クラス名を入れ替えるのが大半なので、ゆっくり焦らず読解してみてください。
AIにコーディングを補助してもらう方法を以前解説しているので、そちらを使えばスムーズかと思います。
また、私が出している【上級】デザインカンプからのコーディング実践演習【WordPress実案件レベル】でのお問い合わせフォームに導入して実践してみるのもいいかと思います。

HTML初心者からWordPress実案件レベルまでのコーディング演習課題を「専用ページ」にて公開しています。2026年も案件獲得や転職に成功した人が多数出ています。

- Figma,Photoshopデザインからのコーディング
- サーバーアップロードでサイト公開
- プロによる最大3回の表示確認特典
- レビュー返しは爆速
- 2024年にデザイン刷新!被らないポートフォリオ
「初級編」は初めてデザインからコーディングする方向け
「中級編」はJavaScriptやjQueryの練習
「上級編」はWordPressの実案件を模擬体験できるレベル感にしています。
中級者の方には高難易度課題を詰め合わせた「即戦力セット」も出しています。
全課題で「実務レベルの、プロの厳しいレビュー」を受けられるようにしています。
また、2025年には随時デザインの刷新をしており、完全リニューアル!!
他者と差をつけられるポートフォリオが準備できます!

制作会社も使用する専用レビューツールで分かりやすく添削していきます!
基本的に「まとめて購入」していただくとかなりお得になります↓

コーディングは書籍だけではなかなか実力がつかないので、実務レベルのレビューを受けて自身をつけたい人は是非挑戦してみてください!

\課題の購入はこちらから/
しょーごログのコーディング課題後に、ニートから最大月収100万を稼げる用になった方のインタビュー記事も参考になるはずです。





























