> For the complete documentation index, see [llms.txt](https://docs.acpt.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.acpt.io/developers/functions/save_acpt_form_field.md).

# save\_acpt\_form\_field

Create or update a form field

Create or update a form field.

Performs an upsert: if a field with the given `name` already exists on the form, it is updated in place — every other field on the form is preserved.

### Usage

```php
save_acpt_form_field([
    'form_name'   => 'new-form',
    'group'       => 'Standard fields',
    'name'        => 'email',
    'label'       => 'Email',
    'type'        => 'Email',
    'description' => 'Your email address',
    'isRequired'  => false,
    'extra'       => [],
    'settings'    => [],
]);
```

### Parameters

| Parameter     | Type    | Required | Description                                                                        |
| ------------- | ------- | -------- | ---------------------------------------------------------------------------------- |
| `form_name`   | string  | Required | The form name (slug). Also accepted as `formName`                                  |
| `name`        | string  | Required | The field name                                                                     |
| `key`         | string  | Optional | A unique key identifying this field within the form. Auto-generated when omitted   |
| `metaFieldId` | string  | Optional | UUID of an existing ACPT meta field to bind this form field to                     |
| `group`       | string  | Optional | The field group label (used to organise fields visually)                           |
| `type`        | string  | Optional | The field type (see allowed values below)                                          |
| `label`       | string  | Optional | The human-readable field label                                                     |
| `description` | string  | Optional | Help text shown below the field                                                    |
| `isRequired`  | boolean | Optional | Whether the field is required. Also accepted as `is_required`. Defaults to `false` |
| `extra`       | array   | Optional | Extra field-type-specific data                                                     |
| `settings`    | array   | Optional | Field display and behaviour settings                                               |

{% hint style="warning" %}
This call always rebuilds the form's **entire** field set — passing only the one field you're changing is safe (every other existing field is preserved automatically), but omitting `form_name` or `name` fails the whole call.
{% endhint %}

**Allowed `type` values:**

Standard fields: `Address`, `AddressMulti`, `Audio`, `AudioMulti`, `Barcode`, `Button`, `Captcha`, `Checkbox`, `Color`, `Country`, `Currency`, `Date`, `DateTime`, `DateRange`, `Email`, `Embed`, `File`, `Hidden`, `HTML`, `Icon`, `ID`, `Length`, `List`, `Number`, `Password`, `Phone`, `QRCode`, `Radio`, `Range`, `Rating`, `Repeater`, `Select`, `Text`, `Textarea`, `Time`, `Toggle`, `Turnstile`, `Url`, `Weight`

Relational fields: `Post`, `PostObject`, `TermObject`, `User`

Layout / formatting elements: `LayoutContainer`, `LayoutSteps`, `FormattingImage`, `FormattingHeading`, `FormattingParagraph`, `FormattingLink`, `Message`, `Acceptance`

WordPress-bound fields (auto-fill from / write to the current post, term, or user): `PostThumbnail`, `PostTitle`, `PostContent`, `PostExcerpt`, `PostDate`, `PostAuthor`, `PostTaxonomies`, `TermName`, `TermDescription`, `TermSlug`, `UserEmail`, `UserFirstName`, `UserLastName`, `Username`, `UserPassword`, `UserBio`

### Return

| Type   | Description                                                                                       |
| ------ | ------------------------------------------------------------------------------------------------- |
| `bool` | `true` on success, `false` if `form_name`/`name` are missing, the form doesn't exist, or on error |
