Skip to content
  1. Extras
  2. MiniShop3
  3. Manager interface
  4. Utilities
  5. Extra fields

Utilities: Extra fields ​

Your own columns on MiniShop3 models, without editing the core. The field is written to the database and shows up on manager forms.

Cookbook

Step-by-step cases (order, repeater, key-value): Extra fields cookbook. Examples: order field, product wholesale price.

Extra fields utility

Purpose ​

You set a key, a widget type, and a column type. After the column migration, the field is available on the model card and, for a product, in CSV import.

Supported models ​

In the UI you pick a short name. The database and POST store the full MiniShop3\Model\... class.

Short nameClass in API / DBDescription
msProductMiniShop3\Model\msProductAn extra field cannot be added: the model has no table of its own, it extends modResource. Product columns belong on msProductData
msProductDataMiniShop3\Model\msProductDataProduct data
msCategoryMiniShop3\Model\msCategoryAn extra field cannot be added, for the same reason: a category also extends modResource. For custom category data use MODX TVs
msVendorMiniShop3\Model\msVendorVendor
msOptionMiniShop3\Model\msOptionOption
msLinkMiniShop3\Model\msLinkLink type
msOrderMiniShop3\Model\msOrderOrder
msOrderAddressMiniShop3\Model\msOrderAddressDelivery address
msOrderProductMiniShop3\Model\msOrderProductOrder line
msOrderStatusMiniShop3\Model\msOrderStatusOrder status
msCustomerMiniShop3\Model\msCustomerCustomer
msCustomerAddressMiniShop3\Model\msCustomerAddressCustomer address
msDeliveryMiniShop3\Model\msDeliveryDelivery
msPaymentMiniShop3\Model\msPaymentPayment

Reading the schema (GET /api/mgr/extra-fields) is available to any authenticated manager. Order and product forms load it without a separate permission. mssetting_save is required only to create, edit, and delete fields.

Creating a field ​

  1. Pick the model in the list at the top of the page.
  2. Click Add field and fill the form.

Field parameters ​

Basic ​

ParameterDescriptionRequired
KeyUnique field name. The pattern is ^[a-z0-9_]+$, case-insensitive; MySQL 8 reserved words are refusedYes
LabelDisplay nameNo — an empty one falls back to the field key
DescriptionHint for the userNo
ActiveThe field is in useYes
Allow NULL (null)The column accepts NULLNo
Attributes (attributes)unsigned for an unsigned number, auto_increment for an identity column. They reach the migration as signed => false and identity => trueNo

Field key

The key must be unique within the model. Use Latin letters and underscores. For example: wholesale_price, external_id, custom_field.

Widget type (xtype) ​

TypeDescriptionUse
textfieldText fieldStrings, SKUs
numberfieldNumber fieldPrices, quantities
textareaMultiline fieldDescriptions
xcheckboxCheckboxYes or no
ms3-combo-selectFixed dropdownStatuses, delivery types
ms3-combo-vendorVendor pickerLink to a vendor
ms3-combo-autocompleteAutocompletePick from a list
ms3-combo-optionsOption pickerProduct variants
ms3-repeaterTable of rows (JSON)Composition, a list of characteristics
ms3-key-valueKey to value (JSON)A set of named properties
datefieldDate fieldDates. The interface sets dbtype to date or datetime itself

The choices are entered in the «Select options» field of the dialog and stored in select_options. The format is one line per choice, value and label separated by ==:

text
value1==First option
value2==Second option
value3==Third option

With no label the list shows the value itself. Unlike the combo fields of Model fields, there is no database source here — only a fixed list.

Repeater (ms3-repeater) ​

Since v1.12. In properties or the widget config, set repeater_config:

json
{
  "columns": [
    { "key": "name", "label": "Name" },
    { "key": "qty", "label": "Qty", "xtype": "numberfield" }
  ],
  "minRows": 0,
  "maxRows": 50,
  "sortable": true,
  "rankField": "rank"
}

The database type is forced: choosing ms3-repeater sets dbtype: json, phptype: json, an empty precision and null: true, and a manual choice is ignored. ms3-key-value behaves the same. These fields do not enter CSV import.

Key-value (ms3-key-value) ​

Config key_value_config:

json
{
  "mode": "fixed",
  "keys": [
    { "key": "width", "label": "Width", "valueType": "number", "required": false },
    { "key": "material", "label": "Material", "valueType": "string", "required": true }
  ]
}

fixed allows only the listed keys. free lets you add pairs yourself.

Database type (dbtype) ​

TypeDescriptionExample values
varcharVariable-length stringText up to 255 characters
textLong textDescriptions, HTML
intIntegerIDs, quantities
decimalDecimal numberPrices with cents
tinyintSmall integer (0-255)Flags, ratings
dateDate without time2024-01-15
datetimeDate and time2024-01-15 12:30:00
timestampTimestampUnix timestamp
jsonJSON dataArrays, objects

Precision ​

For varchar and decimal:

  • varchar: maximum string length (default 255)
  • decimal: format 10,2 (10 digits in total, 2 after the decimal mark)

PHP type (phptype) ​

TypeDescription
stringString
integerInteger
floatFloating-point number
booleanBoolean
jsonJSON (encoded and decoded automatically)
datetimeDateTime object
timestampUnix timestamp

Default value ​

TypeDescription
NULLEmpty value
CURRENT_TIMESTAMPCurrent time (for datetime)
USER_DEFINEDSet it yourself
NONENo default

Indexing ​

TypeDescriptionWhen to use
NONENo indexRarely used fields
INDEXOrdinary indexFields used for search and sorting
UNIQUEUnique indexFields with unique values
FULLTEXTFull-text indexText search

Field examples ​

Wholesale price ​

text
Key: wholesale_price
Label: Wholesale price
xtype: numberfield
dbtype: decimal
Precision: 12,2
phptype: float
Default: NULL
Index: NONE

External ID (1C) ​

text
Key: external_id
Label: ID in 1C
xtype: textfield
dbtype: varchar
Precision: 50
phptype: string
Default: NULL
Index: UNIQUE

Delivery time ​

text
Key: delivery_days
Label: Delivery time (days)
xtype: numberfield
dbtype: int
phptype: integer
Default: USER_DEFINED → 3
Index: NONE

Extra characteristics (JSON) ​

text
Key: extra_attributes
Label: Extra characteristics
xtype: textarea
dbtype: json
phptype: json
Default: NULL
Index: NONE

Where «Precision» goes

The value reaches the migration differently depending on the database type: for varchar, char, int, tinyint and smallint it becomes limit; for decimal, float and double written with a comma (12,2) it becomes a limit and scale pair. For other types the field is ignored.

Editing a field ​

Click the field row. The edit dialog opens.

Limits

After creation only the label, the description, the widget type, the active flag and the widget configs can change — label, description, xtype, active, select_options, repeater_config, key_value_config.

Everything else is fixed: the field key, class, dbtype, phptype, precision, null, default, default_value, attributes, index_type. To change them, delete the field and create it again.

What else happens on creation

For msProductData fields the service also creates a row in ms3_product_fields — which is why the field appears in the Product fields utility right away, with no section, width 6 (12 for ms3-repeater and ms3-key-value) and order 999. Deleting the field removes that row.

For classes without a table of their own no DROP COLUMN runs: only the field metadata is deleted.

Deleting a field ​

  1. Click the delete icon on the field row
  2. Confirm in the dialog

Caution

Deleting a field is irreversible. You lose:

  • the field definition in the schema
  • the column in the database table
  • every value of this field on every record

Use in code ​

Reading a value ​

php
// Get the product
$product = $modx->getObject(\MiniShop3\Model\msProduct::class, $id);

// Get the product data
$data = $product->getOne('Data');

// Read the extra field
$wholesalePrice = $data->get('wholesale_price');

Saving a value ​

php
$data = $product->getOne('Data');
$data->set('wholesale_price', 999.99);
$data->save();

In snippets (Fenom) ​

fenom
{$wholesale_price}
{if $wholesale_price > 0}
    <span class="wholesale">Wholesale: {$wholesale_price | number_format : 0} RUB</span>
{/if}

API endpoints ​

List fields of a model ​

http
GET /api/mgr/extra-fields?class=MiniShop3\Model\msProductData

Create a field ​

http
POST /api/mgr/extra-fields

Request body:

json
{
  "class": "MiniShop3\\Model\\msProductData",
  "key": "wholesale_price",
  "label": "Wholesale price",
  "xtype": "numberfield",
  "dbtype": "decimal",
  "precision": "12,2",
  "phptype": "float",
  "null": true,
  "default": "NULL",
  "index_type": "NONE",
  "active": true
}

Update a field ​

http
PUT /api/mgr/extra-fields/{id}

Delete a field ​

http
DELETE /api/mgr/extra-fields/{id}

Migrations ​

When you create a field:

  1. A row is created in the field configuration table
  2. A column is added to the model table (ALTER TABLE)
  3. An index is created (if you asked for one)

When you delete a field:

  1. The configuration row is removed
  2. The column is removed from the database table