Description
HXFE — Code-First Forms is a code-first WordPress form plugin. Instead of building forms in a GUI, you define them as PHP arrays and place a shortcode anywhere.
This means your forms live in your codebase — version-controlled with Git, automatically deployed, and free from database migration issues.
Why code-first?
- Git history for free — Every change to your form shows up in
git diff - Deploy without fear — Forms are code, so they deploy with your theme. No more “the form disappeared on production”
- Dynamic options — Pull select options from
get_posts(), taxonomies, or any PHP source. No manual updates - One schema, four UIs — Add
step_mode: chatbotorone_by_oneto transform the same fields into a completely different interface
Four UI modes from one schema
- Normal form — Classic input confirm complete flow (default)
- Step form — Multi-page with progress bar (
stepsarray) - One-by-one — Question-at-a-time survey style (
step_mode: 'one_by_one') - Chatbot — Chat bubble interface with typing animation, header, and timestamps (
step_mode: 'chatbot')
Key features
- 15 field types: text, email, tel, url, textarea, select, radio, checkbox, checkbox_group, number, date, file, honeypot, reCAPTCHA, privacy
- Conditional logic: show_if, required_if, skip_if (hide_if deprecated) — works in chatbot mode too
- Dynamic routing: to_rules, subject_rules, complete_redirect_rules, complete_html_rules based on submitted values
- Diagnosis mode: use
complete_html_ruleswithoutto— show results without sending email - Download after submit:
download_urlshows a download button on the complete screen (document request forms) - Form availability window:
available_from/available_untilwith custom before/after HTML - Custom validation:
pattern,minlength,maxlength,error_messageschema keys +hxfe_validate_fieldandhxfe_validate_formfilter hooks - Field HTML injection:
before_html/after_htmlschema keys - Page slug tracking: subject auto-appended with
[form-id@page-slug]for per-page aggregation - Webhook support: send to Zapier, Make, Slack, or any HTTP endpoint
- SMTP built-in: Gmail, SendGrid, Mailgun, or custom SMTP
- File upload: attached to email, auto-deleted after send
- IP restriction and password-protected forms
- iframe embedding with per-form CORS control (
allowed_origins) - Zero cookies: GDPR/EU cookie-compliant by design
- Clean default styles: CSS custom properties (design tokens) for easy theme integration, responsive at 768px
- Schema examples panel in admin: 11 copy-paste samples to get started fast
- AI-friendly: ships with
llms.txtandai-reference.mdfor agentic coding tools
Minimum example
add_filter( 'hxfe_schemas', function( $schemas ) {
$schemas['contact'] = [
'id' => 'contact',
'to' => 'admin@example.com',
'subject' => 'Contact: {name}',
'fields' => [
[ 'key' => 'name', 'type' => 'text', 'label' => 'Name', 'required' => true ],
[ 'key' => 'email', 'type' => 'email', 'label' => 'Email', 'required' => true ],
[ 'key' => 'body', 'type' => 'textarea', 'label' => 'Message', 'required' => true ],
[ 'key' => 'hp', 'type' => 'honeypot' ],
],
];
return $schemas;
} );
Shortcode: [hxfe_form id="contact"]
Chatbot example
$schemas['support'] = [
'id' => 'support',
'to' => 'admin@example.com',
'step_mode' => 'chatbot',
'bot_name' => 'Support Bot',
'bot_icon' => '🤖',
'greeting' => 'Hi! How can I help you today?',
'fields' => [
[ 'key' => 'name', 'type' => 'text', 'label' => 'Name',
'bot_message' => 'What is your name?' ],
[ 'key' => 'email', 'type' => 'email', 'label' => 'Email',
'bot_message' => 'Thanks {name}! What is your email?' ],
[ 'key' => 'hp', 'type' => 'honeypot' ],
],
];
Diagnosis chatbot (no email)
$schemas['diagnosis'] = [
'id' => 'diagnosis',
// No 'to' — result shown without sending email
'step_mode' => 'chatbot',
'complete_html_rules' => [
[ 'when' => ['plan', '==', 'basic'],
'html' => '<h3>Basic plan recommended</h3><p>Hi {name}!</p>' ],
[ 'when' => 'default',
'html' => '<p>Thank you, {name}. We will be in touch.</p>' ],
],
'fields' => [ ... ],
];
Organize schemas in separate files
// functions.php — one line
require_once get_template_directory() . '/inc/hxfe-forms.php';
Or use HXFE as a standalone plugin with glob() auto-loading.
External Services
This plugin optionally connects to Google reCAPTCHA when the recaptcha field type is enabled in a form schema.
What the service is and what it is used for:
Google reCAPTCHA is a spam-prevention service. When enabled, it loads a script from Google’s servers and verifies the user’s response server-side to determine whether the form submission is from a human or a bot.
What data is sent and when:
When a page containing an HXFE form with reCAPTCHA is loaded, the visitor’s browser loads the reCAPTCHA script from google.com. On form submission, the reCAPTCHA token generated in the visitor’s browser is sent to Google’s verification endpoint (https://www.google.com/recaptcha/api/siteverify) along with your site key. No other form field data is transmitted to Google.
reCAPTCHA is disabled by default. It is only active when a site administrator adds a recaptcha field to a form schema and configures valid API keys in the plugin settings.
Links:
* Google reCAPTCHA Terms of Service: https://policies.google.com/terms
* Google Privacy Policy: https://policies.google.com/privacy
Installation
- Upload the plugin folder to
/wp-content/plugins/ - Activate in Plugins Installed Plugins
- Add schemas via the
hxfe_schemasfilter infunctions.php - Place
[hxfe_form id="your-id"]in any page or post - View all registered forms at Settings Form Engine — Forms
FAQ
-
Does HXFE save submissions to the database?
-
No. HXFE sends email only. This is intentional — forms defined in code stay lightweight and free of database dependencies. Use Webhook support to send data to external services like Google Sheets or a CRM.
-
Can I use HXFE without writing PHP?
-
HXFE is designed for developers who want code-first form management. If you need a GUI builder, plugins like WPForms or Fluent Forms may be a better fit.
-
Does the chatbot mode work with conditional logic?
-
Yes.
show_ifconditions work in chatbot mode — hidden fields are automatically skipped. You can also use{field_key}placeholders inbot_messageto reference previous answers. -
Yes. HXFE uses zero cookies. Form state is preserved via hidden JSON fields on the server side, not browser storage.
-
Can I embed forms on external domains?
-
Yes. Use
[hxfe_iframe id="contact" site="https://your-site.com"]and configure allowed origins in Settings Form Engine iframe / CORS Settings. -
How do I connect to Zapier or Make?
-
Add a
webhooksarray to your schema with the target URL. HXFE will POST form data as JSON after each successful submission. Webhook failures do not block form submission. -
Can I skip the confirmation screen?
-
Yes. Add
'confirm' => falseto your schema. Works for normal forms and step forms. -
Can I restrict a form to specific IP addresses?
-
Yes. Add
allowed_ipsto your schema with a list of IPs or CIDR ranges. Visitors outside the whitelist see a blocked message, which you can customize withip_blocked_html.allowed_ips => [ '192.168.1.0/24', '203.0.113.5' ], ip_blocked_html => '<p>This form is only available on the campus network.</p>', -
Can I require a password to access a form?
-
Yes. Add an
authkey to your schema. To keep passwords out of Git, define them as constants inwp-config.phpand reference them in the schema.In
wp-config.php:define( 'HXFE_STAFF_PASS', 'your-secret-password' );In your schema:
‘auth’ => [ ‘users’ => [ [ ‘id’ => ‘staff’, ‘password’ => defined(‘HXFE_STAFF_PASS’) ? HXFE_STAFF_PASS : ” ] ] ]Brute-force protection is built in — access is locked for 15 minutes after 5 failed attempts.
-
Can I prevent PHP files from being edited via the WordPress admin?
-
Yes. Add this to
wp-config.php:define( 'DISALLOW_FILE_EDIT', true );This disables the theme and plugin editors in the WordPress admin. It pairs well with HXFE’s code-first approach — forms and code are managed via deployment, not the admin UI.
-
Can I save uploaded files somewhere other than email attachments?
-
HXFE deletes uploaded files from the server immediately after sending the email. This is intentional — keeping files on the server increases security risk and GDPR responsibility.
For permanent storage, the recommended approach is to use Gmail + Google Apps Script (GAS): set up a time-based trigger that reads incoming form emails and saves attachments to a designated Google Drive folder. This keeps files off your WordPress server entirely and lets you manage access through Google’s permission system.
Reviews
There are no reviews for this plugin.
Contributors & Developers
“HXFE — Code-First Forms” is open source software. The following people have contributed to this plugin.
ContributorsTranslate “HXFE — Code-First Forms” into your language.
Interested in development?
Browse the code, check out the SVN repository, or subscribe to the development log by RSS.
Changelog
1.3.7
- Security: Removed skip_sanitize parameter from hxfe_process_fields() — all values are now sanitized on every call, including confirmsubmit flow
- Security: Clarified that sanitize_text_field() and related functions are idempotent, so re-sanitizing already-sanitized values is safe
1.3.6
- Security: Added nonce verification to hxfe_handle_back() to prevent unauthorized form re-rendering
- Security: Back button now passes hxfe_nonce (hxfe_validate_{form_id}) via hx-vals
- Code: Clarified skip_sanitize=true comment in hxfe_handle_submit() to explain double-sanitize prevention
1.3.5
- Renamed schema key:
redirect_rulescomplete_redirect_rules(consistent with othercomplete_*keys) - Renamed schema keys:
before_open_html/after_close_htmlbefore_html/after_html - Renamed field keys:
min_check/max_checkmin/max(consistent withmin_date/max_date) - Deprecated field key
hide_if— useshow_ifinstead (backward compatible, will be removed in a future version)
1.3.4
- Added: Page slug auto-injected into subject as [form-id@slug] for per-page tracking
- Added: Schema examples panel in admin UI with 7 copy-paste samples
- Added: Responsive breakpoint at 768px
- Added: CSS custom properties (design tokens) for easy theme customization
- Added:
download_url/download_labelschema keys — download button on complete screen - Added:
available_from/available_untilschema keys — form availability window - Added:
before_html/after_htmlschema keys — custom messages outside window - Added:
allowed_originsschema key — per-form iframe CORS restriction - Added: Embed HTML
<iframe>copy button in admin form list - Improved: Admin UI redesigned — stat cards, clean table, monospace field type chips
- Improved: chatbot send button replaced with paper-plane SVG icon
- Improved: Login/auth screen with border, padding, full-width button
- Improved: iframe / CORS Settings tab removed — now schema-level only
- Fixed: hx-encoding=”multipart/form-data” auto-applied when file field present
- Fixed: File name shown correctly on confirm screen
- Fixed: File attachment preserved through confirm submit flow
- Fixed: Temporary file cleanup cron (hourly, 1h expiry)
- Fixed: Fade-in flash bug (remove+reflow caused visible flicker)
- Added:
complete_html_rulesschema key — conditional complete screen HTML (supports {field_key} interpolation) - Added: Diagnosis/calculator mode — omit
towithcomplete_html_rulesfor no-email chatbot - Added: chatbot +
show_if/required_ifconditional fields now fully supported - Improved: chatbot UI redesigned with LINE/Slack-style header, timestamps, and bubble shadows
- Added:
pattern/minlength/maxlength/error_messageschema keys for field-level validation - Added:
hxfe_validate_fieldfilter for per-field custom validation - Added:
hxfe_validate_formfilter for cross-field validation (password confirm, at-least-one, etc.) - Added:
before_html/after_htmlschema keys for injecting HTML around fields - Added:
disable_contextschema key to opt out of page slug auto-injection
1.3.3
- Renamed: SHFE HXFE across all PHP/JS/CSS (class names, IDs, function prefixes)
- Fixed: Scroll after htmx outerHTML swap (re-fetch element by ID after swap)
- Fixed: Step form Back button returning 403 (nonce was missing from hx-vals)
- Fixed: chatbot phpcs:ignore comment appearing as visible text in UI
- Fixed: Copy button fallback for HTTP environments (execCommand)
- Changed: Shortcode copy buttons labeled “Form” / “iFrame” for clarity
1.3.2
- Added: IP restriction — whitelist IPs and CIDR ranges per form (
allowed_ips) - Added: Customizable IP blocked message (
ip_blocked_html) - Added: Form-level password authentication (
auth.users) - Added: Brute-force protection — lockout after 5 failed attempts (15 min)
- Added: Auth session via secure httponly samesite=strict cookie
- Added: Login form labels fully customizable per form
- Added: Support for wp-config.php constants as password source (keeps secrets out of Git)
1.3.1
- Security: file field now uses HXFE’s own safe MIME whitelist by default instead of WordPress defaults
- Security: added .htaccess to hxfe-uploads/ directory to prevent PHP execution
- Added: file field type now works — uploaded files are attached to admin notification emails
- Added: includes/file-upload.php with wp_handle_upload() based processing
- Added: mime_types schema key to whitelist allowed MIME types server-side
- Added: temporary files are automatically deleted after email is sent
- Removed: lint warning about file field being unimplemented
1.3.0
- Refactored: extracted field renderer functions to includes/fields/field-renderers.php
- Refactored: added hxfe_validate_step_request() to DRY up step endpoint gate logic
- Refactored: improved PhpDoc type definitions on core functions (hxfe_process_fields, hxfe_eval_condition, hxfe_interpolate)
1.2.2
- Fixed: confirm_label now correctly applies to the input form submit button
- Fixed: hxfe-front.js (scroll, focus, loading state) was not enqueued
- Fixed: disable_default_css and custom_css now work correctly
- Fixed: chatbot.js is now only loaded on pages with chatbot forms
- Fixed: uninstall.php now removes all plugin settings from the database
- Added: error_message schema key to customize the validation error summary text
- Added: confirm_label schema key (separate from submit_label for clarity)
- Note: file field type renders HTML but file saving is not yet implemented
1.2.1
- Added tel and url field types with built-in validation
- Added Webhook support (Zapier, Make, Slack, custom HTTP endpoints)
- Added label customization: submit_label, back_label, next_label, confirm_heading
- Fixed confirmation screen: radio/select now shows label instead of value
- Fixed confirmation screen: checkbox_group shows comma-separated labels
- Fixed confirmation screen: hidden fields (show_if=false) are now excluded
- Fixed mail body: empty fields and hidden fields are now excluded
- Added confirm: false support for step forms
- Added built-in placeholders: {site_name}, {site_url}, {date}, {time}
- Added admin form list page with lint warnings and shortcode copy buttons
- Strengthened schema lint: all 15 field types, cascade_from, chatbot bot_message
- Added wp_mail() failure logging when WP_DEBUG is enabled
1.2.0
- Added field types: radio, checkbox_group, number, date, file
- Added chatbot UI mode (step_mode: chatbot) with typing animation
- Added 4 completion patterns: message, custom HTML, redirect, redirect_rules
- Added default values (value key on any field)
- Added multiple recipients (to as array)
- Added confirm: false for immediate submission
- Added cascade select (cascade_from / cascade_options)
1.1.0
- Added step forms (groups and one_by_one mode)
- Added reCAPTCHA v2 and v3
- Added privacy policy field
- Added auto-reply email
- Added SMTP configuration (Gmail, SendGrid, Mailgun, custom)
- Added iframe embedding with CORS support
- Added conditional logic (show_if, required_if, skip_if, to_rules, subject_rules)
- Added CSS customization options
1.0.0
- Initial release
- Schema-driven form rendering
- htmx-powered input confirm complete flow
- Admin notification email and auto-reply
- Honeypot spam protection
