Forms
A form is an ordered list of typed fields mapped to the columns of one Dataverse table. Submissions are validated and converted on the server and create a record, or update the record on the page in update mode. Every write is nonce-verified, honeypot-checked and rate limited; Cloudflare Turnstile can be switched on per form.
Setting up a form
On the Forms tab a form needs a key, the entity set and at least one field; the table's logical name is optional but required for metadata labels, choice options and required levels. Fields go in the field table: one row per input, in display order.
| Column of the field table | Meaning |
|---|---|
| Name | Submitted field name. Defaults to the column. |
| Column | Logical name of the target column. |
| Type | One of the types below. |
| Label | Shown to the visitor. Empty means the column's display name from metadata, then a prettified field name. |
| Required | Adds to the column's own required level; metadata can make a field required, never optional. |
| Options | For choices: one value = label per line, empty means the column's own choices. For lookups: the lines table = ..., entity_set = ..., name_column = ... and nav = .... |
| Default | Fixed value of a hidden field, initial value otherwise. |
Below the table: Mode, Bind to collection, Success message, Redirect after success and the Turnstile settings. The older Field map textarea and Required fields line still work for plain text forms; rows in the field table take precedence. Consent adds a checkbox the visitor must tick. Relate to binds a created record to the record the form was shown on: give the lookup's navigation property (schema name casing, for example wbs_Listing) and the collection key.
Place the form with [wbsdvc_form name="inquiry"], the Dataverse Form block, or the form attribute of a collection or record shortcode, which attaches it under the detail view.
Field types
| Type | Input | Value written |
|---|---|---|
| text | Single line | Sanitized text |
| Email input | Validated address; invalid addresses are rejected | |
| phone | Telephone input | Sanitized text |
| textarea | Multi-line | Sanitized multi-line text |
| number | Number input | Integer for Integer and BigInt columns, decimal otherwise; comma decimals accepted |
| money | Number input, two decimals | Decimal |
| date | Date picker | YYYY-MM-DD |
| datetime | Date and time picker | ISO 8601 in UTC, converted from the site's timezone |
| choice | Select | Option value as integer |
| multichoice | Checkboxes | Comma-separated option values |
| boolean | Checkbox | true or false; a required yes/no must be ticked |
| lookup | Select of the target table's names (up to 200 rows, cached) | nav@odata.bind to the target record |
| hidden | None | The Default, typed by the column's metadata |
Typing rules
- Choices resolve by option value first, then by a case-insensitive label match. Options come from the row's Options text or, when empty, from the column metadata. A value outside the known options is rejected with a message naming the field.
- Dates are stored as
YYYY-MM-DD. Date and time values without an offset are read in the site's timezone and written in UTC; prefill converts back. - Lookups accept a GUID or a name. A name is resolved with one query against the target's
name_column; no match is a validation error.navdefaults to the column's logical name; set it when the navigation property differs in casing. - Metadata fills in labels, options and required flags an admin left blank. When metadata is unavailable the form still renders with what the rows say.
- Empty optional fields are skipped on create. Required fields, including those Dataverse marks required, block the submission with a visitor-facing message.
Update mode and bind_to
Set Mode to update and pick a Bind to collection over the same entity set. The form then prefills its inputs from the record selected by ?dvc=<slug> (or the record it is attached to) and saves changes with a PATCH, using If-Match: * so it never creates by accident. The record must be visible through the bound collection, including its status filter; a guessed id of a hidden record is refused. In update mode an emptied text, number, date or choice field clears its column; lookups, yes/no and hidden fields are left alone. Bind to falls back to the Relate to collection when empty. The application user needs Write on the table, and every visitor who can see the record can edit the mapped columns, so bind update forms to collections with a tight status filter or use the Business tier's access rules.
Success message and redirect
The Success message replaces the default thank-you text. Redirect after success sends the visitor to a page on the same host instead; other hosts are ignored. Responses carry the new record's id, which the wbs_dataverse_connect_record_created and wbs_dataverse_connect_record_updated actions and the form.created webhook also receive.
Cloudflare Turnstile
- Create a Turnstile widget in the Cloudflare dashboard for your domain and copy the site key and secret key.
- Enter both keys in the form editor. They are stored once, site-wide, and shared by every form; the secret is never shown again.
- Tick Require a Turnstile challenge on this form for each form that should use it.
A form with the toggle loads the widget script from challenges.cloudflare.com in the browser and, on submit, your site verifies the token with Cloudflare's siteverify endpoint together with the visitor's IP address. Without both keys the challenge is skipped. Forms without the toggle never contact Cloudflare.
Consent and spam defences
- REST nonce on every submission (
X-WP-Nonce); the endpoint is public by design and refuses requests without it. - Honeypot field
_dvc_website: bots fill it, humans never see it, and the response is a silent success. - Rate limit: 5 submissions per IP address per 10 minutes.
- Optional Turnstile per form, and the optional consent checkbox.
Values are sanitized on the way in and typed on the way out; nothing reaches the Web API unvalidated. Failed writes are logged with the Dataverse detail for the admin and health-alerted; the visitor sees a generic message.
The WBS Forms bridge
The free plugin also takes submissions from WBS Forms (or any builder that fires wbs_forms_after_submit with a field-name to value array). The form keeps rendering, validating and mailing on its own; the bridge maps the fields onto a table with per-field typing and creates the record. A mapping is declared per form slug with the wbs_dataverse_connect_bridge_maps filter or stored in the option of the same name:
add_filter('wbs_dataverse_connect_bridge_maps', function ($maps) {
$maps['job-application'] = [
'entity_set' => 'sm_bewerbungs',
'fields' => [
'first_name' => 'sm_vorname',
'email' => ['column' => 'sm_email', 'type' => 'email'],
'birthday' => ['column' => 'sm_geburtsdatum', 'type' => 'date'],
'salutation' => ['column' => 'sm_anrede', 'type' => 'choice',
'options' => ['Mr' => 930860000, 'Ms' => 930860001]],
'licenses' => ['column' => 'sm_fuhrerschein', 'type' => 'multichoice',
'options' => ['C' => 930860000, 'CE' => 930860001]],
'privacy' => ['column' => 'wc_dataprivacypolicyde', 'type' => 'boolean'],
'job' => ['column' => 'sm_job', 'type' => 'lookup', 'nav' => 'sm_Job',
'entity_set' => 'sm_jobs', 'resolve_by' => 'sm_name', 'id_field' => 'sm_jobid'],
],
'defaults' => ['sm_source' => 930860003],
];
return $maps;
});
Bridge types: string (default), email, int, date, boolean, choice, multichoice, lookup. Choices accept the option value or a label from options; lookups accept a GUID or resolve a label through resolve_by and id_field. A map can carry its own connection to write into a different environment. If Dataverse is down the failure is logged and alerted, and the form's own email still goes out, so no submission is lost.
Pro: Contact Form 7 and Gravity Forms
The Pro add-on maps a Contact Form 7 or Gravity Forms form to a form configured on the Forms tab and pushes the submitted values through the same create pipeline. In CF7 add the line wbsdvc_form: inquiry under Additional Settings; in Gravity Forms set the Dataverse form key on the form settings screen. Submitted field names are lowercased and matched against the form's field names. Failures are logged and never block the source form. Details on the Pro page.