Hooks & Filters
All PHP action hooks and filters available in Formcierge for extending plugin behaviour.
Actions
Fires immediately after the Formcierge plugin is activated. Use this to run one-time setup tasks such as creating database tables or scheduling cron events.
add_action( 'formcierge_activated', function () {
// One-time activation tasks
my_addon_create_tables();
} );
Fires after an individual entry field value has been updated via the admin entry editor. Use to sync the updated value to an external system.
add_action( 'formcierge_after_entry_data_update', function ( $entry_id, $field_id, $value ) {
my_crm_update_field( $entry_id, $field_id, $value );
}, 10, 3 );
Fires after an entry has been permanently deleted from the database. Use to clean up any related records your addon may have stored.
add_action( 'formcierge_after_entry_delete', function ( $entry_id ) {
global $wpdb;
$wpdb->delete( $wpdb->prefix . 'my_addon_meta', [ 'entry_id' => $entry_id ], [ '%d' ] );
} );
Fires after all email notifications configured for a form have been sent. Use this when you need to run logic that depends on notifications having already been dispatched.
add_action( 'formcierge_after_form_notifications', function ( $form_id, $entry_id ) {
error_log( "Notifications sent for form $form_id, entry $entry_id" );
}, 10, 2 );
Fires after a notification email has been dispatched. Use for delivery logging, analytics, or triggering follow-up actions.
add_action( 'formcierge_after_send_email', function ( $to, $subject, $message, $form_id ) {
my_slack_notify( "Email sent to $to for form $form_id" );
}, 10, 4 );
Fires after an entry's status has been changed. Both the new and old status values are provided.
add_action( 'formcierge_after_status_change', function ( $entry_id, $new_status, $old_status ) {
if ( $new_status === 'completed' && $old_status !== 'completed' ) {
my_trigger_fulfillment( $entry_id );
}
}, 10, 3 );
Fires after a form submission has been validated, saved to the database, and all built-in notifications have been queued. This is the primary hook for post-submission logic such as webhooks, CRM syncing, or custom emails.
add_action( 'formcierge_after_submission', function ( $form_id, $entry_id, $data ) {
// Send data to a CRM
if ( $form_id === 42 ) {
my_crm_push( $data );
}
}, 10, 3 );
Fires before an entry is permanently deleted. Use this to back up entry data to an external service or clean up related records.
add_action( 'formcierge_before_entry_delete', function ( $entry_id, $form_id ) {
my_archive_entry( $entry_id );
}, 10, 2 );
Fires immediately before a notification email is sent. You can use this hook for logging, auditing, or conditionally blocking email sending by removing the default mailer action.
add_action( 'formcierge_before_send_email', function ( $to, $subject, $message, $form_id ) {
error_log( "[Formcierge] Sending email to $to — Subject: $subject" );
}, 10, 4 );
Fires when Formcierge attempts to create an Easy Digital Downloads payment from a form submission.
add_action( 'formcierge_create_edd_payment', function ( $form_id, $entry_id, $payment_data ) {
error_log( "Creating EDD payment for entry $entry_id" );
}, 10, 3 );
Fires when Formcierge attempts to create a WooCommerce order from a form submission.
add_action( 'formcierge_create_wc_order', function ( $form_id, $entry_id ) {
error_log( "Creating WC order for entry $entry_id" );
}, 10, 2 );
Fires immediately after the Formcierge plugin is deactivated. Use this to clean up scheduled events, flush rewrite rules, or remove transients created by your addon.
add_action( 'formcierge_deactivated', function () {
wp_clear_scheduled_hook( 'my_addon_cron_event' );
} );
Fires before a webhook is dispatched via the Workflow Automation addon.
add_action( 'formcierge_dispatch_webhook', function ( $url, $payload, $entry_id ) {
error_log( "Dispatching webhook to $url for entry $entry_id" );
}, 10, 3 );
Fires after an Easy Digital Downloads payment has been successfully created from a form submission.
add_action( 'formcierge_edd_payment_created', function ( $payment_id, $entry_id ) {
update_post_meta( $payment_id, '_formcierge_entry', $entry_id );
}, 10, 2 );
Fires when an entry's status is changed to "completed". Use this to trigger fulfillment logic, send a confirmation message, or update an external system.
add_action( 'formcierge_entry_completed', function ( $entry_id, $form_id ) {
my_send_completion_email( $entry_id );
}, 10, 2 );
Fires when an entry is marked as spam. Use to sync spam decisions with external spam-filtering or analytics tools.
add_action( 'formcierge_entry_spam', function ( $entry_id, $form_id ) {
my_report_spam_ip( $entry_id );
}, 10, 2 );
Fires when an entry is starred or unstarred in the admin. The second parameter indicates the new starred state.
add_action( 'formcierge_entry_starred', function ( $entry_id, $starred ) {
if ( $starred ) {
my_crm_flag_entry( $entry_id );
}
}, 10, 2 );
Fires the first time an entry is opened in the admin. Can be used to mark an entry as read in an external system or trigger a notification to a team member.
add_action( 'formcierge_entry_viewed', function ( $entry_id ) {
my_notify_assignee( $entry_id );
} );
Fires after Formcierge has fully initialised and all internal components are loaded. Use this hook to safely register extensions, custom field types, or third-party integrations that depend on the plugin being ready.
add_action( 'formcierge_init', function () {
// Plugin is fully loaded — safe to use Formcierge APIs here
my_addon_bootstrap();
} );
Generic integration trigger fired for key lifecycle events. Use this single hook to build integrations that respond to multiple event types without hooking into each individually.
add_action( 'formcierge_integration_trigger', function( $event, $entry_id, $data ) {
if ( 'submission_created' === $event ) {
// Handle new submission
} elseif ( 'status_changed' === $event ) {
// Handle status change
}
}, 10, 3 );
Fires after a note has been added to an entry. Use to send a notification or sync the note to an external project management tool.
add_action( 'formcierge_note_added', function ( $entry_id, $note_id ) {
my_pm_add_comment( $entry_id, $note_id );
}, 10, 2 );
Fires during plugin initialisation to allow registering custom AI providers. Call your provider registration function here so it is available in Settings > AI.
add_action( 'formcierge_register_ai_providers', 'my_register_claude_provider' );
function my_register_claude_provider() {
formcierge_register_ai_provider( new My_Claude_Provider() );
}
Fires during plugin initialisation to allow registering custom email notification templates.
add_action( 'formcierge_register_email_templates', function () {
formcierge_register_email_template( 'my-branded', [
'label' => 'My Branded Template',
'template' => get_stylesheet_directory() . '/email-templates/branded.html',
] );
} );
Fires during plugin initialisation to allow registering custom merge tags.
add_action( 'formcierge_register_merge_tags', function () {
formcierge_register_merge_tag( 'custom_user_id', function ( $context ) {
return get_current_user_id();
} );
} );
Fires after a custom REST API field has been registered on a Formcierge post type.
add_action( 'formcierge_rest_custom_field_registered', function ( $post_type, $field_name ) {
error_log( "REST field registered: $field_name on $post_type" );
}, 10, 2 );
Fires after a new form is created via the REST API. Useful for audit logging or automatically associating new forms with a project or group.
add_action( 'formcierge_rest_form_created', function ( $form_id, $data ) {
my_audit_log( 'form_created', $form_id, get_current_user_id() );
}, 10, 2 );
Fires after a form is deleted via the REST API. Use to remove associated data in external systems or clean up addon-specific records.
add_action( 'formcierge_rest_form_deleted', function ( $form_id ) {
delete_option( 'my_addon_form_settings_' . $form_id );
} );
Fires after a form is updated via the REST API. Use for audit trails or cache invalidation in external systems that store form schemas.
add_action( 'formcierge_rest_form_updated', function ( $form_id, $data ) {
delete_transient( 'my_form_cache_' . $form_id );
}, 10, 2 );
Fires after SMTP settings have been saved and PHPMailer has been configured with the new credentials.
add_action( 'formcierge_smtp_configured', function () {
do_action( 'wp_mail_smtp_after_smtp_config_applied' );
} );
Fires after a WooCommerce order has been successfully created from a form submission.
add_action( 'formcierge_wc_order_created', function ( $order_id, $entry_id ) {
update_post_meta( $order_id, '_formcierge_entry', $entry_id );
}, 10, 2 );
Fires after a webhook has been dispatched. The response array contains the HTTP status code and body returned by the endpoint.
add_action( 'formcierge_webhook_dispatched', function ( $url, $response, $entry_id ) {
$code = wp_remote_retrieve_response_code( $response );
if ( $code !== 200 ) {
error_log( "Webhook to $url returned HTTP $code for entry $entry_id" );
}
}, 10, 3 );
Filters
Modify the list of activity types recorded in the entry activity log. Each type maps to a label shown in the admin. Add custom types here to support addon-specific activities.
add_filter( 'formcierge_activity_types', function ( $types ) {
$types['crm_push'] = 'CRM Push';
return $types;
} );
Filter the list of registered Formcierge addons. Each entry describes an addon's metadata and activation status. Use to register or conditionally disable addons programmatically.
add_filter( 'formcierge_addons', function ( $addons ) {
$addons[] = [
'id' => 'my-addon',
'name' => 'My Custom Addon',
'active' => true,
];
return $addons;
} );
Change the WordPress capability required to access the Formcierge admin panel. Default is "manage_options". Use to allow non-administrators to manage forms.
add_filter( 'formcierge_admin_capability', function ( $capability ) {
return 'edit_posts';
} );
Filters the arguments used to send the admin notification email. Use this to override the recipient, subject, template, or content for admin notifications on a per-form basis.
add_filter( 'formcierge_admin_notification_args', function( $args, $config, $context ) {
if ( $context['form_id'] === 42 ) {
$args['to'] = ['special-team@example.com'];
}
return $args;
}, 10, 3 );
Modify the REST API rate limit, expressed as the maximum number of requests allowed per minute per IP address.
add_filter( 'formcierge_api_rate_limit', function ( $limit ) {
return 120;
} );
Filter an entry field value before it is saved during an admin edit. Return the modified value, or return a WP_Error to block the update.
add_filter( 'formcierge_before_entry_data_update', function ( $value, $entry_id, $field_id ) {
if ( $field_id === 'field_phone' ) {
$value = preg_replace( '/[^0-9+-() ]/', '', $value );
}
return $value;
}, 10, 3 );
Filter the target status before an entry's status is changed. Return a different status string to override, or return the original to allow the change.
add_filter( 'formcierge_before_status_change', function ( $new_status, $entry_id ) {
if ( $new_status === 'completed' && my_entry_has_open_notes( $entry_id ) ) {
return 'in-progress';
}
return $new_status;
}, 10, 2 );
Filter the submission data array before it is written to the database. Use to transform, enrich, or remove field values. Return the modified data array.
add_filter( 'formcierge_before_submission_save', function ( $data, $form_id ) {
$data['server_ip'] = $_SERVER['REMOTE_ADDR'] ?? '';
return $data;
}, 10, 2 );
Add or modify the example field prompts provided to the AI model when generating forms.
add_filter( 'formcierge_brain_field_examples', function ( $examples ) {
$examples[] = 'A signature pad for legally binding consent';
return $examples;
} );
Modify the responsive breakpoints used to switch between column layouts on public forms. Values are in pixels.
add_filter( 'formcierge_breakpoints', function ( $breakpoints ) {
$breakpoints['mobile'] = 600;
return $breakpoints;
} );
Control whether the current user can edit field values on a specific entry. Return false to make the entry read-only.
add_filter( 'formcierge_can_edit_entry_data', function ( $can_edit, $entry_id ) {
if ( my_entry_is_completed( $entry_id ) ) {
return false;
}
return $can_edit;
}, 10, 2 );
Modify the AI chat rate limit — the maximum number of AI generation requests a single user can make per minute.
add_filter( 'formcierge_chat_rate_limit', function ( $limit ) {
return current_user_can( 'manage_options' ) ? 30 : $limit;
} );
Modify the system prompt sent to the AI model for form generation. Use to customise AI behaviour or add domain-specific instructions.
add_filter( 'formcierge_command_prompt', function ( $prompt, $context ) {
return $prompt . 'nnAlways generate forms in English. Do not use more than 8 fields.';
}, 10, 2 );
Modify the list of countries available in the Country field type. Use to restrict options, reorder, or add custom territories.
add_filter( 'formcierge_country_list', function ( $countries ) {
return array_intersect_key( $countries, array_flip( ['US', 'GB', 'CA'] ) );
} );
Change the default status assigned to new entries when they are first created. The default is "unread".
add_filter( 'formcierge_default_entry_status', function ( $status ) {
return 'new';
} );
Add custom data to the diagnostic report displayed in Settings > Diagnostic.
add_filter( 'formcierge_diagnostic_report', function ( $report ) {
$report['My Addon'] = [
'Version' => MY_ADDON_VERSION,
'API Status' => my_addon_api_connected() ? 'Connected' : 'Disconnected',
];
return $report;
} );
Enrich a single item returned by a dynamic source before it is sent to the front-end dropdown.
add_filter( 'formcierge_dynamic_source_enrich_item', function ( $item, $source_id ) {
if ( $source_id === 'my_products' ) {
$item['description'] = get_post_meta( $item['value'], '_short_desc', true );
}
return $item;
}, 10, 2 );
Register or modify available ecommerce integrations shown in form payment settings.
add_filter( 'formcierge_ecommerce_integrations', function ( $integrations ) {
$integrations[] = [
'id' => 'my_payment',
'label' => 'My Payment Gateway',
'class' => 'My_Payment_Integration',
];
return $integrations;
} );
Add file attachments to a notification email before it is sent. Return an array of absolute file paths.
add_filter( 'formcierge_email_attachments', function ( $attachments, $form_id, $entry_id ) {
$pdf_path = my_generate_receipt_pdf( $entry_id );
if ( $pdf_path ) {
$attachments[] = $pdf_path;
}
return $attachments;
}, 10, 3 );
Filter the raw email body template before merge tags are resolved.
add_filter( 'formcierge_email_body', function ( $body, $form_id, $entry_id ) {
return $body . 'nn---nSent by My Plugin';
}, 10, 3 );
Filter the fully merged email content after merge tags have been resolved. Last chance to modify before it is handed off to the mailer.
add_filter( 'formcierge_email_content', function ( $content, $notification_id, $entry_id ) {
return make_clickable( $content );
}, 10, 3 );
Override the From email address used in notification emails.
add_filter( 'formcierge_email_from_email', function ( $email, $form_id ) {
return 'noreply@mysite.com';
}, 10, 2 );
Override the From name shown in notification emails.
add_filter( 'formcierge_email_from_name', function ( $name, $form_id ) {
return get_bloginfo( 'name' ) . ' Support';
}, 10, 2 );
Add custom headers to notification emails such as Reply-To, BCC, or X- tracking headers.
add_filter( 'formcierge_email_headers', function ( $headers, $form_id ) {
$headers[] = 'Reply-To: support@mysite.com';
return $headers;
}, 10, 2 );
Modify the list of email recipients for a notification. Use to add conditional CC addresses or route to different teams based on form data.
add_filter( 'formcierge_email_recipients', function ( $recipients, $form_id, $entry_id ) {
$service = formcierge_get_entry_field( $entry_id, 'field_service' );
if ( $service === 'billing' ) {
$recipients[] = 'billing@mysite.com';
}
return $recipients;
}, 10, 3 );
Filter the email subject line after merge tags have been resolved.
add_filter( 'formcierge_email_subject', function ( $subject, $form_id, $entry_id ) {
return '[MyBrand] ' . $subject;
}, 10, 3 );
Add or remove sections displayed on the entry detail page in the admin. Useful for addons that want to surface extra panels alongside the field values.
add_filter( 'formcierge_entry_detail_sections', function ( $sections, $entry_id ) {
$sections[] = [
'id' => 'crm_panel',
'label' => 'CRM Record',
'callback' => 'my_render_crm_panel',
];
return $sections;
}, 10, 2 );
Modify how an entry field value is displayed in the admin entry list and detail view.
add_filter( 'formcierge_entry_display_data', function ( $value, $field_id, $entry_id ) {
if ( str_contains( $field_id, 'card' ) ) {
return '**** **** **** ' . substr( $value, -4 );
}
return $value;
}, 10, 3 );
Modify the list of available entry statuses. Add custom statuses to model your team's workflow.
add_filter( 'formcierge_entry_statuses', function ( $statuses ) {
$statuses['in-progress'] = 'In Progress';
$statuses['awaiting-payment'] = 'Awaiting Payment';
return $statuses;
} );
Add custom merge tags available in notification templates for a specific form.
add_filter( 'formcierge_form_merge_tags', function ( $merge_tags, $form_id ) {
$merge_tags[] = [
'tag' => '{custom_reference}',
'label' => 'Custom Reference Number',
'value' => my_generate_reference( $form_id ),
];
return $merge_tags;
}, 10, 2 );
Modify the available statuses that can be assigned to forms themselves. Default statuses are active, inactive, and draft.
add_filter( 'formcierge_form_statuses', function ( $statuses ) {
$statuses['archived'] = 'Archived';
return $statuses;
} );
Change the number of forms shown per page in the admin forms list. Default is 20.
add_filter( 'formcierge_forms_per_page', function ( $per_page ) {
return 50;
} );
Add or rename merge tag categories shown in the merge tag picker within the notification editor.
add_filter( 'formcierge_merge_tag_categories', function ( $categories ) {
$categories['crm'] = 'CRM Fields';
return $categories;
} );
Add extra data to the context object passed to merge tag resolution. Allows custom merge tags to access any data you inject here.
add_filter( 'formcierge_merge_tag_context', function ( $context, $form_id, $entry_id ) {
$context['crm_contact_id'] = my_crm_get_contact( $entry_id );
return $context;
}, 10, 3 );
Override or transform the resolved value of any merge tag. The tag string includes the curly braces, e.g. "{field:email}".
add_filter( 'formcierge_merge_tag_value', function ( $value, $tag, $context ) {
if ( str_contains( $tag, 'email' ) ) {
return strtoupper( $value );
}
return $value;
}, 10, 3 );
Normalize a field definition array before it is stored or processed. Use to set defaults, enforce constraints, or add computed properties.
add_filter( 'formcierge_normalize_field', function ( $field, $form_id ) {
if ( $field['type'] === 'tel' ) {
$field['required'] = false;
}
return $field;
}, 10, 2 );
Add data to the context array used when rendering notification templates.
add_filter( 'formcierge_notification_context', function ( $context, $form_id, $entry_id ) {
$context['site_logo_url'] = get_custom_logo();
return $context;
}, 10, 3 );
Run custom validation before Formcierge's built-in field validation. Return a WP_Error to reject the submission with a custom message.
add_filter( 'formcierge_pre_submission_validate', function ( $data, $form_id ) {
$email = $data['field_email'] ?? '';
if ( str_ends_with( $email, '@banned-domain.com' ) ) {
return new WP_Error( 'blocked_email', 'This email domain is not allowed.' );
}
return $data;
}, 10, 2 );
Prepare a single field value for storage. Called for each field before the entry is written to the database.
add_filter( 'formcierge_prepare_entry_field', function ( $value, $field ) {
if ( ! empty( $field['sensitive'] ) ) {
return my_encrypt( $value );
}
return $value;
}, 10, 2 );
Filter the final CSS output after a form style template has been compiled.
add_filter( 'formcierge_processed_template', function ( $output, $form_id ) {
if ( $form_id === 12 ) {
$output .= '.fc-form { border: 2px solid red; }';
}
return $output;
}, 10, 2 );
Modify the list of US states available in the State field type.
add_filter( 'formcierge_state_list', function ( $states ) {
$states['PR'] = 'Puerto Rico';
return $states;
} );
Modify the list of states or provinces returned for a specific country when the Address or State field is used in country-aware mode.
add_filter( 'formcierge_states_by_country', function ( $states, $country_code ) {
if ( $country_code === 'AU' ) {
$states['ACT'] = 'Australian Capital Territory';
}
return $states;
}, 10, 2 );
Control which submission metadata fields are included in REST API responses for entry data.
add_filter( 'formcierge_submission_meta_expose', function ( $fields ) {
$fields[] = 'referrer';
return $fields;
} );
Add or remove form style templates available in the Template Customiser.
add_filter( 'formcierge_templates', function ( $templates ) {
$templates[] = [
'id' => 'my-corporate',
'label' => 'Corporate Blue',
'variables' => [
'--fc-primary' => '#003087',
'--fc-radius' => '2px',
],
];
return $templates;
} );
Modify the thank-you screen configuration shown to users after a successful form submission.
add_filter( 'formcierge_thankyou_screen', function ( $config, $form_id ) {
$config['type'] = 'redirect';
$config['redirect_url'] = home_url( '/dashboard/' );
return $config;
}, 10, 2 );
Provide a fallback value for merge tags that were not resolved by any registered handler.
add_filter( 'formcierge_unknown_merge_tag', function ( $value, $tag ) {
return '';
}, 10, 2 );
Filters the arguments used to send the user confirmation email. Use this to personalise the confirmation email on a per-form or per-submission basis.
add_filter( 'formcierge_user_confirmation_args', function( $args, $config, $context ) {
$args['subject'] = 'Thank you, ' . ( $context['submission']['name'] ?? 'friend' ) . '!';
return $args;
}, 10, 3 );
Add custom validation for any field type. Return a non-empty error string to fail validation, or null/empty to pass.
add_filter( 'formcierge_validate_field', function ( $error, $value, $field ) {
if ( $field['type'] === 'email' && $value ) {
$domain = explode( '@', $value )[1] ?? '';
if ( $domain && ! checkdnsrr( $domain, 'MX' ) ) {
return 'Please enter a valid email address with a working domain.';
}
}
return $error;
}, 10, 3 );