Forms
77 hooks fired by Forms: 64 filters and 13 actions across 82 call sites.
77 hooks fired by Forms: 64 filters and 13 actions across 82 call sites. 80 of the 82 call sites are described by a docblock, at the call or on the constant that names the hook; the rest are listed with their signature and call sites only. Paths are relative to the plugin directory.
wp_react_settings_shared_context_initial_values
Filter · 1 argument · 1 call site
Filters the shared context given to controls on the Forms settings tab.
This is the same filter the standalone settings page fires. Add-ons put connection state and other shared values here; firing it on both mounts keeps their controls populated whichever settings screen is open.
applyFilters( 'wp_react_settings_shared_context_initial_values', {} )initialValues(Object) — Shared context values. Default empty object.
Fired from:
assets/packages/forms/admin/screens/Settings.js:195
xpac-forms-after-settings-modal-content
Filter · 3 arguments · 3 call sites
Content appended inside a settings panel's item modal.
applyFilters( 'xpac-forms-after-settings-modal-content', [], { value: options, onChange: onUpdate, }, 'xpac-forms-email-notification' )
applyFilters( 'xpac-forms-after-settings-modal-content', [], { value: options, onChange: onUpdate, }, 'xpac-forms-messages' )
applyFilters( 'xpac-forms-after-settings-modal-content', [], { value: options, onChange: onUpdate, }, 'xpac-forms-redirect' )Fired from:
assets/packages/forms/form/sidebars/Settings/Panels/EmailNotification/Modal.js:193assets/packages/forms/form/sidebars/Settings/Panels/Messages/Modal.js:53assets/packages/forms/form/sidebars/Settings/Panels/Redirect/Modal.js:54
xpac-forms-field-name
Filter · 3 arguments · 1 call site
The name generated for a newly inserted field block.
applyFilters( 'xpac-forms-field-name', randomName, blockAttributes, { postId, isNewPost, prefix, } )Fired from:
assets/packages/forms/blocks/shared/HOCs/WithRandomName.js:18
xpac-forms-field-output-props
Filter · 4 arguments · 1 call site
The props a field block renders its control with.
applyFilters( 'xpac-forms-field-output-props', { blockProps: {}, fieldProps: {}, }, blockName, attributes, isEditor )Fired from:
assets/packages/forms/hooks/useFieldOutputProps.js:6
xpac-forms-field-panels
Filter · 2 arguments · 1 call site
Panels added to a field block's inspector.
applyFilters( 'xpac-forms-field-panels', [], blockName )Fired from:
assets/packages/forms/hooks/useFieldPanels.js:7
xpac-forms-form-panels
Filter · 1 argument · 1 call site
Panels added to the form editor's Settings sidebar.
applyFilters( 'xpac-forms-form-panels', initialPanels )Fired from:
assets/packages/forms/hooks/useFormPanels.js:61
xpac_form_post_{$block['blockName']}_upload
Action · Dynamic name · 4 arguments · 1 call site
Fires once every file in one field has been dealt with.
The variable part of the name is the field's block name, and this
closes the window the matching xpac_form_pre_{$blockName}_upload
opened — the upload_mimes filter this class adds has already been
removed by the time it fires, so a listener that added filters of its
own on the opening action removes them here.
It fires whatever happened, including when every file was refused, and
it fires before the refusals in $results are copied into the errors
that stop the submission. So this is the last point at which a listener
can act on a file it wanted, and it cannot change the outcome: the
return value of an action is discarded.
do_action( "xpac_form_post_{$block['blockName']}_upload", $block, $results, $maxSize, $limit )$block(array) — Parsed block for the field that was uploaded for.$results(array) — One entry per attempted file, each of them ['upload' => array, 'error' => string|null, 'data' => ['id' => int, 'file' => array]|null].$maxSize(int) — Per-file size cap in bytes. 0 for no cap.$limit(int) — Maximum number of files. 0 for no limit.
Fired from:
packages/Forms/core/base/Uploader.php:596
xpac_form_pre_{$block['blockName']}_upload
Action · Dynamic name · 4 arguments · 1 call site
Fires before one field's files are handed to wp_handle_upload().
The variable part of the name is the block name of the field being
uploaded for — xp/form-field-file for the shipped File field, and an
add-on's own block name for a field it registered — so a listener sees
only the field type it asked about.
This opens a per-field window that closes at the matching
xpac_form_post_{$blockName}_upload, which is where a listener that
redirects the upload directory or switches the attachment record off
belongs. CommunityPlatform's avatar field does exactly that: it adds an
upload_dir filter and a ..._insert_wp_attachment filter here and
removes both again on the closing action
(packages/CommunityPlatform/Modules/Members/ProfileFields/Blocks/AvatarUpload.php:135).
do_action( "xpac_form_pre_{$block['blockName']}_upload", $block, $upload, $maxSize, $limit )$block(array) — Parsed block for the field being uploaded for.$upload(array) — Files about to be stored, already cut to $limit.$maxSize(int) — Per-file size cap in bytes. 0 for no cap.$limit(int) — Maximum number of files. 0 for no limit.
Fired from:
packages/Forms/core/base/Uploader.php:452
xpac_form_upload_{$block['blockName']}_attachment_post_status
Filter · Dynamic name · 2 arguments · 1 call site
Filters the status a submitted file is stored with.
The default is "private", which keeps the upload out of the anonymous media listing. A site that wants submitted files back in the media library for every role can return "inherit" here.
apply_filters( "xpac_form_upload_{$block['blockName']}_attachment_post_status", 'private', $block )$postStatus(string) — Attachment post status.$block(array) — Parsed block the files were posted for.
Fired from:
packages/Forms/core/base/Uploader.php:493
xpac_form_upload_{$block['blockName']}_insert_wp_attachment
Filter · Dynamic name · 5 arguments · 1 call site
Filters whether stored files get an attachment record of their own.
The variable part of the name is the field's block name, as above.
Returning false skips wp_insert_attachment() for every file in this
field: the bytes are still written by wp_handle_upload(), but there
is no post to point at, so the entry records no id for the field and
the cleanup that runs when a submission is refused — which deletes
attachments — cannot reach the file either.
That is only the right answer for a listener that takes ownership of the file itself. CommunityPlatform's avatar field returns false here because it resizes the upload into its own set of files on the closing action and stores those instead.
apply_filters( "xpac_form_upload_{$block['blockName']}_insert_wp_attachment", true, $block, $upload, $maxSize, $limit )$insertWpAttachment(bool) — Whether to create attachments. Default true.$block(array) — Parsed block for the field being uploaded for.$upload(array) — Files about to be stored.$maxSize(int) — Per-file size cap in bytes. 0 for no cap.$limit(int) — Maximum number of files. 0 for no limit.
Fired from:
packages/Forms/core/base/Uploader.php:474
xpac_form_upload_{$block['blockName']}_parent_post_id
Filter · Dynamic name · 1 argument · 1 call site
Filters the post a submitted file is attached to.
The variable part of the name is the field's block name. The default is the form itself, which is what makes an upload findable from the entry it arrived with.
The parent does not decide who may read the file. Attachments here are
stored with the "private" status precisely so that the published form
being their parent does not make them readable — see
insertAttachment() above — so reparenting is a bookkeeping choice,
not an access one. Return 0 to leave the attachment unattached.
apply_filters( "xpac_form_upload_{$block['blockName']}_parent_post_id", $this->getFormId() )$parentPostId(int) — Post id to attach to. Default: the form's id.
Fired from:
packages/Forms/core/base/Uploader.php:514
xpac_forms_action_item_status
Filter · 4 arguments · 1 call site
Filters whether one configured item runs for this submission.
Asked once per item as a form is submitted, for every panel that stores a list of them: the notification emails, each integration's actions, and the form's own redirect and message items. Returning false drops that item before it is used, and a dropped item is not counted as a failure anywhere — an integration reads it as something somebody switched off on purpose, not as a configuration that produced nothing.
The default is the item's own stored status, or true
when the item carries none, which is the case for anything
written by a REST client, an import or a migration rather
than by the editor.
$module says which panel is asking, so a callback can
target one of them: "xpac-forms-email",
"xpac-forms-redirect", "xpac-forms-messages", or an
add-on's own module id for its integration actions.
Conditional Logic is the plugin's own listener here — it is how a per-item condition decides whether that item applies to a given submission.
apply_filters( 'xpac_forms_action_item_status', $item['status'] ?? true, $item, $externalSubmission, $module )$status(bool) — Whether the item runs.$item(array) — The stored item.$submission(Submission) — Callback-safe submission without write-only answers.$module(string) — Module id of the panel asking.
Fired from:
packages/Forms/core/base/Utils.php:93
xpac_forms_after_form_begin
Action · 3 arguments · 1 call site
Fires just inside the opening <form> tag.
Output is captured and inserted ahead of the form's own fields, so this is how a hidden input reaches a submission: Forms' Honeypot prints its decoy field here and UserAuth its hidden action fields. Anything printed is inside the form and is therefore submitted with it.
do_action( 'xpac_forms_after_form_begin', $post, $block, $settings )$post(WP_Post) — The form being rendered.$block(WP_Block) — The form block instance on the page.$settings(FormSettings) — The form's stored settings.
Fired from:
packages/Forms/core/base/Blocks.php:1041
xpac_forms_after_submit
Action · 1 argument · 1 call site
Fires when a submission has been accepted.
The point past which a first submission can no longer be refused: throttling, validation, uploads and pre-submit callbacks passed. A completed-mutation recovery enters directly here because those earlier decisions and its irreversible mutation already passed.
Forms' entry Logger stores the row at priority 10 and Deliveries\Dispatcher records queued integrations at priority 20.
do_action( 'xpac_forms_after_submit', $this )$submission(Submission) — The accepted submission.
Fired from:
packages/Forms/core/base/Submission.php:2178
xpac_forms_before_form_end
Action · 3 arguments · 1 call site
Fires just before the closing </form> tag.
Output is captured and appended after the form's own fields and inside the form tag, so anything printed here is submitted with it. UserAuth's account verification prints its feedback message here when the form's message position is "bottom", and on xpac_forms_after_form_begin when it is "top".
do_action( 'xpac_forms_before_form_end', $post, $block, $settings )$post(WP_Post) — The form being rendered.$block(WP_Block) — The form block instance on the page.$settings(FormSettings) — The form's stored settings.
Fired from:
packages/Forms/core/base/Blocks.php:1084
xpac_forms_deliveries_retention_days
Filter · 1 argument · 1 call site
Filters how many days a successful delivery record is kept for.
Applies to the sent records only — a failed or still-pending delivery
is never pruned, whatever this returns. Zero, or anything below it,
switches successful-history pruning off; the job remains armed for
the fixed retry-payload deadline.
apply_filters( 'xpac_forms_deliveries_retention_days', $days )$days(int) — Days to keep. Default 30, or the site's setting.
Fired from:
packages/Forms/core/deliveries/Retention.php:155
xpac_forms_disable_default_styles
Filter · 1 argument · 1 call site
Filters whether the form block's own stylesheet is dropped entirely.
This is the highest layer of the opt-out and the only one resolvable at
block registration, so true here is final and takes effect everywhere at
once: the style handle is deregistered on the front end and in wp-admin,
and the wp_theme_json_data_user filter this class attaches otherwise is
never added. That filter is what merges the shipped xp-form style
defaults into the site's global styles, so the form's built-in CSS custom
properties go with it and the form editor has no stylesheet left for its
Styles panel to switch on and off.
The Appearance setting feeds this filter at priority 1.
A theme opting out with settings.custom.xp-form.defaultStyles in its
theme.json, or the Styles panel writing the same key into the global
styles user layer, reaches the same front-end result but keeps the handle
registered in wp-admin as an alternate stylesheet.
apply_filters( 'xpac_forms_disable_default_styles', false )$disabled(bool) — Whether to drop the default styles. Default false.
Fired from:
packages/Forms/core/base/GlobalStyles.php:76
xpac_forms_editor_inline_js_data
Filter · 1 argument · 1 call site
Filters the data the form editor reads as window.xpacForms.
Printed before the form settings script on the post edit screen, so
an add-on's editor panel can be handed server-side values. A
non-array return is cast to one. The keys Forms owns —
validationMessages, submissionMessages and
registeredBlocksConfig — are merged in afterwards and cannot be
replaced here.
apply_filters( 'xpac_forms_editor_inline_js_data', [ 'presets' => [] ] )$data(array) — Editor data. Default['presets' => []].
Fired from:
packages/Forms/core/base/PostType.php:393
xpac_forms_email_content_type
Filter · 3 arguments · 1 call site
Filters whether one notification is sent as HTML or as plain text.
"html" sends the message as an HTML body: the submitted values are
escaped as they are substituted, {{ALL_FIELDS}} becomes a table
rather than a run of lines, and the assembled body is passed
through wp_kses_post() so an owner's own markup survives and a
script does not. Any other value sends the message unchanged, as
text. The stored contentType is the default, and an item saved
before the setting existed carries none, so it reads "text" —
which is what every notification was.
apply_filters( 'xpac_forms_email_content_type', (string) ($item['contentType'] ?? 'text'), $item, $externalSubmission )$type(string) — "text" or "html", from the item's storedcontentType.$item(array) — The notification's stored settings.$submission(Submission) — Submission being mailed.
Fired from:
packages/Forms/core/base/Email.php:381
xpac_forms_email_field_value
Filter · 4 arguments · 1 call site
Filters a submitted field's value as the email prints it.
The value that replaces this field's {{name}}
variable in the notification's subject, message and
address lines. Reached for every field type the switch
above does not handle itself, so checklist, dropdown,
radio and file fields never arrive here — those are
turned into their chosen labels or their attachment
URLs first — and neither do the two types the entry
refuses to keep, confirmation and password, which
are left out of the notification entirely: every
variable of theirs resolves to nothing, and they are
absent from {{ALL_FIELDS}}. Storing a password and
mailing it are the same disclosure, so Logger's policy
is the one applied here.
A field type registered by an add-on is exactly what lands in this branch, which is what the hook is for: a date stored as an ISO string, or a value stored as an id, can be rendered here as the reader expects to see it. The result is rendered as text before it is substituted: a scalar as itself, an array as its scalar members joined with ", ", and anything else — an object, null — as nothing at all.
apply_filters( 'xpac_forms_email_field_value', $data_value, $type, $key, $externalSubmission )$data_value(mixed) — The submitted value.$type(string) — Field type, as Blocks::getFieldTypeByBlock() reports it.$key(string) — Field name, the same one the {{variable}} uses.$submission(Submission) — Submission being mailed.
Fired from:
packages/Forms/core/base/Email.php:319
xpac_forms_email_headers
Filter · 3 arguments · 1 call site
Filters the headers one notification is sent with.
The list handed to wp_mail(), each entry already terminated with
CRLF: From, MIME-Version and Content-Type always, then Reply-To,
Cc and Bcc for each of those the form has configured. Adding a
header an install needs on every notification — List-Unsubscribe,
an X- header its mail service reads — is what this is for. The
return replaces the list rather than adding to it, and is cast
with (array), so returning null sends the notification with no
headers of its own at all.
apply_filters( 'xpac_forms_email_headers', $headers, $item, $externalSubmission )$headers(string[]) — Header lines, each ending in CRLF.$item(array) — The notification's stored settings.$submission(Submission) — Submission being mailed.
Fired from:
packages/Forms/core/base/Email.php:474
xpac_forms_entries_delete_attachments
Filter · 3 arguments · 1 call site
Whether the files a deleted submission carried are deleted with it.
On since 2026-08-21 — DECISIONS.md 18. It shipped off because an uploaded file can be adopted by something outside Forms and nothing on the attachment records that; what changed is not that risk but the four guards below, which now handle the one real case of it rather than leaving every file on disk for ever to avoid it. A site owner deleting a submission for privacy reasons had not deleted the attachment, which is the failure that outweighs the other.
Return false on a site that would rather keep them.
apply_filters( 'xpac_forms_entries_delete_attachments', true, $form_id, $entry_ids )$delete(bool) — Whether to delete the attachments. Default true.$form_id(int) — The form post ID.$entry_ids(int[]) — Entries about to be deleted.
Fired from:
packages/Forms/core/entries/Cleaner.php:660
xpac_forms_entries_entry_data
Filter · 2 arguments · 2 call sites
Filters the answers about to be stored as a submission's entry meta.
Runs on xpac_forms_after_submit at priority 10, before the entry
row exists — and therefore before Deliveries\Dispatcher, which is
priority 20 on the same action, has scheduled a single integration.
A key added here is stored with the submission; a key removed here
is never stored at all.
Returning an empty array suppresses a non-idempotent internal entry. A public request still appends its private request marker, safe retry payload and delivery manifest after this filter. That is required for password-only and mutation-only forms: there may be no displayable answer, but the irreversible operation and dispatch still need one durable exact-request boundary.
The array has already been through the answer allowlist, so this is
where a value the server computes belongs; a key that arrives in the
request body needs xpac_forms_entries_extra_answer_keys instead.
Nothing narrows what comes back, including a key carrying
DeliveryState::RESERVED_PREFIX — which the detail panel and the
export then hide.
Every value is stored as text: an array is joined with commas and anything else is cast to string. This filter changes displayable entry answers only; Logger builds the credential-free delivery payload independently after the filter.
Fires a second time for a submission a spam detector refused, from
createSpamEntry() below: that path runs on
xpac_forms_spam_submission, the array additionally carries the
verdict under Logger::META_SPAM, and no delivery is ever
dispatched for it.
This filter is documented in packages/Forms/core/entries/Logger.php
apply_filters( 'xpac_forms_entries_entry_data', self::answersFor($submission), $submission->forExternalCallback() )
apply_filters( 'xpac_forms_entries_entry_data', $answers, $submission->forExternalCallback() )$data(array<string, mixed>) — Answers, keyed by field name.$submission(Submission) — Submission being stored.
Fired from:
packages/Forms/core/entries/Logger.php:134packages/Forms/core/entries/Logger.php:245
xpac_forms_entries_entry_lifetime
Filter · 2 arguments · 1 call site
Filters how many days an untouched submission is kept for.
Zero, or anything below it, switches retention off for that form — nothing is retired, nothing is deleted and nothing is swept. The default handed in is the site's own setting, so a filter that returns its argument unchanged is a no-op.
apply_filters( 'xpac_forms_entries_entry_lifetime', self::retentionDays(), $form_id )$days(int) — Days to keep. Default 0, or the site's setting.$form_id(int) — The form post ID.
Fired from:
packages/Forms/core/entries/Cleaner.php:219
xpac_forms_entries_extra_answer_keys
Filter · 2 arguments · 1 call site
Filters the POST keys a submission may store that are not field blocks.
An add-on can put a key on the wire that no block declares — Stripe's
Payment Element registers as unchangeable and its browser code posts
stripe alongside the answers, which is how the payment record reaches
the Submissions screen. Such a key has to be named here or it is
dropped with everything else the visitor invented.
Prefer xpac_forms_entries_entry_data for a value the server computes:
that filter runs after the answers are assembled and is not restricted.
This one exists only for data that arrives in the request body, which
is why the reserved prefix still applies to whatever it returns.
apply_filters( 'xpac_forms_entries_extra_answer_keys', [], $submission->forExternalCallback() )$keys(string[]) — Extra POST keys to store. Default none.$submission(Submission) — Submission being stored.
Fired from:
packages/Forms/core/entries/Logger.php:504
xpac_forms_entries_field_value
Filter · 5 arguments · 1 call site
Filters one submitted answer before it is stored.
Runs while the entry meta is assembled, so before the entry row exists and before any integration has been scheduled.
Fires once per answer whose field type is not handled
above, which is every type but four: checklist and
dropdown are joined into a comma-separated string
instead, and confirmation and password are dropped
from the entry and never reach this.
Only the stored copy changes. The value is written as text
— an array flattened to its values and joined with commas,
anything else cast to string — and an integration is
handed the Submission, so it sends what the visitor
posted whatever this returns.
apply_filters( 'xpac_forms_entries_field_value', $meta_value, $type, $meta_key, $blocks, $submission->forExternalCallback() )$meta_value(mixed) — Submitted value for this field.$type(string) — Field type: the block name without itsxp/form-field-prefix, e.g. "text", "email", "file".$meta_key(string) — Field name, which is the meta key it is stored under.$blocks(array<string, array>) — The submission's field blocks, keyed by field name, each carrying its resolvedtype.$submission(Submission) — Submission being stored.
Fired from:
packages/Forms/core/entries/Logger.php:340
xpac_forms_entries_table_additional_columns
Filter · 2 arguments · 1 call site
Filters the columns a form's submissions are listed under.
The array handed in is field name => column label for at most the
first three of the form's own fields — the cap that keeps a
twenty-field form from producing a table nobody can read. A key has to
be a meta key the entry really stores, which for an add-on's own column
means the key it wrote through xpac_forms_entries_entry_data.
What comes back is both the set of columns the screen shows by default
and the basis of all_columns, the every-field list the CSV export
writes: an added column lands after the form's own fields, and one of
the three taken away is left out of the export as well.
Asked once per form by forForm(), which the submissions screen's
context, its rows, a single submission, the overview's one-line
summaries and both exports all go through.
apply_filters( 'xpac_forms_entries_table_additional_columns', $columns, $form )$columns(array<string, string>) — Column key => label.$form(WP_Post) — The form post.
Fired from:
packages/Forms/core/entries/Admin/FormFields.php:127
xpac_forms_entries_table_additional_sortable_columns
Filter · 2 arguments · 1 call site
Filters which submission columns are declared sortable.
Only the keys are read, so the value against each one is free; the
default passes [$key, 'asc'], the shape the list table this screen
replaced wanted.
Nothing consumes the result today: the DataViews screen reports every
field as sortable and validates a requested sort key against the
entries table's own columns and this form's columns instead. The name,
its arguments and its order are kept because add-ons registered on it
before that screen existed — GoogleReCaptcha still does.
apply_filters( 'xpac_forms_entries_table_additional_sortable_columns', $sortable, $form )$sortable(array<string, array>) — Column key => [key, direction].$form(WP_Post) — The form post.
Fired from:
packages/Forms/core/entries/Admin/FormFields.php:149
xpac_forms_entries_trash_lifetime
Filter · 1 argument · 1 call site
Filters how many days a trashed submission is kept before deletion.
Zero removes the trash step, so a submission past the retention window is deleted outright — which is what the job did before it had one.
apply_filters( 'xpac_forms_entries_trash_lifetime', $days )$days(int) — Days a trashed submission is kept. Default EMPTY_TRASH_DAYS.
Fired from:
packages/Forms/core/entries/Cleaner.php:243
xpac_forms_entries_{$type}_field_value
Filter · Dynamic name · 3 arguments · 1 call site
Filters one stored answer as it is rendered for the admin.
The variable part is the field's type, which is its block name
without the xp/form-field- prefix: "text", "email", "textarea",
"number", "phone", "url", "date", "dropdown", "radio",
"checklist", "confirmation", "consent", "file", "hidden" or
"dynamic-select" for the shipped fields, plus any an add-on
registers — UserAuth adds "password" — or whatever
xpac_forms_{$block_name}_field_type answered for a block that is
not a field block. Nothing fires for an answer whose block has
since been removed from the form, because no type resolves for it.
A file answer arrives already rendered as links to its
attachments; every other type arrives as the stored answer escaped
as text, ready to be written into the page, so a fragment built
around it carries what the visitor typed and not markup they
invented. What comes back is passed through wp_kses_post(), so
markup survives but a form, an input or a select does not.
Reached by the CSV export as well, which asks with the "archive" context and flattens the result to one line — and which skips rendering entirely for a type nothing is listening on, so adding a listener here also changes what the export writes for that type.
apply_filters( "xpac_forms_entries_{$type}_field_value", $value, $blocks[$key]['attrs'], $context )$value(string) — The escaped answer, or the rendered links for a file field.$attrs(array) — The field block's attributes, including its label.$context(string) — Screen asking: "archive" for the table and the exports, "single" for one submission.
Fired from:
packages/Forms/core/entries/Admin/FormFields.php:268
xpac_forms_entry_write_failed
Action · 3 arguments · 1 call site
Fires when a submission was accepted and could not be stored.
The visitor has already been told the submission succeeded by the time
this runs, and on the entry path nothing else in the product knows
it did not — Deliveries\Dispatcher reads the same 0 that means "there
was nothing to store" and skips every integration without comment.
do_action( 'xpac_forms_entry_write_failed', $reason, $form_id, $error )$reason(string) — 'entry', 'meta', 'commit' or 'cleanup'.$form_id(int) — Form the submission was made against.$error(string) — Database error, or '' when none was reported.
Fired from:
packages/Forms/core/entries/Database.php:942
xpac_forms_form_accessible
Filter · 3 arguments · 1 call site
Filters whether the current request may use a form.
The escape hatch for an install whose forms are deliberately not published — one embedded while a site is being set up, or held in a status a workflow plugin owns. Returning true reopens such a form; returning false closes one that is otherwise live.
The context tells the paths apart, so a callback can reopen the rendering of a form without also reopening its submissions: "render", "submit", "structure" and "preview", each of them a CONTEXT_* constant on this class. Preview additionally requires a valid preview nonce and the right to edit the form, and this filter cannot grant either.
Add-ons that resolve a form id on their own pass their own context
string, so the set is open rather than fixed at four. FormsAutoSubmit
asks under "autosubmit" before acting on a signed link
(packages/FormsAutoSubmit/Addon.php:297), after its own post_status
test — so returning false there closes the route, and returning true
cannot open an unpublished form to it. A callback that means "close
everything" should therefore not switch on the four names above.
apply_filters( 'xpac_forms_form_accessible', $accessible, $form, $context )$accessible(bool) — Whether the form may be used. Default: published, or readable by this user.$form(WP_Post) — The form post.$context(string) — Path asking: "render", "submit", "structure", "preview", or an add-on's own name.
Fired from:
packages/Forms/core/base/PostType.php:762
xpac_forms_form_block_attributes
Filter · 4 arguments · 1 call site
Filters the HTML attributes printed on a form's <form> tag.
Runs before the attributes are handed to
get_block_wrapper_attributes(), and only for a form the
request may actually see. A non-array return is treated as
empty. Forms then sets action and data-id itself, so
overriding those here has no effect, and prepends its own
xp-block-form to whatever class is returned rather than
replacing it. data-validation-events is JSON-encoded after
this filter and so must be left as an array. Every other
value reaches get_block_wrapper_attributes(), which drops
an attribute whose value is boolean true without a word —
pass '1'.
apply_filters( 'xpac_forms_form_block_attributes', [ 'data-validation-events' => $settings->get( 'validation.events', [] ), 'data-message-position' => $settings->get('messages.position', 'bottom'), ], $post, $block, $settings )$attributes(array) — Attribute name/value pairs, starting withdata-validation-eventsanddata-message-positionfrom the form's settings.$post(WP_Post) — The form being rendered.$block(WP_Block) — The form block instance on the page.$settings(FormSettings) — The form's stored settings.
Fired from:
packages/Forms/core/base/Blocks.php:972
xpac_forms_form_requires_login
Filter · 2 arguments · 1 call site
Filters whether a form may only be submitted by a signed-in visitor.
The one restriction that depends on who is asking rather than on the form, so a callback that answers true for some visitors and not others belongs here rather than in the two above.
apply_filters( 'xpac_forms_form_requires_login', ! empty($login['status']), $form )$required(bool) — Whether signing in is required. Default false.$form(WP_Post) — The form being checked.
Fired from:
packages/Forms/core/base/PostType.php:876
xpac_forms_form_schedule
Filter · 2 arguments · 1 call site
Filters the window during which a form takes submissions.
status false means the form has no schedule and is open, which is
what a form that has never been given one reads. start and end are
wall-clock times in the site's timezone, "Y-m-d\TH:i" as the editor
writes them, and either may be empty to leave that end open. Anything
that is not a time is ignored rather than treated as now, so a
malformed setting cannot close a form by accident.
apply_filters( 'xpac_forms_form_schedule', [ 'status' => ! empty($schedule['status']), 'start' => (string) ($schedule['start'] ?? ''), 'end' => (string) ($schedule['end'] ?? ''), ], $form )$window(array) —statusbool,startandendwall-clock strings.$form(WP_Post) — The form being checked.
Fired from:
packages/Forms/core/base/PostType.php:839
xpac_forms_form_submission_limit
Filter · 2 arguments · 1 call site
Filters how many submissions a form accepts in total.
Zero, which is what a form with no limit reads, means no limit and costs no query or advisory lock. Any positive number is both the limit and the bound on the query that counts against it. It also serializes the final availability check and entry write for this form, so two requests cannot both take the last place.
apply_filters( 'xpac_forms_form_submission_limit', empty($limit['status']) ? 0 : (int) ($limit['value'] ?? 0), $form )$maximum(int) — Submissions the form accepts, 0 for no limit.$form(WP_Post) — The form being checked.
Fired from:
packages/Forms/core/base/PostType.php:918
xpac_forms_idempotency_lock_timeout
Filter · 2 arguments · 1 call site
Filters how long a duplicate form-instance request waits for its first request.
apply_filters( 'xpac_forms_idempotency_lock_timeout', 3, $formId )$seconds(int) — Default three seconds, clamped to 0–5 seconds.$formId(int) — Current form id.
Fired from:
packages/Forms/core/base/Rest.php:727
xpac_forms_idempotency_ttl
Filter · 2 arguments · 2 call sites
Filters how long an accepted form-instance digest prevents a duplicate.
apply_filters( 'xpac_forms_idempotency_ttl', DAY_IN_SECONDS, $formId )$seconds(int) — Default one day, clamped to one minute–seven days.$formId(int) — Current form id.
Fired from:
packages/Forms/core/base/MutationGuard.php:542packages/Forms/core/base/Rest.php:703
xpac_forms_init
Action · 0 arguments · 1 call site
Fires when Forms is ready to be extended.
Runs on init at priority 200, late enough that every add-on has
been loaded and that anything registered on init itself is in
place. Forms' own components and every add-on subscribe here
rather than to init directly, which is why registering a field
type, a delivery action or a REST route needs no ordering against
the plugin's own bootstrap.
Some of the plugin's registrars only accept a call from inside it:
PostType::enablePostTypeFieldBlockSupport() reports
_doing_it_wrong() when it is reached at any other time.
do_action( 'xpac_forms_init' )Fired from:
packages/Forms/Bootstrap.php:122
xpac_forms_initialize_submission
Action · 1 argument · 1 call site
Fires once a submission has been built and before it is processed.
The last point at which a submission is still writable: setData() and
setRules() both refuse once this action has returned, because
did_init is set on the next line. Conditional Logic uses it to strip
the answers of fields the visitor never saw. The form post, the
request data, the parsed block tree and the validation rules are all
resolved by now.
do_action( 'xpac_forms_initialize_submission', $this )$submission(Submission) — The submission being initialised.
Fired from:
packages/Forms/core/base/Submission.php:362
xpac_forms_inline_js_data
Filter · 1 argument · 1 call site
Filters the data the form front end reads as window.xpacForms.
Printed once per page, before the form block's view script, the
first time a form is rendered. Add-ons put the values their
front-end code needs here — Turnstile and reCAPTCHA their site
keys, Stripe its publishable key. A non-array return is cast to
one. The object is deep-frozen in the browser, and the keys Forms
owns — nonce, healthCheckUrl, validationMessages and
submissionMessages — are merged in afterwards and cannot be
replaced here.
apply_filters( 'xpac_forms_inline_js_data', [] )$data(array) — Front-end data keyed by name. Default empty array.
Fired from:
packages/Forms/core/base/Blocks.php:315
xpac_forms_integration_applies
Filter · 3 arguments · 1 call site
Filter whether an integration is dispatched for this submission.
Fires only for an integration that declared a settings key. Return true to dispatch an integration this would otherwise skip.
apply_filters( 'xpac_forms_integration_applies', [] !== $items, $slug, $submission )$applies(bool) — Whether the integration has actions configured.$slug(string) — Integration slug.$submission(Submission) — Submission being dispatched.
Fired from:
packages/Forms/core/deliveries/Applicability.php:211
xpac_forms_integration_label
Filter · 2 arguments · 1 call site
Filters the name an integration is shown under.
The default is derived from the slug, which is the delivery callback's
Class::method verbatim: XPACGroup\Plugin\Airtable\Addon::process
gives "Airtable", the namespace segment before the class. An
integration whose class does not sit under a package-named namespace,
or one whose product is spelled differently from its package, renames
itself here.
Asked wherever a delivery is shown, and only there — no decision in the pipeline reads it, so returning something else cannot change what is sent or retried. It reaches the Deliveries table's Integration column and the dropdown that filters it, a submission's own deliveries panel, the parked-integration list, and the notice naming an integration the circuit breaker has stopped calling. It is also part of what that table's search matches and what its CSV export writes, so a label is worth keeping stable once anyone has seen it.
apply_filters( 'xpac_forms_integration_label', $name, $slug )$name(string) — Default label, derived from the slug.$slug(string) — Integration slug,Class::methodas Dispatcher::slugFor() built it.
Fired from:
packages/Forms/core/deliveries/Health.php:146
xpac_forms_overview_cache_ttl
Filter · 2 arguments · 1 call site
Filters how long, in seconds, the overview response is held.
The screen asks six aggregate questions of the entries table, and two
of them cannot be indexed usefully: the per-day series groups on
DATE(created) while reading status, and the recent list filters on
status NOT IN (…). Both read every row whatever keys exist, so a
cached response is the only thing that closes them.
Kept to a minute rather than longer because the payload carries relative dates ("10 minutes ago") that go stale as it sits, and because an owner who has just taken a submission expects to see it. Return 0 to bypass the cache entirely.
apply_filters( 'xpac_forms_overview_cache_ttl', MINUTE_IN_SECONDS, $days )$ttl(int) — Seconds to hold the response. Default 60.$days(int) — Window the response describes, 0 for all time.
Fired from:
packages/Forms/core/entries/Admin/Rest.php:675
xpac_forms_post_meta_default_values
Filter · 1 argument · 1 call site
Filters the settings blob a form starts life with.
One entry per settings panel, keyed by panel name. Add-ons register their panel's defaults here so a form that has never been saved still reads a complete settings object. Forms' own "messages", "redirect" and "validation" defaults are merged in afterwards and win on a collision.
apply_filters( 'xpac_forms_post_meta_default_values', [] )$defaults(array) — Panel defaults keyed by panel name. Default empty array.
Fired from:
packages/Forms/core/base/PostType.php:153
xpac_forms_post_meta_schema
Filter · 1 argument · 1 call site
Filters the REST schema of a form's settings blob.
One JSON Schema entry per settings panel, keyed by panel
name. Every key an add-on stores has to be declared: core
defaults additionalProperties to false on each nested
object, and this call only sets it to true at the top level,
so one undeclared key fails validation and the whole
form_settings value comes back as null — blanking every
panel in the editor, not just the offending one.
apply_filters( 'xpac_forms_post_meta_schema', [] )$properties(array) — Panel schemas keyed by panel name. Default empty array.
Fired from:
packages/Forms/core/base/PostType.php:192
xpac_forms_post_render_form
Action · 3 arguments · 1 call site
Fires after a form's markup has been assembled.
The markup is already built and is returned as soon as this returns, so a callback cannot change it — this is the point for work that only makes sense once a form is known to be on the page, which is what Turnstile and reCAPTCHA use it for to enqueue their scripts. Output is not captured, so anything echoed here escapes the form markup.
do_action( 'xpac_forms_post_render_form', $post, $block, $settings )$post(WP_Post) — The form that was rendered.$block(WP_Block) — The form block instance on the page.$settings(FormSettings) — The form's stored settings.
Fired from:
packages/Forms/core/base/Blocks.php:1103
xpac_forms_post_script_dependencies
Filter · 1 argument · 1 call site
Filters the script handles the form editor script depends on.
Appended to the settings script's own dependencies, so an add-on's editor bundle is printed before the script that renders the form sidebar and can register its panels in time.
apply_filters( 'xpac_forms_post_script_dependencies', [] )$handles(string[]) — Registered script handles to add as dependencies. Default empty array.
Fired from:
packages/Forms/core/base/PostType.php:527
xpac_forms_post_style_dependencies
Filter · 1 argument · 1 call site
Filters the stylesheet handles the form editor styles depend on.
Appended to the settings stylesheet's own dependencies, so an add-on that ships editor CSS adds its handle here to have it printed on the form edit screen.
apply_filters( 'xpac_forms_post_style_dependencies', [] )$handles(string[]) — Registered style handles to add as dependencies. Default empty array.
Fired from:
packages/Forms/core/base/PostType.php:484
xpac_forms_pre_render_form
Action · 3 arguments · 1 call site
Fires before a form's fields are rendered.
The <form> attributes are already resolved and the fields
have not been rendered yet, which makes this the place to set
up state the field blocks will read. Nothing is captured, so
anything echoed here escapes the form markup — use
xpac_forms_after_form_begin for output that belongs inside it.
do_action( 'xpac_forms_pre_render_form', $post, $block, $settings )$post(WP_Post) — The form being rendered.$block(WP_Block) — The form block instance on the page.$settings(FormSettings) — The form's stored settings.
Fired from:
packages/Forms/core/base/Blocks.php:1023
xpac_forms_private_upload_directory
Filter · 2 arguments · 1 call site
Filters the absolute directory used for private form uploads.
The default remains below WordPress' uploads directory so existing installs keep their paths. A host can point it outside the document root; the authenticated download route reads the attachment's actual path and does not require the directory to have a public URL.
apply_filters( 'xpac_forms_private_upload_directory', trailingslashit($uploads['basedir']) . self::DIRNAME, $uploads )$path(string) — Default absolute directory.$uploads(array) — Result of wp_upload_dir().
Fired from:
packages/Forms/core/base/Uploads.php:103
xpac_forms_provider_blocks_data
Filter · 1 argument · 1 call site
Filters the values the server supplies for provider fields.
Keyed by provider field name — UserTargeting answers
---user-geo-country--- here. A value may be a callable, resolved
lazily the first time the field is read. Every key added becomes a
reserved name: a submitted key of the same name is dropped from the
request, because the point of a provider field is that the visitor is
not its author.
apply_filters( 'xpac_forms_provider_blocks_data', [] )$data(array) — Provider values, or callables returning them, keyed by field name. Default empty array.
Fired from:
packages/Forms/core/base/Submission.php:305
xpac_forms_quarantine_spam
Filter · 3 arguments · 1 call site
Filters whether a refused submission is stored for review.
Returning false restores the behaviour where a rejection discarded the submission outright, for a site that would rather not keep the content of what its detectors refuse.
apply_filters( 'xpac_forms_quarantine_spam', true, $submission->forExternalCallback(), $verdict )$store(bool) — Whether to write a quarantined entry.$submission(Submission) — Submission that was refused.$verdict(array) — Detector slug and reason.
Fired from:
packages/Forms/core/entries/Logger.php:229
xpac_forms_redirect_config
Filter · 1 argument · 1 call site
Filters where a form sends the visitor after a submission.
Read when the response is built, after the form's own redirect action
items have been resolved: enable is false and the URLs empty unless
a redirect item matched. The submission is not passed, so a callback
that only wants to redirect one form has to attach itself while that
form is being processed rather than at load time — which is what
UserAuth's Login and Registration modules do from their own actions.
apply_filters( 'xpac_forms_redirect_config', $base )$config(array) — Redirect settings:enablebool,successanderrorURLs.
Fired from:
packages/Forms/core/base/Submission.php:732
xpac_forms_render_form_content
Filter · 4 arguments · 1 call site
Filters whether a form's own fields are printed.
Returning false empties the fields while keeping the <form>
element and both injection points, so whatever
xpac_forms_after_form_begin and xpac_forms_before_form_end
printed still renders — which is how UserAuth replaces an
account-verification form's body with a message and leaves a
submittable form behind. The fields have already been rendered
by this point; the filter discards the result rather than
skipping the work.
apply_filters( 'xpac_forms_render_form_content', true, $post, $block, $settings )$render(bool) — Whether to print the form's fields. Default true.$post(WP_Post) — The form being rendered.$block(WP_Block) — The form block instance on the page.$settings(FormSettings) — The form's stored settings.
Fired from:
packages/Forms/core/base/Blocks.php:1061
xpac_forms_spam_submission
Action · 2 arguments · 1 call site
Fires when a spam detector has refused a submission.
The submission is about to be discarded: validation failed, so xpac_forms_after_submit never runs and nothing else in the product hears about it. Forms' own Logger listens here and stores the attempt with status "spam" so it reaches the Spam tab, where Not-spam restores it. A misclassification is otherwise unrecoverable.
do_action( 'xpac_forms_spam_submission', $this->forExternalCallback(), $this->spam_verdict )$submission(Submission) — Submission that was refused.$verdict(array) — Detector slug, reason and whether it was a verdict or a failure.
Fired from:
packages/Forms/core/base/Submission.php:1638
xpac_forms_structure_response
Filter · 1 argument · 1 call site
Filters the field schema the public structure route hands out.
A list with one entry per field the form renders, each of them
['blockName' => string, 'fieldType' => string|null, 'metadata' => array], where metadata is that field's stored
attributes without lock and metadata. Fields switched off
through metadata.blockVisibility, and fields whose block
registered no structure provider, are already absent.
The route is public and unauthenticated, so anything added here becomes readable by anybody who can reach a published form.
apply_filters( 'xpac_forms_structure_response', $structure->build() )$structure(array) — Field descriptors, in document order.
Fired from:
packages/Forms/core/base/Rest.php:888
xpac_forms_submission_info
Action · 1 argument · 1 call site
Fires while one submission's info panel is built.
An echo, not a filter: whatever a listener prints is captured by
the output buffer around this call and returned as info_html on
the single-submission REST response, which the detail panel renders
as it stands. Deliberately unfiltered, because listeners add
controls and wp_kses_post() would quietly strip a form, an input
or a select — this is server-side add-on output behind the
submissions capability, the same trust boundary the metabox it
replaced had.
Nothing runs unless a listener is attached: the buffer is only
opened once has_action() says there is one. Read-only as far as
the pipeline goes — it fires long after the entry was stored and
has no bearing on a delivery or a retry.
The argument keeps the shape the old metabox passed, so an existing
listener reads what it always read: the entry row's own columns —
id, created, updated, form_id, source_url, user_agent,
status, delivery_failures — plus metadata, a list of
['meta_key' => …, 'meta_value' => …] with the reserved-prefix
bookkeeping keys left out. The meta map the rest of this class
works from is unset.
do_action( 'xpac_forms_submission_info', $legacy )$entry(array) — Entry row, with its answers undermetadata.
Fired from:
packages/Forms/core/entries/Admin/Rest.php:2192
xpac_forms_submission_lock_timeout
Filter · 2 arguments · 1 call site
Filters how long a constrained submission waits for the same form.
Values are clamped to 0..30 seconds so a callback cannot turn an anonymous request into an unbounded worker. Five seconds is long enough for Forms' own Logger and Dispatcher while keeping overload visible as the retryable 503-shaped error rather than a hung request.
apply_filters( 'xpac_forms_submission_lock_timeout', 5, $this )$seconds(int) — Seconds to wait. Default 5.$submission(Submission) — Submission waiting for its form.
Fired from:
packages/Forms/core/base/Submission.php:2417
xpac_forms_submission_messages
Filter · 1 argument · 1 call site
Filters the fallback messages a submission answers with.
These are the product's own wording, used when a form has no
message of its own for the outcome. The result is cached in a
static for the rest of the request, so this runs once, at the
first message lookup — a callback attached after that point is
never consulted. Add a key to introduce a new message; an add-on's
verification wording lives here rather than in its own code so it
stays translatable and overridable in one place. The last three are
the browser's own outcomes, printed to the page as
window.xpacForms.submissionMessages by Blocks::getInlineJsData().
apply_filters( 'xpac_forms_submission_messages', [ 'validation_error' => __( 'Validation errors occur.', '{XPAC}' ), 'success_fallback' => __( 'Successfully submitted.', '{XPAC}' ), 'error_fallback' => __( 'Something went wrong.', '{XPAC}' ), 'missing_token' => __('Token is missing.', '{XPAC}'), 'verification_failed' => __( 'Anti-spam verification failed, please try again later.', '{XPAC}' ), 'verification_error' => __( 'Could not verify the token.', '{XPAC}' ), 'network_error' => __( 'Your answers were not sent because the site could not be reached. ' . 'Check your connection and try again.', '{XPAC}' ), 'server_error' => __( 'Your answers were not sent because the site ran into a problem. ' . 'Please try again in a few minutes.', '{XPAC}' ), 'timeout_error' => __( 'Your answers were not sent because the request took too long. Please try again.', '{XPAC}' ), 'options_unavailable' => __( 'The choices for this field could not be loaded. Reload the page to try again.', '{XPAC}' ), 'form_closed' => __( 'This form is closed and is not taking answers at the moment.', '{XPAC}' ), 'form_limit_reached' => __( 'This form has had all the answers it can take.', '{XPAC}' ), 'login_required' => __( 'Please log in to fill in this form.', '{XPAC}' ), ] )$messages(array) — Message strings keyed by outcome:validation_error,success_fallback,error_fallback,missing_token,verification_failed,verification_error,network_error,server_error,timeout_error,options_unavailable,form_closed,form_limit_reached,login_required.
Fired from:
packages/Forms/core/base/Submission.php:2663
xpac_forms_submission_validation
Filter · 2 arguments · 1 call site
Filters the outcome of validating a submission.
The seam every spam gate hangs off: Honeypot, Akismet, Cloudflare
Turnstile and reCAPTCHA all refuse a submission by setting success
to false here. Runs after the field rules, so errors already holds
whatever they rejected. Setting success to true clears nothing —
errors is still returned to the visitor and is what the front end
marks the offending fields from — so a callback that means "accept
this" has to empty errors as well.
A refusal that also calls flagAsSpam() is recorded as spam and reaches the Spam tab; a refusal without it is only a validation error.
apply_filters( 'xpac_forms_submission_validation', $validation, $this )$validation(array) —successbool anderrors, a list offield/messagepairs.$submission(Submission) — The submission being validated.
Fired from:
packages/Forms/core/base/Submission.php:2523
xpac_forms_submit_callbacks
Filter · 1 argument · 1 call site
Filters the integration callbacks a submission is delivered to.
Each named callback is added as [ClassName::class, 'method'], is
snapshotted with the accepted entry, and later receives one Submission
in its own Action Scheduler job. Callbacks without a stable name use a
legacy at-most-once inline path and cannot be crash-replayed.
apply_filters( 'xpac_forms_submit_callbacks', [] )$callbacks(array) — Callables, each taking one Submission.
Fired from:
packages/Forms/core/deliveries/Dispatcher.php:388
xpac_forms_submit_response
Filter · 2 arguments · 1 call site
Filters the body the submit route answers with.
The last word on what the visitor's browser is told, and it comes
after the submission has already run: the entry is written, the
notifications are queued and the integrations have been called.
Changing success here changes what the visitor is shown and
nothing that was done.
The array carries success, a validation array of
['success' => bool, 'errors' => array], the message to show,
its messagePosition ("top" or "bottom"), the redirect config
and a data array the front end passes through untouched. A
failure that is not a validation failure adds an error key
holding the WP_Error's code, message and data.
Rest::sendErrorResponse() is the plugin's own use of this, at
priority PHP_INT_MAX - 10, so that something further down the
submission can replace the message the visitor reads.
apply_filters( 'xpac_forms_submit_response', $response, $submission->forExternalCallback() )$response(array) — Response body, as described above.$submission(Submission) — Callback-safe submission without write-only answers.
Fired from:
packages/Forms/core/base/Rest.php:475
xpac_forms_throttle_limit
Filter · 3 arguments · 1 call site
Filters how many submissions one IP may make to one form per window.
Return 0 to disable the limit for that form.
apply_filters( 'xpac_forms_throttle_limit', self::LIMIT, $formId, $submission )$limit(int) — Attempts allowed inside the window.$formId(int) — Form being submitted.$submission(Submission) — Submission being attempted.
Fired from:
packages/Forms/core/base/Throttle.php:65
xpac_forms_throttle_lock_timeout
Filter · 2 arguments · 1 call site
Filters how long the throttle waits to update one sender's counter.
The protected work is two option reads/writes and normally completes in milliseconds. Values are clamped to 0..5 seconds so an anonymous request cannot be held indefinitely; failure is treated as a spent budget and receives the normal 429 response.
apply_filters( 'xpac_forms_throttle_lock_timeout', 1, $submission )$seconds(int) — Seconds to wait. Default 1.$submission(Submission) — Submission being counted.
Fired from:
packages/Forms/core/base/Throttle.php:199
xpac_forms_throttle_window
Filter · 3 arguments · 1 call site
Filters the throttle window, in seconds.
apply_filters( 'xpac_forms_throttle_window', self::WINDOW, $formId, $submission )$window(int) — Window length in seconds.$formId(int) — Form being submitted.$submission(Submission) — Submission being attempted.
Fired from:
packages/Forms/core/base/Throttle.php:74
xpac_forms_throttled
Action · 3 arguments · 1 call site
Fires when a submission is refused for exceeding the attempt limit.
do_action( 'xpac_forms_throttled', $formId, $attempts, $submission )$formId(int) — Form being submitted.$attempts(int) — Attempts already recorded in the window.$submission(Submission) — Submission that was refused.
Fired from:
packages/Forms/core/base/Throttle.php:261
xpac_forms_upload_errors
Filter · 2 arguments · 1 call site
Filters the files the server refused, before they stop a submission.
Return an empty array to keep the old behaviour, where a refused file was dropped and the visitor was told the submission had succeeded.
apply_filters( 'xpac_forms_upload_errors', $this->errors, $submission )$errors(array) — Field name => list of ['message' => string].$submission(Submission) — Submission the files were posted with.
Fired from:
packages/Forms/core/base/Uploader.php:806
xpac_forms_upload_handler
Filter · 1 argument · 1 call site
Filters the class that handles this submission's file uploads.
Asked once per submission, and only when the request carries a form instance id — an id-less submission never uploads. The returned name is used only if it is a subclass of AbstractUploader; anything else leaves the submission without an uploader, so no files data is merged into the request.
apply_filters( 'xpac_forms_upload_handler', Uploader::class )$handler(string) — Fully qualified uploader class name. Default Uploader::class.
Fired from:
packages/Forms/core/base/Submission.php:283
xpac_forms_uploader_blocks
Filter · 1 argument · 1 call site
Filters the fields an upload is allowed to be posted for.
A map of field name to parsed block, holding the form's visible
changeable fields. It is the allowlist this method checks $_FILES
against: a posted part whose name is not a key here is skipped
entirely, and the block found under that key is where the size cap,
the ticked file types and the file count come from.
So removing a key refuses uploads for that field, and adding one accepts uploads for a field the form does not declare — with whatever restrictions the array given for it carries, or none.
Only reached when $_FILES is not empty, so a form with no upload
never asks.
apply_filters( 'xpac_forms_uploader_blocks', $submission->getBlocks() )$blocks(array) — Field name => parsed block.
Fired from:
packages/Forms/core/base/Uploader.php:729
xpac_forms_uploads_private
Filter · 1 argument · 1 call site
Filters whether form uploads are stored privately.
apply_filters( 'xpac_forms_uploads_private', ! empty($stored) && 'no' !== $stored )$private(bool) — Whether new uploads are kept out of the web root.
Fired from:
packages/Forms/core/base/Uploads.php:66
xpac_forms_use_assets_in_post_type_with_field_support
Filter · 2 arguments · 2 call sites
Filters whether the form editor assets load on this screen.
Asked on every admin post screen, once for the editor stylesheet and once for its script, and only after the post type has already been found to support the field blocks — so returning true cannot add a post type that PostType::enablePostTypeFieldBlockSupport() has not registered. Returning false empties the asset's configuration, so nothing is printed on that screen.
This filter is documented in packages/Forms/core/base/PostType.php
apply_filters( 'xpac_forms_use_assets_in_post_type_with_field_support', true, $typenow )$use(bool) — Whether to load the editor assets. Default true.$typenow(string) — Post type of the screen being printed.
Fired from:
packages/Forms/core/base/PostType.php:466packages/Forms/core/base/PostType.php:509
xpac_forms_validation_block_rules
Filter · 1 argument · 1 call site
Filters the validation rules a form block is checked against.
Keyed by full block name — xp/form-field-email, or an add-on's own
block — with a list of rule class names, or of
['rule' => class, 'options' => array] entries, against each. Every
rule must be a subclass of Rules\Rule; anything else is dropped.
A rule named here is registered under its getName(), which is what
puts its message in Validators::getMessages().
This is the only way to add a rule to a block that is already
registered: Blocks::registerFormBlock() is a no-op for a block name
it already knows, so an add-on cannot re-declare one of Forms' own
fields to append to it.
The rules land after the block's own, and rules run in order until one refuses, so a field's Required rule is still what answers an empty value. Nothing here can take a rule away.
Read wherever a block's rules or the message catalogue is asked for rather than once at registration, so a callback attached at any point before a form is submitted or rendered is honoured. Every read walks the whole answer, so a callback that does real work should cache it itself.
apply_filters( 'xpac_forms_validation_block_rules', [] )$rules(array<string, array>) — Rule lists keyed by block name. Default empty array.
Fired from:
packages/Forms/core/validation/Validators.php:168
xpac_forms_validation_choices_allowed_values
Filter · 2 arguments · 1 call site
Filters the values a choice field will accept.
Runs once per choice field per validated submission, for the dropdown, radio, checklist and Dynamic Select blocks, with the values that field's own markup offers. A submitted value that is not in the returned list is refused before the entry is written and before any integration runs.
Returning an empty array switches the rule off for that field, which is how a field with no resolvable options behaves already: Dynamic Select backed by a REST source resolves its options in the browser, so the server has no list to compare against and never refuses one.
The list is compared with strict string equality, so members must be strings. An empty string is never compared — a field that was left blank is Required's business, not this rule's.
apply_filters( 'xpac_forms_validation_choices_allowed_values', $values, $block )$values(array) — Values the field offers, as strings.$block(array) — The parsed block being validated.
Fired from:
packages/Forms/core/validation/rules/Choices.php:175
xpac_forms_validation_{$name}_rule_message
Filter · Dynamic name · 2 arguments · 1 call site
Filters the message a validation rule reports when it refuses a value.
The variable part is the rule's own getName(): "required", "email",
"url", "format", "equality", "exclusion", "choices", "range",
"length", "pattern", "unique", "fileMaxCount", "fileMaxSize" and
"fileMimeType" ship here, and an add-on's rule adds its own — UserAuth
registers "passwordStrength".
"range" and "length" hand in an array of three wordings — both,
min and max — when they are asked statically for the browser's
catalogue, and the one wording that fits the field when a rule is in
hand. Every other rule hands in a string either way.
The message handed in is the rule's default, or the field's own
message option where the form declares one: that override is applied
before this filter, so a callback replaces what the form's author typed
as readily as the default.
Fires while a submission is validated, which is before the entry is stored and before any integration is dispatched. The result is returned to the browser against the field that failed, and only for the first rule that failed on it — later rules on the same field are never asked for a message.
Also fires with $rule null, from a static getMessage() call that
has no field in hand: the consent block's exclusion rule takes
Required::getMessage() as its message while the block registry is
built, so that message passes through this filter under "required"
first and under "exclusion" later.
What a callback returns is held to the same allowlist afterwards, as the default and the form's own wording are, so a callback cannot put something that runs into the page a refusal is rendered on.
apply_filters( "xpac_forms_validation_{$name}_rule_message", $message, $rule )$message(string|array) — Message the rule will report.$rule(Rule|null) — Rule instance, or null when asked statically.
Fired from:
packages/Forms/core/validation/rules/Rule.php:182
xpac_forms_{$action}_callbacks
Filter · Dynamic name · 2 arguments · 1 call site
apply_filters( "xpac_forms_{$action}_callbacks", [], $safeSubmission )Fired from:
packages/Forms/core/base/Submission.php:1821
xpac_forms_{$name}_field_type
Filter · Dynamic name · 1 argument · 1 call site
Filters the field type a block contributes to a form.
The variable part is the full block name, slashes and hyphens
included — xpac_forms_xp/form-field-choice_field_type, for instance
— so an add-on filters the one name it registered. Only reached for
blocks outside the xp/form-field- prefix, whose type is read
straight off the name and cannot be filtered. The type is what the
editor and the entries table use to decide how a value is rendered.
apply_filters( "xpac_forms_{$name}_field_type", 'text' )$type(string) — Field type slug. Default 'text'.
Fired from:
packages/Forms/core/base/Blocks.php:105