Forms

Build, publish, test and manage forms in WordPress.

Forms uses the WordPress block editor. Each field is a block. A published form is placed on a page, post or template with the Form block.

Accepted submissions stay in WordPress. Forms can also send notification emails and pass selected data to an add-on.

Build and publish a form in 10 minutes

Go to XPAC → Forms → All Forms and select Add New Form.

Choose one of the seven starting patterns: Contact form, Newsletter signup, Support request, Event registration, Job application, Feedback or Quote request. Close the pattern window to start with an empty form.

Add, remove and reorder fields. Select a field to edit its label, name, description and rules in the block sidebar. Keep field names unique.

Add a Submit block if the pattern does not already have one. A form without a Submit block cannot be sent.

Open the form settings sidebar. Check Submissions, Anti-spam protection, Messages, Redirect, Email Notifications and Validation.

Publish the form. Edit the page where it should appear, insert the Form block, choose the published form, then publish or update the page.

Open the page in a private browser window. Send one valid entry and one entry with a required field empty. Check the result under XPAC → Forms → Submissions and check Deliveries if the form sends email or uses an add-on.

Publish the form as well as the page

A draft, scheduled, private, pending or trashed form is not available to normal visitors. A signed-in editor may still see a preview, which can hide this mistake.

You can also start by duplicating a form, importing a Forms JSON file, or inserting a pattern into a form that is already open. The All Forms actions menu can copy the Form block markup for pasting into a page or post.

Choose and configure fields

Most fields have these controls:

  • Label is the question the visitor reads. When you hide a visible label, test the control's accessible name with a screen reader.
  • Name identifies the answer in submissions, email variables and add-on mappings. If you change a name later, review every notification and integration that used it.
  • Description adds help below the control.
  • Placeholder is an example inside supported controls. It does not replace a label. Date and Time save it, but a browser that uses a native picker may not display it.
  • Required refuses an empty answer. You can replace its error message.

Add-ons may place another panel below a field's normal controls.

Built-in fields and actions

BlockUse it forImportant controls and checksBlock reference
CheckboxesZero, one or several choicesAdd choice labels and saved values; choose any initial ticks; Required means at least one must be ticked.Checkboxes
ConfirmationAsking for the same answer twiceChoose a target Text, Email, Phone or supported add-on field. The two values must match. The repeated value is not stored or sent in notifications.Confirmation
ConsentRecording an affirmative agreementWrite the agreement as the label and add a link if needed. Turn on Required when the visitor must agree.Consent
DateA calendar dateSet a placeholder and optional earliest and latest date. The range is checked in the browser and on the server.Date
DropdownOne choice in a compact listAdd labels and saved values; choose the initial option. A submitted value must still be one of the saved choices.Dropdown
Dynamic SelectChoices from WordPress or a REST endpointDisplay as a dropdown, radio group or checklist. Choose taxonomy terms, posts, users or REST, then set that source's filter, order and value controls.Dynamic Select
EmailAn email addressChecks email syntax. One submission per address applies to this form and ignores case. It does not prove that the mailbox exists or belongs to the visitor.Email
File UploadOne or several filesChoose allowed types, maximum size, multi-file mode and maximum count. The server's upload limit is still the upper limit.File Upload
HiddenA preset value that is not displayedSet the field name and value. A visitor can change browser-submitted hidden data, so do not use it as proof of identity, permission or price.Hidden
NumberA numeric answerSet optional minimum and maximum values. Both limits are enforced on the server.Number
PhoneA phone numberChoose a regional mask when the format must be constrained. A mask checks shape, not whether the number works or belongs to the visitor.Phone
Radio ButtonsOne choice from a short visible listAdd labels and saved values; choose the initial selection. A submitted value must still be one of the saved choices.Radio Buttons
TextOne lineSet minimum and maximum character counts. An optional pattern handles account codes and other fixed formats.Text
TextareaA longer answerSet the label, name, placeholder, description and Required rule.Textarea
TimeA time of daySet a placeholder and optional earliest and latest time. Both limits are enforced on the server.Time
URLA web addressChecks URL syntax. It does not check that the page exists or is safe to visit.URL
ResetClearing every current answerChange the button text and use its colour, typography, spacing and border controls. It does not delete a stored submission.Reset
SubmitSending the formChange the text, optional redirect and loader position. Use its colour, typography, spacing and border controls.Submit

The Form block reference covers the block used to place a saved form elsewhere on the site.

The form editor also allows Group, Columns, Heading, Paragraph, Separator, Spacer, Buttons and Patterns. Other page blocks are not offered inside a form.

Validation rules

Validation runs in the browser for quick feedback and again on the server before anything is accepted. A direct request cannot bypass the server checks.

RuleWhere it appearsWhat it checks
RequiredMost visitor-facing fieldsThe answer is not empty.
ChoiceCheckboxes, Dropdown, Radio Buttons and Dynamic SelectThe submitted value belongs to the allowed list.
MatchConfirmationThe answer equals the target field.
FormatEmail, Phone and URLThe value has the expected shape.
RangeNumber, Date and TimeThe answer is inside the saved minimum and maximum.
LengthTextThe answer meets the minimum and maximum character count.
PatternTextThe whole answer matches the regular expression.
Unique addressEmailNo active submission for this form already has the address.
File type, size and countFile UploadEvery uploaded file meets the saved field limits and the server limit.

For a Text pattern, write a Pattern message that tells the visitor what to enter. For example, a pattern of [A-Z]{2}-[0-9]{4} accepts AB-1234. An invalid pattern is reported in the editor and is not enforced until it is fixed.

Under Validation, choose whether a field is checked when it loses focus, while the visitor types or selects, or only when the form is sent. A new form checks on Submit until you enable an earlier trigger.

Dynamic Select sources

SourceControls
Taxonomy termsTaxonomy, optional parent term ID, order by name/count/ID, direction, and whether empty terms are hidden. Use -1 for all terms and 0 for top-level terms.
PostsPost type, post status, value as ID/slug/title, order by title/date/ID, and direction. Published is the normal status for a public form.
UsersOptional role, order by display name/email/ID, and direction.
REST endpointURL, label property and value property. The response must be a non-empty JSON list.

A same-site REST request carries the normal WordPress REST nonce. A request to a different origin does not. That server must allow the visitor's browser through CORS. A bad URL, timeout, HTTP error, malformed response or empty list blocks the submission and shows the choices-loading message.

The server does not fetch a remote REST list again as proof that a value is trusted. Do not use a remote choice by itself to authorize access, identify a person or set a price.

File Upload limits

Leave Allowed file types empty to use the file types WordPress normally allows. Leave the field's size or count limit empty for no extra field-level limit. The host and WordPress limits still apply.

Executable files such as .exe and .swf are refused. HTML and JavaScript files are accepted only from signed-in users who have WordPress's unfiltered upload permission. Test every allowed type on the real host before launch.

Decide what happens when a form is sent

The following panels are in the form's settings sidebar.

Submissions and availability

Three optional controls decide when fields are available:

  • Open and close on a schedule uses the site's timezone. Either end may be left open.
  • Limit how many submissions it takes counts active submissions. Spam and deleted entries do not consume the limit.
  • Only take submissions from logged-in visitors refuses signed-out visitors.

All three are off on a new form.

Each control has its own visitor message. Leave a message blank to keep the shipped, translated wording. If several rules apply, a closed or full form is reported before the sign-in requirement.

Forms checks capacity and One submission per address again at the point of acceptance. Concurrent requests cannot both take the last place or reuse the same address.

Spam protection

Honeypot adds a decoy field that people do not see. A bot that fills it is marked as spam. It needs no external service and starts off on a new form.

Site-wide flood control is under Settings → Spam and abuse. Its default is 20 attempts per visitor, per form, in five minutes. A limit of 0 turns it off. Keep a limit on login, registration and password forms.

Akismet, Cloudflare Turnstile and Google reCAPTCHA add more checks. Turnstile and reCAPTCHA refuse protected submissions when their credentials are missing; they do not turn protection off without notice.

Messages

The Messages panel holds per-form success responses and their position above or below the fields. New forms place the response below. Conditional Logic can make different responses apply to different answers.

Site defaults live under XPAC → Forms → Settings → Messages. They cover success, validation, spam, storage errors, network errors, unexpected server responses and choices that did not load. Leave a box blank to retain the shipped translation. Per-form responses override the site success message when they apply.

Email notifications

Add one or more notifications under Email Notifications. Each has To, From, optional Reply-To, optional Cc and Bcc, a subject, a message and a plain-text or HTML format.

A new notification is filled with the site administrator address, site name and all stored fields. Review those values before publishing.

Notifications run in the background after the submission is stored. Delivered means WordPress accepted the message through wp_mail(). It does not prove that the receiving mail server put it in the inbox.

Use the Variables button to insert a field by name or one of these values:

VariableValue
{{ADMIN_EMAIL}}Site administrator email address.
{{NOREPLY_EMAIL}}A no-reply address on the site's domain.
{{SITE_TITLE}}Site title.
{{REFERRER}}Page where the visitor filled in the form.
{{ALL_FIELDS}}Every stored answer with its label.

If a File Upload field appears in the message, directly or through {{ALL_FIELDS}}, its files are attached. Confirmation and Password values are not stored, emailed or offered to add-on mappings.

HTML notification markup is cleaned before it is sent. Visitor answers remain text and cannot add markup to the email.

Redirects

The Redirect panel holds one or more destinations after success. Conditional Logic can choose a destination from the visitor's answers.

A Redirect URL on the Submit block has priority over the form's Redirect panel. This lets two Submit buttons lead to different places. Leave the button URL blank to use the form-level redirect. With no matching redirect, the visitor stays on the page and sees the success message.

Work with Forms in wp-admin

Everything is under XPAC → Forms.

TabWhat it is for
OverviewSubmission, spam and delivery totals for the selected period; latest submissions; busiest forms; queue health.
All FormsCreate, search, filter, sort, edit, preview, publish, duplicate, export, trash and restore forms.
SubmissionsRead answers, filter the inbox, work with stars and notes, mark spam, export and delete.
DeliveriesSee email and add-on jobs, retry failures, dismiss failures, copy errors and export the current view.
SettingsSite-wide retention, abuse, messages and appearance. Administrators only.

All Forms

Use the status tabs, search, Add filter, column sorting and View options to narrow the list. Row actions include Edit, Submissions, Preview, Copy embed code, Publish, Switch to draft, Duplicate, Export as JSON and trash actions. The available actions depend on the form status and your WordPress permissions.

Permanently deleting a form also permanently deletes its submissions. Moving it to the Trash does not. Restoring a form returns it as a draft, so publish it again before expecting it to appear for visitors.

Submissions

Choose a form, then use status, date, search and field filters. The CSV export follows the current filters and includes every answer, including columns that are not visible in the table.

  • Opening an entry marks it read. It can be marked unread again.
  • A star puts it in the Starred view.
  • Notes record who wrote them and when. Notes are not included in CSV or print output.
  • Mark as spam, Not spam, Move to Trash, Restore and Delete permanently work on one or several selected entries.

Deleting a submission normally deletes files that still belong only to that form. The site-wide file setting can keep them instead. A file used as a featured image or referenced by another surviving submission is kept.

Deliveries

Each row identifies the submission, form, integration, status, attempts and latest error. Filter by date, form, provider or status.

  • Retry now queues a failed or dismissed delivery again when its retry data is still present.
  • Retry all failed works on the current form and provider filters.
  • Dismiss stops a failed job from counting as an outstanding failure. It does not say that the destination received the data.
  • Open submission shows the saved entry. Copy error provides text for support.

Retry data is an encrypted snapshot of the accepted form and answers. It is removed after 30 days even if the failure remains listed. Fix and retry a failure before that deadline. A provider timeout can be ambiguous: check the destination before retrying, because some services may create a duplicate.

Delivery jobs need WordPress cron and Action Scheduler. Tools → Scheduled Actions shows the queue. A Forms queue warning means new submissions are still being stored, but email and add-ons may not be running.

Site-wide settings

Settings pageControls
SubmissionsRetention days, private uploads, and whether deletion removes files.
Spam and abuseAttempts per visitor, counting period, and whether rejected spam is kept.
DeliveriesHow long to keep the record when all integrations succeeded.
MessagesDefault visitor wording for seven outcomes. Blank values keep the shipped translations.
AppearanceWhether the built-in form stylesheet is loaded.

Access and WordPress capabilities

Forms follows WordPress capabilities rather than hard-coded role names.

TaskRequired capability
Open All Forms and work with forms the user may editedit_posts, plus the normal per-post capability for the selected form.
Create a new formpublish_posts.
Import Forms JSONedit_posts; imported published/private forms become drafts when the user lacks publish_posts.
Export a formedit_posts and permission to edit that form.
Open Overview, Submissions and Deliveries; read, export and moderate entriesxpac_manage_form_submissions.
Open Forms Settings or global integration credentialsmanage_options.

Administrators receive xpac_manage_form_submissions through their existing manage_options permission. Other roles do not receive it automatically. A site owner can grant and remove it from a role with WP-CLI:

wp cap add editor xpac_manage_form_submissions
wp cap remove editor xpac_manage_form_submissions

The grant is stored in the database. Removing a deployment snippet that added it does not revoke it; run the matching removal.

Connect and test add-ons

Most provider credentials are site-wide under XPAC → Integrations. What a form does with the account is configured on that form. A saved credential proves only that WordPress accepted the setting; it does not prove that the credential works.

Use this test sequence for every enabled provider:

  1. Work on staging or with a provider account and destination made for testing.
  2. Give the credential only the permissions the add-on needs.
  3. Save the credential, reload the page and confirm that private values remain masked.
  4. Configure each action and conditional branch the live form will use. Use an address, list, table, template or webhook endpoint you control.
  5. Submit a clearly marked entry for each case while signed out. Confirm the Forms entry, the Deliveries result and the record at the provider.
  6. Exercise the provider's documented failure or test case. Confirm that the visitor entry remains available and the delivery explains what failed.
  7. Remove test contacts, rows, posts and payments. Revoke test credentials that are no longer needed.

Do not use a live mailing list, live payment mode or a production automation as a test destination. Never paste a credential into documentation, tickets, screenshots or chat. Password masking protects the wp-admin display; it is not encryption of the WordPress option in the database.

Add-ons with global credentials

Add-onGlobal settingPer-form controlSafe acceptance test
AirtablePersonal access token and optional read-only Test connection under Integrations → AirtableAirtable action panelUse a test base/table, create or update a row with a unique marker, then remove it.
AkismetOfficial Akismet plugin key first, otherwise the masked key under Integrations → AkismetAnti-spam protection → Akismet and field mappingsUse Akismet's documented test content on staging; confirm the entry follows the expected Spam path.
BrevoAPI key under Integrations → BrevoBrevo action panelUse a test list, template and owned inbox. Check each configured subscribe, unsubscribe, email or event action separately.
Campaign MonitorAPI key and Client ID under Integrations → Campaign MonitorCampaign Monitor action panelUse a test list and owned address; test subscribe and unsubscribe paths that the form uses.
Cloudflare TurnstileSite and secret keys plus widget options under Integrations → Cloudflare TurnstileToggle in Anti-spam protection; optional Turnstile field block sets placementUse Cloudflare's published test keys on staging and cover accepted, missing and failed tokens.
GetResponseAPI key and optional MAX platform settings under Integrations → GetResponseGetResponse action panelUse a test campaign and owned address; check create/update and remove actions if configured.
Google reCAPTCHAv3 site and secret keys, score and badge options under Integrations → reCAPTCHAToggle in Anti-spam protectionRegister the staging hostname, then cover an accepted score and a refused or missing token.
KlaviyoPrivate API key under Integrations → KlaviyoKlaviyo action panelUse a test list/profile and event name; check every subscribe, unsubscribe or event action in use.
MailchimpAPI key under Integrations → MailchimpMailchimp action panelUse a test audience and owned address. Confirm the intended pending or subscribed state.
MaxMindAccount ID and license key under Integrations → MaxMindIndirect: User Targeting country rules inside Conditional LogicOn staging, test both is and is not from networks with known public locations, plus an unavailable lookup. Check whether WooCommerce credentials take precedence.
SendGridAPI key under Integrations → SendGridSendGrid action panelUse a restricted key, test list/template and owned inbox. Test template email and contact actions separately.
StripeMode, currency, publishable/secret keys and webhook secret under Integrations → StripeStripe Payment Element blockUse Test mode, Stripe test cards and a signed test webhook. Cover success, decline, required authentication and a visitor who closes the page after payment.
TouchBaseProAPI key under Integrations → TouchBaseProTouchBasePro action panelUse a test list and owned address; confirm subscribe and unsubscribe behavior used by the form.
ZohoClient ID, client secret, data center and OAuth connection under Integrations → ZohoZoho action panelConnect a test Zoho Campaigns account and list; test add and remove actions with an owned address.

Provider setup, required scopes, mappings, consent behavior and failure handling are documented on each linked page.

Add-ons without a shared API key

Add-onWhere it is configuredWhat to test
WebhooksWebhooks panel on the formSend non-personal fixture data to a test receiver. Check method, encoding, headers, selected fields, response and retry behavior. Fixed header secrets are part of the form configuration.
ZapierZapier panel on the formUse a staging Catch Hook with downstream actions disabled. Inspect the sample payload before enabling the Zap.
Submission To PostSubmission To Post panel on the formCreate a draft or private post in a test post type. Check author, status, dates, taxonomy, fields and files.
Conditional LogicConditional Logic block and Execute if controlsTest every matching and non-matching branch. Hidden or disabled fields must not be required or stored.
Multi-Step FormSteps, Step, Next and Previous blocksTest keyboard and pointer navigation, validation before Next, going back, and the final Submit. Nothing is stored when the visitor leaves halfway.
Forms Auto SubmitAuto Submit panel plus a server-generated signed URLUse fixture values and a short-lived link. Test a valid link, an altered link, expiry and replay behavior. Do not put secrets in the URL.
User AuthUser Auth form panel and Forms Settings → User Auth pagesUse disposable accounts and staging mail. Test each configured registration, login, profile, reset and verification action without touching real users.
User TargetingUser Conditions added to Conditional LogicTest both sides of device, URL, cookie, storage and country rules. Country rules also need MaxMind.

Style forms with theme.json

The built-in form stylesheet is meant to provide a modern, restrained baseline. Keep XPAC → Forms → Settings → Appearance → Use the built-in form styling on, then map its tokens to the active theme under settings.custom.xp-form.

The form editor's Styles sidebar edits Label, Description, Input and Validation styles. It includes typography, spacing, colours, borders, radii and shadows where they apply, including input hover, focus, disabled, error and success states. Those values are site-wide, not per-form. Submit and Reset use their own block colour, typography, spacing and border controls.

Style precedence is:

  1. Turning built-in styling off under Forms Settings → Appearance disables the stylesheet for the whole site. The Styles sidebar cannot turn it back on.
  2. Values saved through the form editor's Styles sidebar override the theme.
  3. settings.custom.xp-form in the active theme's theme.json overrides the plugin defaults.
  4. Plugin defaults fill any values that remain unset.

Modern, minimal token map

The active Boombox theme uses the following map. Put it under settings.custom in theme.json. It expects the named palette, spacing, radius, font-weight and ring tokens to exist in that theme; change the references when another theme uses different slugs.

{
	"ring": "0 0 0 3px color-mix(in srgb, var(--wp--preset--color--live) 30%, transparent)",
	"xp-form": {
		"defaultStyles": true,
		"spacer": "var(--wp--preset--spacing--md)",
		"primary-color": "var(--wp--preset--color--live)",
		"error-color": "var(--wp--preset--color--hot)",
		"success-color": "var(--wp--preset--color--up)",
		"label-color": "var(--wp--preset--color--ink)",
		"label-font-weight": "var(--wp--custom--font-weight--semi-bold)",
		"info-color": "var(--wp--preset--color--muted)",
		"validation-txt-color": "var(--wp--preset--color--hot)",
		"input-color": "var(--wp--preset--color--ink)",
		"input-bg-color": "var(--wp--preset--color--surface)",
		"input-brd-color": "var(--wp--preset--color--border)",
		"input-brd-radius": "var(--wp--custom--radius--sm)",
		"input-box-shadow": "none",
		"input-placeholder-color": "var(--wp--preset--color--muted)",
		"input-disabled-color": "var(--wp--preset--color--muted)",
		"input-disabled-bg-color": "var(--wp--preset--color--sunken)",
		"input-disabled-brd-color": "var(--wp--preset--color--border)",
		"input-disabled-box-shadow": "none",
		"input-hover-color": "var(--wp--preset--color--ink)",
		"input-hover-bg-color": "var(--wp--preset--color--surface)",
		"input-hover-brd-color": "var(--wp--preset--color--border-strong)",
		"input-hover-box-shadow": "none",
		"input-focus-color": "var(--wp--preset--color--ink)",
		"input-focus-bg-color": "var(--wp--preset--color--surface)",
		"input-focus-brd-color": "var(--wp--preset--color--live)",
		"input-focus-box-shadow": "var(--wp--custom--ring)",
		"input-error-color": "var(--wp--preset--color--ink)",
		"input-error-bg-color": "var(--wp--preset--color--surface)",
		"input-error-brd-color": "var(--wp--preset--color--hot)",
		"input-error-box-shadow": "none",
		"input-error-focus-color": "var(--wp--preset--color--ink)",
		"input-error-focus-bg-color": "var(--wp--preset--color--surface)",
		"input-error-focus-brd-color": "var(--wp--preset--color--hot)",
		"input-error-focus-box-shadow": "var(--wp--custom--ring)",
		"input-success-color": "var(--wp--preset--color--ink)",
		"input-success-bg-color": "var(--wp--preset--color--surface)",
		"input-success-brd-color": "var(--wp--preset--color--up)",
		"input-success-box-shadow": "none",
		"input-success-focus-color": "var(--wp--preset--color--ink)",
		"input-success-focus-bg-color": "var(--wp--preset--color--surface)",
		"input-success-focus-brd-color": "var(--wp--preset--color--up)",
		"input-success-focus-box-shadow": "var(--wp--custom--ring)",
		"alert-brd-radius": "var(--wp--custom--radius--sm)",
		"alert-success-color": "var(--wp--preset--color--ink)",
		"alert-success-bg-color": "var(--wp--preset--color--surface)",
		"alert-success-brd-color": "var(--wp--preset--color--up)",
		"alert-error-color": "var(--wp--preset--color--ink)",
		"alert-error-bg-color": "var(--wp--preset--color--surface)",
		"alert-error-brd-color": "var(--wp--preset--color--hot)"
	}
}

After a styling change, check these states on a phone-sized and desktop viewport:

  • normal, hover, focus, disabled, error and success inputs;
  • text, placeholders, labels, descriptions and validation messages;
  • checkboxes, radio buttons, file controls, Submit and Reset;
  • light and dark colour schemes used by the theme;
  • keyboard-only use and visible focus on every control; and
  • reduced-motion mode. Do not add non-essential movement when the visitor asks for reduced motion.

Keep normal text contrast at least 4.5:1. Control boundaries and focus indicators should be at least 3:1 against adjacent colours. Do not use colour as the only sign of an error or success.

Retention, uploads and privacy

The default retention value is 0, which keeps submissions until somebody deletes them. Set Settings → Submissions → Keep submissions for to the shortest useful period. Expired entries first move to Trash, then follow the site's normal trash period. A site with trash disabled deletes them immediately.

Keep submissions marked as spam decides whether a refused submission can be reviewed under Spam. Delete uploaded files with the submission controls file cleanup. Both are on by default. Successful delivery records are kept for 30 days by default; change that under Settings → Deliveries. Failed, pending and dismissed delivery history is kept. Backups, sent email and connected providers need their own retention rules.

By default, an uploaded file is web-accessible to anyone who has its direct URL. Keep uploaded files private moves new uploads to the Forms private tree, and the Forms download link requires xpac_manage_form_submissions. It does not move files that already exist. Direct-path protection depends on the web server as described below.

Apache can use the guard file written by Forms. nginx ignores that file. Before collecting sensitive uploads on nginx, ask the host to deny direct requests:

location ~ /wp-content/uploads/xpac-forms-private/ {
	deny all;
	return 404;
}

Submit a test file. Its direct uploads URL must fail in a private browser window, while the Forms download link works for a signed-in user with the submissions capability. Repeat this after a host move or web-server change.

An accepted submission may exist in Forms tables, uploaded files, delivery history, notification mailboxes, backups and every connected provider. Forms does not currently join WordPress's Tools → Export Personal Data or Erase Personal Data workflow. Handle a data request in XPAC → Forms → Submissions, and include mail, providers and backups in the site's process.

Deactivating or deleting plugin files does not purge forms, submissions, notes, delivery state or uploads. Plan and verify a data cleanup before permanent removal.

Move forms between sites

Choose Export as JSON from a form's actions menu, or select several forms and use the bulk export. Choose Import above All Forms on the other site.

An import creates new form IDs. It never updates an existing form. Fields, form settings, notifications and add-on configuration travel; submissions do not. A user without publish_posts imports published or private forms as drafts.

One file may contain at most 100 forms and may be at most 5 MB. The complete file is checked before any form is stored.

Treat a form export as private configuration

Review recipients, redirects, webhooks and add-on actions after import. Fixed webhook headers and other secrets stored on the form are included in its JSON. Import only a file from a trusted source, and rotate a secret if the file reached the wrong person.

Before production

  • Forms requires WordPress 6.5 or newer and PHP 8.0 or newer.
  • Back up the database and uploads before an update. Update Forms and its add-ons together, especially Forms and Stripe.
  • Confirm WordPress cron runs. Check Tools → Scheduled Actions for stuck work.
  • Configure the site's mail transport and From domain. Submit while signed out and check the receiving inbox and spam folder.
  • Choose submission, spam, file and delivery retention settings.
  • Test private uploads on the production web-server type.
  • Test every enabled add-on with its own test destination.
  • Do not launch while Submissions are waiting on a database update is visible.
  • Submit one complete production-host test and confirm Submissions and Deliveries.

If the site is behind a trusted reverse proxy, set define( 'XPAC_TRUST_PROXY', true ); only when the proxy overwrites forwarding headers and visitors cannot reach the origin directly. A false declaration lets a visitor supply an address; a missing declaration can make all visitors share the proxy's flood-control count.

Troubleshooting

ProblemCheck
Editors see the form but visitors see nothingPublish the form itself, then check schedule, capacity and login-only settings.
The form page is blank after a form was restoredA restored form is a draft. Publish it again.
A required or range value is refusedCheck the field's Required, minimum, maximum, length and pattern controls. Server validation follows the saved form.
Dynamic choices do not appearOpen the REST URL, check JSON properties, CORS, permissions, timeout and whether the list is empty.
A file is refusedCheck the field type/size/count, WordPress allowed types, PHP/server size limits and the user's upload permission.
Everyone receives Too many attemptsCheck the flood-control values and trusted reverse-proxy configuration.
The entry exists but email did not arriveCheck Deliveries, Action Scheduler, the site's mail transport, From domain, SPF/DKIM and the recipient's spam folder.
An add-on failedOpen Deliveries, copy the error, check the exact account and destination, then retry before the 30-day snapshot expires. Check the provider before retrying an ambiguous timeout.
Deliveries remain pendingConfirm WP-Cron runs and inspect Tools → Scheduled Actions.
Private file URLs still open on nginxAdd the server deny rule; a random folder name is not access control.
Forms shows a database update noticeStop launch work and give the WordPress database user permission to create, alter and write the xp_forms_* tables.

Developer references

Forms are posts of type xpac-form. Submissions use the plugin's xp_forms_* tables rather than wp_posts. Use public hooks from the generated references instead of depending on internal classes or database details.

On this page