Hooks

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:193
  • assets/packages/forms/form/sidebars/Settings/Panels/Messages/Modal.js:53
  • assets/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 stored contentType.
  • $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:134
  • packages/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 its xp/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 resolved type.
  • $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 with data-validation-events and data-message-position from 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) — status bool, start and end wall-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:542
  • packages/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::method as 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: enable bool, success and error URLs.

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 under metadata.

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) — success bool and errors, a list of field/message pairs.
  • $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:466
  • packages/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

On this page

wp_react_settings_shared_context_initial_valuesxpac-forms-after-settings-modal-contentxpac-forms-field-namexpac-forms-field-output-propsxpac-forms-field-panelsxpac-forms-form-panelsxpac_form_post_{$block['blockName']}_uploadxpac_form_pre_{$block['blockName']}_uploadxpac_form_upload_{$block['blockName']}_attachment_post_statusxpac_form_upload_{$block['blockName']}_insert_wp_attachmentxpac_form_upload_{$block['blockName']}_parent_post_idxpac_forms_action_item_statusxpac_forms_after_form_beginxpac_forms_after_submitxpac_forms_before_form_endxpac_forms_deliveries_retention_daysxpac_forms_disable_default_stylesxpac_forms_editor_inline_js_dataxpac_forms_email_content_typexpac_forms_email_field_valuexpac_forms_email_headersxpac_forms_entries_delete_attachmentsxpac_forms_entries_entry_dataxpac_forms_entries_entry_lifetimexpac_forms_entries_extra_answer_keysxpac_forms_entries_field_valuexpac_forms_entries_table_additional_columnsxpac_forms_entries_table_additional_sortable_columnsxpac_forms_entries_trash_lifetimexpac_forms_entries_{$type}_field_valuexpac_forms_entry_write_failedxpac_forms_form_accessiblexpac_forms_form_block_attributesxpac_forms_form_requires_loginxpac_forms_form_schedulexpac_forms_form_submission_limitxpac_forms_idempotency_lock_timeoutxpac_forms_idempotency_ttlxpac_forms_initxpac_forms_initialize_submissionxpac_forms_inline_js_dataxpac_forms_integration_appliesxpac_forms_integration_labelxpac_forms_overview_cache_ttlxpac_forms_post_meta_default_valuesxpac_forms_post_meta_schemaxpac_forms_post_render_formxpac_forms_post_script_dependenciesxpac_forms_post_style_dependenciesxpac_forms_pre_render_formxpac_forms_private_upload_directoryxpac_forms_provider_blocks_dataxpac_forms_quarantine_spamxpac_forms_redirect_configxpac_forms_render_form_contentxpac_forms_spam_submissionxpac_forms_structure_responsexpac_forms_submission_infoxpac_forms_submission_lock_timeoutxpac_forms_submission_messagesxpac_forms_submission_validationxpac_forms_submit_callbacksxpac_forms_submit_responsexpac_forms_throttle_limitxpac_forms_throttle_lock_timeoutxpac_forms_throttle_windowxpac_forms_throttledxpac_forms_upload_errorsxpac_forms_upload_handlerxpac_forms_uploader_blocksxpac_forms_uploads_privatexpac_forms_use_assets_in_post_type_with_field_supportxpac_forms_validation_block_rulesxpac_forms_validation_choices_allowed_valuesxpac_forms_validation_{$name}_rule_messagexpac_forms_{$action}_callbacksxpac_forms_{$name}_field_type