Informacje techniczne
Documentation E-Toolkit Form Builder
Instructions, technical specifications and change history — always in line with the current version of the product.
Technical compliance
WordPress
From version 6.4
Tested up to 7.1WooCommerce
Optional integration
PHP
From version 8.1
Knowledge base
Documentation
User Manual Set-up, operation and troubleshooting.
E-Toolkit Form Builder — User Guide
What the plugin does
E-Toolkit Form Builder creates forms, publishes them through a shortcode, sends email, and stores submissions in the WordPress dashboard.
The field palette also includes slider, currency, section, address and password fields. Password values are never stored in submissions, emails, drafts or exports; only an action that explicitly opts in to sensitive values can consume them during the original request.
Quick start
- Open E-Toolkit → Form Builder or Form Builder.
- Create a form or select an existing one.
- On Form Builder, select one of the ten presets or add fields manually.
- Select a field in the center and configure it on the right. General contains field data and the Required option, Appearance contains visual settings, and Logic contains conditional rules.
- Open General settings to configure appearance, actions, messages, and integrations for the whole form.
- Click Save.
- Add the E-Toolkit Form block in the block editor and select the form, or copy a shortcode such as
into a page or post.
Applying a preset to a form that already has fields requires confirmation and replaces the current layout.
Field bundles work differently: Name, Address, and UTM tracking append their fields to the current form. The UTM bundle adds hidden fields for utm_source, utm_medium, utm_campaign, utm_term, and utm_content.
Presets
The builder includes ten starting forms: Contact, Newsletter, Quote request, Consultation booking, Event registration, Complaint, Satisfaction survey, Application, Order, and Document upload. Presets are starting points; every field and text can be changed.
Fields and layout
The field panel contains:
- Presets — ready-to-use starting forms,
- Field bundles — reusable groups appended without replacing existing fields,
- Basic — text, email, phone, URL, hidden, date, time, number, rating, calculation, textarea, single file, and multiple files,
- Choice — select, radio, checkbox, and checkbox list,
- Layout — divider, paragraph, and form steps,
- Actions — submit button.
Sections can be collapsed. Select, delete, or drag a field to reorder it. Settings include label, name, placeholder, width, required state, choices, consent text, file restrictions, and conditional logic. In the Logic tab, choose Configure conditions to edit up to ten visibility rules in a dedicated dialog, then join them as all conditions or any condition. Use the live Condition test panel to enter sample answers and verify each rule and the final field visibility before applying the configuration. Fields that would create a circular dependency are not available as controlling fields. A multiple-file field accepts up to 20 files; configure its file count, size, and type limits in the field settings.
Text-like and hidden fields can read an initial value from a named URL parameter. The dedicated UTM mode only accepts parameter names beginning with utm_. Date fields support minimum and maximum dates, allowed weekdays (1 for Monday through 7 for Sunday), and excluded dates entered one per line. These rules are enforced on the server as well as exposed to the browser where native date inputs support them.
Under Settings → Integrations → Anti-spam, enter blocked email domains one per line. example.com blocks that domain and its subdomains; *.example.com blocks subdomains only.
Repeater section
The Repeater section lets visitors add rows containing the same data set, such as participants, products, or estimate items. Configure minimum and maximum row count, button text, and fields in each row.
A row can contain text, email, number, date, textarea, select, radio, checkbox, checkbox list, and hidden fields. A repeater cannot contain another repeater. The server always enforces the 50-row limit.
Submissions store an ordered list of rows. The dashboard and emails show readable labels, JSON, REST, and webhooks preserve the nested structure, and CSV stores the complete repeater as JSON in one column.
Calculations
A Calculation field displays a live result and cannot be edited by the visitor. Build formulas with field-name and operator buttons:
{field:quantity} * {field:price}
({field:net} + {field:shipping}) * 1.23Supported operators are +, -, *, /, %, ^, and parentheses. Formulas also support min(), max(), avg(), abs(), round(), ceil(), floor(), and the PI constant. Decimal constants use a dot. Results can use number, currency, or percentage format; a currency such as PLN, EUR, or USD; 0–6 decimal places; and standard, ceiling, or floor rounding. The formula test accepts sample values and displays the result or a parsing error without saving those samples.
For a calculation field controlled by conditional logic, choose whether hiding it should produce 0 or omit the field. Zero remains available to later calculations and is stored with the submission. An omitted calculation is not evaluated or stored.
Fields referenced by a formula must contain numbers. Select, radio, and checkbox-list options can have a separate optional calculation value, while their technical value remains unchanged in submissions and conditional logic. Without a calculation value, the technical option value is used. An empty numeric field equals 0.
Numeric fields inside a repeater appear in the formula picker with a Σ marker. Their wildcard tag, for example {field:price-*}, adds the values from every populated repeater row. Rows added dynamically are included immediately, and the server recalculates the same total before storing the submission.
The server recalculates the result before saving. Changing the hidden result in browser tools does not affect the submission, email, webhook, or REST API. Division by zero, circular references, and invalid formulas stop submission and show an error beside the calculation field.
Multilingual forms
Language versions require ET Lingua.
- Open the source form.
- Select a target language in the language selector.
- If it does not exist, a connected form version is created.
- Translate labels, placeholders, options, consent text, messages, and buttons in that version.
Language versions are separate technical posts but do not appear as independent forms in the builder's main selector or Mail Manager. Changes to source structure synchronize field types, order, IDs, required state, logic, and added or removed fields. Existing translations remain intact.
Emails and templates
Under Emails and templates, you can assign an administrator template, set its subject and recipient, enable a customer confirmation with its own template and subject, create forms and templates, send a test email, preview the form, or delete it.
Edit subjects and recipients with the pencil icon. The field opens in a small popup so the table does not change height.
In Email Template Builder, Export JSON and Import JSON move a complete template between installations. The file contains its name, blocks, styles, and language versions. Import loads it into the editor; click Save to persist it. Select attachments again after import because Media Library IDs are local to each WordPress installation.
Newsletter unsubscribe link
For a form connected to E24 Leads, use {unsubscribe_url} in the customer confirmation, including directly in an HTML block:
<a href="{unsubscribe_url}">Unsubscribe from the newsletter</a>After form submission, E24 Leads returns an individual signed contact link, which the plugin inserts before WordPress sends the confirmation. This requires an enabled and correctly configured E24 Leads integration.
Publishing a form
In the block editor, add the E-Toolkit Form block and select a published form. In other editors, use ; copy the ID from the builder or Emails and templates. Both methods use the same frontend renderer. The frontend supports AJAX submission and a classic WordPress fallback, with nonce protection and server-side validation.
Save and continue later
Enable drafts under General settings → General and choose a link lifetime from 1 to 365 days. Visitors can save their answers, optionally provide an email address, and receive a secure continuation link. Opening it restores the values and last step.
Drafts are separate from completed submissions, so they do not trigger emails, webhooks, payments, or integrations. Final submission creates a normal entry and removes the used draft. A daily retention task deletes expired drafts and files belonging only to them.
Actions after submission
Under General settings → Confirmations and actions, arrange operations from top to bottom:
- any number of email notifications, each with its own recipient, subject, and content,
- a form-specific webhook with an optional HMAC secret,
- a custom success message or redirect URL.
Each action can be disabled or restricted by up to ten conditions based on field values. Select whether all conditions or any condition must match. Email content and settings support {field:field_name} tags. Forms saved with the earlier single-condition format continue to work without migration. Forms without new email or webhook actions continue to use their legacy settings.
Submission history shows each action result. Email and webhook actions have separate retry buttons that do not reload the list.
Submissions
The Submissions screen stores responses and can send messages to the administrator, another recipient, and optionally the customer. You can:
- filter by form, status, and date,
- search field data, IP address, and browser,
- assign New, Read, Handled, and Spam statuses,
- change status or delete entries in bulk,
- expand details and add an administrator note without leaving the list,
- resend email and, when configured, the webhook,
- view save, email, webhook, status, and note history,
- export filtered data to CSV or JSON.
The search field also accepts an exact numeric submission ID. Links from extensions can open the matching submission details automatically.
CSV contains shared submission data, status, and dynamic form-field columns. JSON preserves the complete field structure. Under Settings → Main settings → Submission retention, permanently delete entries older than the selected number of days. 0 disables retention.
Configure the legacy webhook under Settings → Integrations → Webhook. If its secret is empty, the plugin generates one after the URL is saved. The receiver can verify X-ETFB-Signature.
Privacy and personal data
Form Builder integrates submissions and drafts with Tools → Export Personal Data and Tools → Erase Personal Data. Records are matched by the exact email address stored in form or draft fields.
Exports include answers, technical submission data, and handling history. Erasure removes matching submissions, history, drafts, and their files from uploads. WordPress also suggests privacy-policy text under Settings → Privacy.
Form backup, import, and duplication
Export form saves the schema, form settings, messages, and actions as JSON. Import form validates a file up to 2 MB, regenerates field identifiers, remaps conditional rules, and loads it into the current editor; click Save to persist it. Duplicate opens a complete copy as a new form and also requires saving. Provider secrets and global plugin settings are never included.
The older Export fields action remains available for integrations that only consume the schema.
Antispam protection
Under Settings → Integrations → Anti-spam, enable the hidden honeypot and optionally select Google reCAPTCHA, hCaptcha, or Cloudflare Turnstile. Enter the site and secret keys issued for the selected provider. Leaving the provider as None keeps only the honeypot.
You can also enable Check valid submissions with Akismet. This option requires the separate Akismet plugin to be active and configured. A submission classified as spam is stopped before it is stored or sent to email, webhooks, integrations, and payment providers. If Akismet is unavailable or temporarily returns an invalid response, the form remains available and the submission continues normally.
Akismet receives only the data needed for classification: IP address, browser information, referrer, form page URL, email address, detected name, website URL, and text/textarea content. Uploaded files, phone fields, hidden values, and technical form fields are not sent. Include this processing in the site's privacy policy when the option is enabled. Changing other settings with an empty CAPTCHA secret field preserves the already saved secret.
Troubleshooting
- Form missing on the page — check the shortcode and form ID.
- Email missing — check recipients, templates, and hosting SMTP configuration.
- CAPTCHA fails — check that the selected provider matches the configured site and secret keys and that the provider domain is reachable from the server.
- Akismet does not check submissions — verify that the Akismet plugin is active, has an API key, and that the option is enabled in Form Builder settings.
- Editing unavailable — check the license and administrator permissions.
- Language version has incorrect fields — save the source form to synchronize structure.
- Language change does not show a form — confirm ET Lingua is active and the language is configured.
Developer documentation Functions, hooks, filters and integration tips.
E-Toolkit Form Builder — Developer Guide
This document describes the public API intended for integrations and extensions. Treat elements not listed here as implementation details that may change between releases.
Basic usage
Embed a form with . Integrations should use the stable field id or name provided in the schema. Register hooks on plugins_loaded:
add_action('plugins_loaded', function () {
// Register integration filters and actions.
}, 20);Custom field types
An extension can allow a custom schema type, normalize its configuration, render its control, and handle value validation:
add_filter('etfb_form_field_types', function (array $types): array {
$types[] = 'my_field';
return $types;
});
add_filter('etfb_normalize_form_field', function (array $field, string $type): array {
if ($type === 'my_field') {
$field['my_setting'] = sanitize_text_field((string) ($field['my_setting'] ?? ''));
}
return $field;
}, 10, 2);
add_action('etfb_render_field_my_field', function (array $field, array $context): void {
echo '<input type="text" name="' . esc_attr($context['name']) . '">';
}, 10, 2);
add_filter('etfb_validate_submission_field', function ($result, array $field, array $payload, array $context) {
if (($field['type'] ?? '') !== 'my_field') {
return $result;
}
return [
'handled' => true,
'value' => sanitize_text_field((string) ($payload[$field['name']] ?? '')),
'errors' => [],
'field_error' => '',
];
}, 10, 4);The validation result may also contain attachments and cleanup_files. Files in cleanup_files are removed if the complete submission fails validation.
Use etfb_email_display_values and etfb_submission_display_field to present a custom field. Add a section to expanded submission details with etfb_submission_detail_sections.
Extend default-message attachments with etfb_admin_email_attachments and etfb_client_email_attachments. Return only existing, readable local paths.
Add builder settings through window.ETFB_FIELD_SETTINGS_EXTENSIONS. It supports text, number, textarea, select, and checkbox. storage: 'field' writes values directly to the field schema:
window.ETFB_FIELD_SETTINGS_EXTENSIONS.my_field = {
key: 'my_field_content',
fieldTypes: ['my_field'],
storage: 'field',
title: 'Field text',
fields: [
{ key: 'my_label', control: 'text', label: 'Message', default: 'Default text' },
],
};Server code must independently sanitize every value through etfb_normalize_form_field.
Custom submission actions
An extension can add an action to the builder, sanitize its configuration, and register the server-side handler. Use the same unique action type in PHP and JavaScript.
add_filter('etfb_form_action_types', function (array $types): array {
$types['my_crm'] = __('Send to CRM', 'my-extension');
return $types;
});
add_filter('etfb_form_action_config_sanitizer', function ($sanitizer, string $type) {
if ($type !== 'my_crm') {
return $sanitizer;
}
return static function (array $config): array {
return [
'pipeline' => sanitize_key((string) ($config['pipeline'] ?? '')),
];
};
}, 10, 2);
add_action('plugins_loaded', function (): void {
if (!class_exists('ETFB_Form_Action_Registry')) {
return;
}
ETFB_Form_Action_Registry::register(
'my_crm',
static function (array $action, $submission_id, int $form_id, array $values, array $schema, array $context): array {
// Send the already validated $values to the external service.
return [
'ok' => true,
'message' => 'Sent to CRM.',
];
}
);
}, 20);Expose the action controls before etfb-admin executes. text, number, textarea, select, checkbox, field, and mapping controls are supported:
add_action('admin_enqueue_scripts', function (): void {
if (!wp_script_is('etfb-admin', 'enqueued')) {
return;
}
wp_add_inline_script('etfb-admin', <<<'JS'
window.ETFB_FORM_ACTION_EXTENSIONS = window.ETFB_FORM_ACTION_EXTENSIONS || {};
window.ETFB_FORM_ACTION_EXTENSIONS.myCrm = {
type: 'my_crm',
label: 'Send to CRM',
buttonLabel: '+ CRM',
defaults: { pipeline: 'sales' },
fields: [
{
key: 'pipeline',
control: 'select',
label: 'Pipeline',
options: [
{ label: 'Sales', value: 'sales' },
{ label: 'Support', value: 'support' },
],
},
],
};
JS, 'before');
}, 100);The handler receives normalized values. Return ok and an optional message. Set blocking to true when a failure should stop later actions. Observe every execution with etfb_form_action_executed; use etfb_blocking_form_action_types when an entire action type must always be blocking.
Validate and modify submissions
Hooks run after server-side validation. $values contains normalized, sanitized values indexed by field names, and $schema contains the field configuration.
etfb_submission_schema
Changes the schema used for processing. If it changes field names, they must remain consistent with submitted data.
add_filter('etfb_submission_schema', function (array $schema, int $form_id): array {
return $schema;
}, 10, 2);etfb_submission_field_errors
Adds validation errors. Array keys are field names and values are messages.
add_filter('etfb_submission_field_errors', function (array $errors, int $form_id, array $values, array $schema): array {
if (($values['company_code'] ?? '') === 'blocked') {
$errors['company_code'] = 'This code cannot be used.';
}
return $errors;
}, 10, 4);etfb_submission_values
Changes validated values before storage and integrations run.
add_filter('etfb_submission_values', function (array $values, int $form_id, array $schema): array {
$values['source'] = 'website';
return $values;
}, 10, 3);Form and submission language
add_filter('etfb_form_language', function (string $language, int $form_id): string {
return 'en';
}, 10, 2);
add_filter('etfb_submission_language', function (string $language, int $form_id, array $values): string {
return isset($_POST['etfb_language'])
? sanitize_key(wp_unslash($_POST['etfb_language']))
: $language;
}, 10, 3);etfb_admin_submission_language controls the submission-list language; an empty code disables filtering. Filter the form selector with etfb_submission_forms(array $forms, string $language).
Copying and compiling language versions
etfb_translation_copy_meta_keys() returns configuration metadata copied to a new language version. Extend it without copying runtime artifacts:
add_filter('etfb_translation_copy_meta_keys', function (array $keys): array {
$keys[] = '_my_form_setting';
return $keys;
});Language versions and frontend assets
After changing a translated schema, call the public compiler. It returns true or WP_Error and stores a signed runtime artifact only after a valid compiler response. A local form may retain a local schema; an error for a SaaS-managed form returns WP_Error:
$result = etfb_compile_translated_form_schema($form_id, $schema);
if (is_wp_error($result)) {
// Keep the previous schema or schedule another synchronization attempt.
}Register frontend CSS under the public etfb-front handle:
if (etfb_register_front_style()) {
wp_enqueue_style('etfb-front');
}Conditions and calculations in the schema
Action conditions retain the legacy field, operator, and value keys and additionally expose relation (all or any) plus a rules array. Each rule contains the same three legacy keys. Consumers should prefer rules; an empty array means that the action always runs. The plugin accepts at most ten rules and automatically converts an older single condition during normalization.
Field visibility uses the equivalent structure under logic, with fieldId in place of field and an additional action key set to show or hide. Schema normalization removes direct and transitive circular dependencies deterministically; rules accepted earlier in schema order are retained.
Calculation fields expose calculation_hidden_behavior as zero (the default) or ignore. When conditional logic hides the field, zero stores a normalized zero and makes it available to dependent calculations; ignore omits the field from processing and submission data.
A calculation can sum a numeric repeater child from every row with {field:child_name-*}. The wildcard refers to the child name, not the repeater name or field ID. Both browser and server implementations treat an empty set as zero and reject non-numeric populated values.
Submission events
add_action('etfb_before_submission', function (int $form_id, array $values, array $schema): void {
// Immediately before storing the submission.
}, 10, 3);
add_action('etfb_submission_saved', function (int $submission_id, int $form_id, array $values, array $schema): void {
// After storage. Does not run when submission storage is disabled.
}, 10, 4);
add_action('etfb_submission_sent', function (int $submission_id, int $form_id, array $values, array $schema): void {
// After a successful wp_mail().
}, 10, 4);
add_action('etfb_submission_processed', function ($submission_id, int $form_id, array $values, array $schema, array $context): void {
// After email and integrations. $context includes email_sent.
}, 10, 5);
add_action('etfb_submission_deleted', function (int $submission_id): void {
// Remove extension data connected to the submission.
});Draft actions
add_action('etfb_draft_saved', function (int $draft_id, int $form_id, array $values): void {
// A draft was created or updated.
}, 10, 3);
add_action('etfb_draft_completed', function (int $draft_id, int $submission_id, array $values): void {
// A draft became a final submission.
}, 10, 3);$submission_id may be 0 when submission storage is disabled. Integrations must handle this case.
Submission event labels
add_filter('etfb_submission_event_labels', function (array $labels): array {
$labels['my_crm_sent'] = 'Sent to CRM';
return $labels;
});Webhooks
add_filter('etfb_webhook_payload', function (array $payload, $submission_id, $form_id, array $values, array $schema): array {
$payload['source'] = 'wordpress';
return $payload;
}, 10, 5);
add_filter('etfb_webhook_url', function (string $url, int $form_id, array $values, array $schema): string {
return $url;
}, 10, 4);
add_filter('etfb_allow_unsafe_webhook_url', function (bool $allowed, string $url, int $form_id): bool {
return wp_get_environment_type() === 'local';
}, 10, 3);
add_action('etfb_webhook_delivery', function ($submission_id, string $status, array $result): void {
// $status: queued, success, or failed.
}, 10, 3);Allow unsafe local URLs only in a controlled development environment.
Submission limits
add_filter('etfb_submission_rate_limit', function (int $limit, int $form_id): int {
return 10;
}, 10, 2);
add_filter('etfb_submission_rate_window', function (int $seconds, int $form_id): int {
return 5 * MINUTE_IN_SECONDS;
}, 10, 2);Akismet
When Akismet protection is enabled, valid field values are checked after server-side validation and before persistence or external actions. Service errors fail open; a confirmed spam response stops the submission.
add_filter('etfb_akismet_payload', function (array $payload, int $form_id, array $schema, array $values): array {
return $payload;
}, 10, 4);
add_filter('etfb_akismet_is_spam', function (bool $is_spam, array $payload, int $form_id): bool {
return $is_spam;
}, 10, 3);
add_action('etfb_submission_rejected_as_spam', function (int $form_id, string $provider): void {
// $provider is currently "akismet".
}, 10, 2);
add_action('etfb_akismet_check_failed', function (string $reason, int $form_id): void {
// Operational signal only; no submitted personal data is included.
}, 10, 2);REST API
POST /wp-json/et-form-builder/v1/forms/{form_id}/submissions
Content-Type: application/json{
"fields": {
"name": "Jane Doe",
"email": "jane@example.com",
"message": "Hello"
}
}The endpoint accepts a published form. Pass a reCAPTCHA token as g-recaptcha-response inside fields.
add_filter('etfb_rest_submission_allowed', function ($allowed, WP_REST_Request $request, int $form_id) {
return $allowed; // true or WP_Error.
}, 10, 3);
add_filter('etfb_rest_rate_limit', function (int $limit, int $form_id, WP_REST_Request $request): int {
return 20;
}, 10, 3);
add_filter('etfb_rest_rate_window', function (int $seconds, int $form_id, WP_REST_Request $request): int {
return 300;
}, 10, 3);
add_filter('etfb_rest_client_ip', function (string $ip, WP_REST_Request $request): string {
return $ip;
}, 10, 2);Form and admin screens
etfb_resolved_form_id changes the form ID before shortcode rendering, for example for a language version:
add_filter('etfb_resolved_form_id', function (int $form_id, array $atts): int {
return $form_id;
}, 10, 2);etfb_form_saved runs after a form schema is saved:
add_action('etfb_form_saved', function (int $form_id, array $schema): void {
// Synchronize with an external system.
}, 10, 2);Extend admin lists and helper data with:
etfb_builder_forms(array $forms, $current_form_id),etfb_builder_language_data(array $data, $form_id),etfb_mail_manager_forms(array $forms),etfb_email_builder_language_data(array $data, $template_id).
etfb_e24_leads_payload($payload, $form_id, $schema, $values) changes the E24 Leads payload.
JavaScript event after submission
A successful form emits the bubbling etfb:submission-success event before any configured redirect. Response data is in event.detail:
document.addEventListener('etfb:submission-success', (event) => {
console.log(event.detail);
});Extension-triggered e-mail templates
ETFB_Email::send_action_email() accepts an optional sanitized template_id in its action configuration. The selected Form Builder e-mail template wraps the action content and contributes its configured attachments. Extensions may pass scalar merge tags; {tag_name} placeholders are sanitized before replacement. Keys ending in _url are sanitized as URLs.
Use etfb_action_email_attachments to filter the final attachment list for an action e-mail.
Calculation fields
A calculation field exposes a normalized numeric $values entry with . as the separator before etfb_submission_values.
[
'type' => 'calculation',
'name' => 'total',
'calculation_formula' => '{field:quantity} * {field:price}',
'calculation_format' => 'currency', // number, currency, percent
'calculation_currency' => 'PLN',
'calculation_decimals' => 2,
'calculation_rounding' => 'round', // round, ceil, floor
]Sensitive field values
The password field is removed from normal submission values. A custom form action can explicitly opt in with etfb_form_action_receives_sensitive_values and then read the original value from $context['sensitive_values']. Built-in email and webhook actions do not receive it, and manual retries cannot recover it.