Forms

Last updated: September 2026, plugin 1.5.2

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 tableMeaning
NameSubmitted field name. Defaults to the column.
ColumnLogical name of the target column.
TypeOne of the types below.
LabelShown to the visitor. Empty means the column's display name from metadata, then a prettified field name.
RequiredAdds to the column's own required level; metadata can make a field required, never optional.
OptionsFor choices: one value = label per line, empty means the column's own choices. For lookups: the lines table = ..., entity_set = ..., name_column = ... and nav = ....
DefaultFixed 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

TypeInputValue written
textSingle lineSanitized text
emailEmail inputValidated address; invalid addresses are rejected
phoneTelephone inputSanitized text
textareaMulti-lineSanitized multi-line text
numberNumber inputInteger for Integer and BigInt columns, decimal otherwise; comma decimals accepted
moneyNumber input, two decimalsDecimal
dateDate pickerYYYY-MM-DD
datetimeDate and time pickerISO 8601 in UTC, converted from the site's timezone
choiceSelectOption value as integer
multichoiceCheckboxesComma-separated option values
booleanCheckboxtrue or false; a required yes/no must be ticked
lookupSelect of the target table's names (up to 200 rows, cached)nav@odata.bind to the target record
hiddenNoneThe 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. nav defaults 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

  1. Create a Turnstile widget in the Cloudflare dashboard for your domain and copy the site key and secret key.
  2. Enter both keys in the form editor. They are stored once, site-wide, and shared by every form; the secret is never shown again.
  3. 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.

See also