非同期フォーム(fetch + admin-ajax + nonce)
概要
画面遷移なしで問い合わせを送信する最低限のAjaxフォーム。CSRF対策(nonce)込みで、本番化しやすい構成にしています。UIはプレーンでOK、まずは動かす。
PHP(functions.php)
PHP
// スクリプト登録 & nonce埋め込み
add_action('wp_enqueue_scripts', function () {
wp_enqueue_script('ajax-form', get_stylesheet_directory_uri() . '/ajax-form.js', [], false, true);
wp_localize_script('ajax-form', 'AJX', [
'url' => admin_url('admin-ajax.php'),
'nonce' => wp_create_nonce('send_contact'),
]);
});
// ハンドラ
add_action('wp_ajax_send_contact', 'handle_send_contact');
add_action('wp_ajax_nopriv_send_contact', 'handle_send_contact');
function handle_send_contact() {
check_ajax_referer('send_contact', 'nonce');
$name = sanitize_text_field($_POST['name'] ?? '');
$msg = sanitize_textarea_field($_POST['message'] ?? '');
if ($name === '' || $msg === '') wp_send_json_error(['message' => '必須項目が未入力です'], 422);
// ここでwp_mail()などに接続可能
wp_send_json_success(['message' => '送信しました']);
}JS(ajax-form.js)
JavaScript
document.addEventListener('submit', async (e) => {
const form = e.target.closest('#ajax-contact');
if (!form) return;
e.preventDefault();
const fd = new FormData(form);
fd.append('action', 'send_contact');
fd.append('nonce', AJX.nonce);
const res = await fetch(AJX.url, { method: 'POST', body: fd });
const data = await res.json();
form.querySelector('.message').textContent =
data.success ? data.data.message : (data.data?.message || '失敗しました');
});フォームHTML
HTML
<form id="ajax-contact">
<input name="name" placeholder="お名前">
<textarea name="message" placeholder="メッセージ"></textarea>
<button>送信</button>
<p class="message" aria-live="polite"></p>
</form>解説
・wp_localize_scriptでnonceとURLをJSへ安全に橋渡し
・返却はwp_send_json_*を使い、フロントで一行で扱える形に
・実運用ではreCAPTCHA/Rate limit/ログを追加


