Skip to main content

Attribute fields & types reference

Attributes are the custom, taxonomy-driven fields you attach to products — a Color dropdown, a Weight numeric, a Care instructions long-text block. This page is the field-by-field lookup for how an attribute is defined: its data type, its option values, its validation and display settings, and the edge-case behaviors (numeric precision formatting, force-delete guards, grouped listing) that you can't see from the form alone.

For the task of creating and editing attributes, see Manage attributes. For how attributes hang off categories and attribute groups, see How product taxonomy works and Manage attribute groups. To set attribute values on a specific product, see Set a product's categories & attributes.

Before you begin

Managing attribute definitions requires the products scope plus the relevant granular permission: attributes.create, attributes.update, attributes.archive, attributes.delete, or attributes.import. See Product permissions reference.

Data types

Every attribute has a Type that fixes how its value is stored, cast, and rendered. The default type is string.

Type (type)Label in dialogStoresNotes
stringStringShort single-line textDefault type. Can be flagged Is Link? (display.is_link) to render as a hyperlink. Supports a character limit.
longtextLongtextMulti-line / rich textCan be flagged Is HTML? (display.is_html). Supports a character limit. Has no Display (options) section.
integerIntegerWhole numbersSupports min / max validation.
numericNumericDecimal numbersSupports min / max and a precision (decimal places). See Numeric precision formatting. Numeric attribute values can back a relative pricing tier basis.
checkboxCheckboxA booleanThe value is cast to a real boolean when read on a product. Has no Display (options) section.
dateDateA dateDate-only value.
datetimeA date + timeSupported by the back end and validation, but the attribute dialog's type list currently exposes only the six types above; use the API or import to set datetime.

The back end accepts exactly these seven values (string, longtext, date, datetime, numeric, integer, checkbox); any other type is rejected with a validation error.

Checkbox is cast to boolean

When a product's value for a checkbox attribute is read, the value cast is switched to boolean — so a stored 1/0 comes back as true/false rather than a string. Aside from the numeric precision formatting described below, this is the only type whose product value is transformed away from its raw stored form.

Option values & options_type

Any non-checkbox, non-longtext attribute can be marked Has Options? to become a pick-list (for example a Color attribute with a fixed set of swatches). Options live as separate value rows on the attribute.

FieldWhere it livesMeaning
Has Options? (has_options)display.has_optionsWhether the attribute is a pick-list. This is a virtual attribute — there is no physical has_options column; reads and writes both go through the display JSON, so they can never diverge.
Type (options_type)display.typeSingle (single-select) or Multi (multi-select). Defaults to Multi.
Allow Custom Value? (allow_custom_value)display.allow_custom_valueWhether a user can type a value outside the option list.
Option valueattribute_values.valueThe option text itself (max 255 characters). Blank lines are ignored on save.
Option sort_orderattribute_values.sort_orderThe display order of each option (0-based).

In the dialog you type or paste options one per line into Type or Paste Options; each line becomes one option value with a sequential sort_order. On update, options you remove from the list are deleted, and options that remain are matched by their value text and kept.

The Display (options) section is hidden entirely for checkbox and longtext attributes — those types can't have options.

Validation, display & notes fields

The validation field is a free-form JSON object; only the keys relevant to the chosen type are read. The display field is a separate JSON object holding presentation flags. notes is free text.

FieldKeyApplies toMeaning
Character Limitvalidation.limitstring, longtextMaximum text length.
Precision (digits)validation.precisionnumericDecimal places to format the value to, 09.
Minvalidation.mininteger, numericMinimum allowed value.
Maxvalidation.maxinteger, numericMaximum allowed value.
Is Link?display.is_linkstringRender the value as a hyperlink.
Is HTML?display.is_htmllongtextTreat the value as HTML.
Sort Orderdisplay.sort_orderallThe attribute's own position in a list (virtual attribute, stored inside display).
Available for templatesavailable_for_templatesallSee Template flag.
NotesnotesallFree-text note, max 255 characters. Internal — not shown on products.

Field-level rules enforced on save:

RuleField
Required, max 255, unique across attributesname
Required, one of the seven typestype
Nullable arraydisplay_options, validation
Nullable, boolean when presentavailable_for_templates
Must reference an existing attribute groupattribute_group_id
Nullable, max 255notes

The Validation section of the dialog is shown for string, longtext, numeric, and integer types only.

Numeric precision formatting

When you read an option value of a numeric attribute that has a validation.precision set, the value is passed through number_format() with that precision before it's returned.

  • The returned value is a formatted string (for example precision 2 turns a stored 9.5 into "9.50", and 1234.5 into "1,234.50" with a thousands separator).
  • Because it's formatted for display, it may not reflect the raw stored precision — a stored 9.567 read with precision 2 comes back rounded to "9.57".
  • Formatting is applied only when both conditions hold: the attribute type is numeric and validation.precision is present. Otherwise the raw stored value is returned unchanged.

Grouped + ungrouped listing

GET /api/attributes/grouped returns attributes organized for the taxonomy UI in two buckets:

KeyContents
groupedEach attribute group with its attributes nested inside (sorted by each attribute's sort_order).
ungroupedAttributes with no group — where attribute_group_id is null or 0.

An attribute is considered ungrouped when its attribute_group_id is null or zero. On save, a 0 group id is normalized to null, so both forms are treated identically as "no group." To organize attributes into groups, see Manage attribute groups.

Template flag

available_for_templates is a boolean flag that marks an attribute as usable in product templates — the reusable starting points you build products from. It's a first-class field on the attribute (validated as boolean, cast to bool), independent of type, options, or group. Setting it doesn't change how the attribute behaves on an individual product; it only controls whether the attribute is offered when building from templates.

Force-delete with ignore_relations

Deleting an attribute normally checks whether anything still references it. Two independent kinds of usage are checked:

  1. Products — how many products carry a value for this attribute.
  2. Integration import mappings — any DataImportMapping whose sku_field is attributes.{name}, that is, a channel import that maps an incoming column onto this attribute.

The ignore_relations flag on the delete request changes the behavior:

Situationignore_relationsResult
Attribute used by products and/or import mappingsabsent / falseBlocked400 with a "currently used" message listing the relations. Nothing is deleted.
Attribute used by products onlytrueDeleted. The product values and product links are detached and the attribute is removed. The response still returns an impact payload (products_count) so the downstream effect is acknowledged, never silent.
Attribute used by import mappingstrueStill blocked400 with the impact details. A force-delete can't bypass this, because deleting the attribute would silently break those channel import mappings. Remove or repoint the mappings first.

Every delete response — allowed or blocked — carries an impact object with products_count, import_mappings_count, and the affected import_mappings, so the consequences of a force-delete are always surfaced rather than hidden. There is no separate secondary confirmation step; the impact payload is the acknowledgment.

To find what a delete would affect before you try it, the POST /api/attributes/deletable endpoint returns a deletable flag and reason per attribute id — see Manage attributes.

Next steps

Last verified: