Build Phases

Phase 4 — Forms & Submissions

Contact Form 7 integration via the WordPress REST API.

Find Your Form ID

In WordPress admin, go to Contact → Contact Forms. Click your form — the URL will show ?post=123. That number is your Form ID.

Contact Form Component

// src/components/ContactForm.tsx
"use client";
import { useState } from "react";

// Replace YOUR_FORM_ID with the numeric ID from CF7 admin URL (?post=123)
const CF7_URL = `${process.env.NEXT_PUBLIC_WP_API_URL
  ?.replace("/wp/v2","")}/contact-form-7/v1/contact-forms/YOUR_FORM_ID/feedback`;

export default function ContactForm() {
  const [status, setStatus] = useState<"idle"|"loading"|"success"|"error">("idle");

  async function handleSubmit(e: React.FormEvent<HTMLFormElement>) {
    e.preventDefault();
    setStatus("loading");
    const formData = new FormData(e.currentTarget);
    try {
      const res = await fetch(CF7_URL, { method: "POST", body: formData });
      const result = await res.json();
      setStatus(result.status === "mail_sent" ? "success" : "error");
    } catch {
      setStatus("error");
    }
  }

  return (
    <form onSubmit={handleSubmit}>
      <input type="text"  name="your-name"    placeholder="Your Name" required />
      <input type="email" name="your-email"   placeholder="Email"     required />
      <textarea          name="your-message"  placeholder="Message"   required />
      <button type="submit" disabled={status === "loading"}>
        {status === "loading" ? "Sending..." : "Send Message"}
      </button>
      {status === "success" && <p>Message sent!</p>}
      {status === "error"   && <p>Something went wrong. Please try again.</p>}
    </form>
  );
}
!

The CF7 endpoint path is /wp-json/contact-form-7/v1/contact-forms/ID/feedback — not the standard /wp/v2/ path. Replace ID with the numeric ID from the CF7 admin URL.

Matching Field Names

The name attribute on each input must match exactly what you set in the CF7 form editor in WordPress. Mismatched names are the most common cause of silent failures.

CF7 Field TagHTML name attribute
[text your-name]name="your-name"
[email your-email]name="your-email"
[textarea your-message]name="your-message"

API Response Statuses

StatusMeaning
mail_sentForm submitted and email sent successfully
mail_failedForm valid but email failed to send — check SMTP settings
validation_failedRequired fields missing or invalid
spamFlagged by Akismet or honeypot
TIP

Test your form submission directly in the terminal first: curl -X POST "https://cms.yourdomain.com/wp-json/contact-form-7/v1/contact-forms/123/feedback" -F "your-name=Test" -F "your-email=test@test.com" -F "your-message=Hello"

PreviousPhase 3 — Dynamic PagesNextPhase 5 — ISR Webhooks