Skip to content

Import forms from Contact Form 7 - #5

Merged
AllTerrainDeveloper merged 1 commit into
mainfrom
importer/contact-form-7
Aug 16, 2026
Merged

AllTerrainDeveloper merged 1 commit into
mainfrom
importer/contact-form-7

Conversation

@AllTerrainDeveloper

Copy link
Copy Markdown
Owner

The first of the three importers: Contact Form 7, the most-installed form plugin there is, and therefore the plugin most of our potential users are switching away from.

What it does

Forms → Import (a plain admin page under the Forms menu; URL-reachable inside the OpenStation shell like every other Forms page) lists every CF7 form on the site, with an Import button per form and an import-all button per source. Each import creates a new AllTerrain form and never touches the original — importing is safe to try, safe to repeat, and reversible by deleting the copy.

The importer reads CF7's data, not its API: wpcf7_contact_form posts and their _form / _mail / _mail_2 / _messages meta. That is deliberate — the moment somebody most wants to import is right after deactivating the old plugin, exactly when its classes are gone and its posts are not.

What converts, and how faithfully

  • Fields — every CF7 form-tag becomes the equivalent field: text/email/url/tel/textarea/number/range/date/hidden/file map one to one; select (and multiple), checkbox, radio carry their choices including the label|value pipe syntax; an exclusive checkbox group becomes the radio group it behaves as; acceptance becomes a consent field with its tag content as the consent line and CF7's required-by-default semantics preserved. The * becomes required; placeholder/watermark decide whether the first quoted value is a default or a hint; min/max/minlength/maxlength/step/filetypes all survive.
  • Labels — read from the <label> Question [tag] </label> markup CF7's own generator writes, so the question imports as the author wrote it; where the markup doesn't cooperate, the field name is humanised (your-name → "Your name").
  • Mail → notification — recipient, subject and body come across with [your-name] rewritten onto {field:…} merge tags and the [_site_*]/[_date]/[_remote_ip] specials onto their equivalents. The Name <address> sender splits into from-name and from-email; a Reply-To: header becomes the reply-to; attachments switch on file attachment. Mail (2) imports only when CF7 had it switched on — importing a disabled autoresponder as a live one would e-mail visitors nobody meant to e-mail.
  • Messages — mail_sent_ok becomes the confirmation.
  • Dropped or downgraded, on purpose — CF7's quiz and CAPTCHA tags are anti-spam, and this plugin already screens for spam without charging the visitor; they are dropped. An unrecognised add-on tag becomes a visible plain-text field rather than vanishing, because a reviewable field is honest and silent data loss is not.

One conversion subtlety worth knowing about: CF7's default plain-text body reads [your-name] <[your-email]>, and a notification message is kses-filtered on save — which reads <…> as a bogus tag and would delete the visitor's address outright. Plain-text bodies get their angle brackets entity-encoded on the way in; HTML bodies are left for kses to judge. (Verified against a live kses round-trip.)

The registry is the API

Importers register on a new atf_importers filter — label plus three callables (available, forms, import) — and the built-in CF7 importer uses that filter exactly as a third-party source would. atf_imported_schema lets a site correct a mapping before the form saves; atf_form_imported fires after. All three are documented in docs/hooks-reference.md as Experimental; the readme gains a "Switching? Bring your forms with you" section and an FAQ entry.

Verification

  • 11 new PHPUnit tests (555 → suite total 544 green): the default CF7 contact template field-for-field, choice/pipe/exclusive semantics, placeholder-vs-default, bounds and filetypes, dropped-vs-downgraded tags, the full mail conversion, the Mail (2) switch, an end-to-end import from a real wpcf7_contact_form post (asserting the source is untouched and atf_form_imported fires), capability gating, and registry validation of malformed importers.
  • Live QA in wp-env: seeded a realistic CF7 form via the database, imported it through the actual admin page, and opened the result in the builder — five fields with correct types, labels, required flags and consent text; notification with {field:…} tags, reply-to and entity-encoded address line; confirmation carried over.
  • PHPCS: 0 errors (remaining warnings are the codebase's pre-existing kinds).

WPForms and Gravity Forms follow, one PR each.

🤖 Generated with Claude Code

https://claude.ai/code/session_0119U4sRRWGcTQdwYreTwpAp

The single biggest barrier to switching form plugins is the fifteen forms
somebody already built. Forms → Import now lists every wpcf7_contact_form
post on the site — read from the database directly, so it works after CF7
has been deactivated — and turns each one into an ordinary AllTerrain form:
tags become fields with their labels read from the surrounding markup, the
mail template becomes a notification with [your-name] rewritten onto
{field:…} merge tags, Mail (2) comes along only when it was switched on,
and the thank-you message becomes the confirmation. The source is never
modified, so importing is safe to try and safe to repeat.

The registry is a filter (atf_importers) that the built-in importer uses
exactly as a third-party source would, plus atf_imported_schema to correct
a mapping before it saves and atf_form_imported after the fact. WPForms
and Gravity Forms follow in their own changes.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0119U4sRRWGcTQdwYreTwpAp
@AllTerrainDeveloper
AllTerrainDeveloper merged commit e96985c into main Aug 16, 2026
3 checks passed
@AllTerrainDeveloper
AllTerrainDeveloper deleted the importer/contact-form-7 branch August 16, 2026 17:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant