Add more details: Custom Attributes

Custom Attributes

Products, variants, orders and customers can all be expanded with additional information. Here's how you can do it.

The following structure is used in the config.php to define custom attributes on products, variants, accounts and orders. Attributes allow you to create arbitrary fields that will be available in the API and exports. There are different types of attributes.

The API-outputs defined below are using the Shop API, some differences might apply to other APIs, which will be defined in the corresponding API reference.

Mapped attributes

The normal attribute on a product or variant is one which is mapped to an attribute object which can contain meta-data. There is a reason for this, for example: if you have a specific Color-attribute that contains the name, hex-code and image of the color. You do not want to upload these values every time, so an attribute is then created, which you then link to the products that should have the color. Think of mapped attributes as const values that you can later choose from.

The structure looks something like this:

<?php
$usr_conf['ATTRIBUTE_TYPES'] = [
    'sh_swatch' => [
        'desc' => 'Showroom Color Swatch',
        'readonly' => true,
        'group' => 'variation',
        'elements' => [
            'color' => ['desc' => 'Image', 'type' => 'image', 'size' => '60x60'],
            'color_text' => ['desc' => 'Color', 'type' => 'textarea']
        ],
    ]
];

You can then create a new Showroom Color Swatch-attribute under CATALOG / ATTRIBUTES:

When this attribute is saved, this attribute option will be listed under the Showroom Color Swatch-title in the variant-section of the product:

In the API, the values will come out like this:

{
    "countryOfOriginName": "",
    "sh_swatch": {
        "color": {
            "type": "image",
            "url": "https://.../client/dynamic/attributes/image_9471.jpg",
            "width": "60",
            "height": "60",
            "mimeType": "image/jpeg"
        },
        "color_text": "#8b0000"
    },
    "markets": {
        "...": "..."
    }
}

Dynamic attributes

Dynamic attributes are in comparison to mapped attributes not linked to any pre existing attribute, but do have specific data for the specific products. This data needs to be set for each product instead of linking to an existing attribute. The difference between mapped and dynamic is that dynamic uses "readonly": false for the attribute.

It used to be that if you had "readonly": false on the attribute, only the element with the text key would be visible in the API. This meant that if you needed multiple elements you needed multiple attributes as well. To keep with the previous behavior, this is still the case for single-element attributes. For dynamic attributes with multiple elements, every element will now be returned in the API as [attribute-name]-[element-name].

<?php
$usr_conf['ATTRIBUTE_TYPES'] = [
    'limited_edition' => [
        'desc' => 'Limited Edition',
        'group' => 'product',
        'readonly' => false,
        'elements' => [
            'bool' => ['desc' => 'Limited Edition', 'type' => 'boolean',
                'options' => [['0','No'],['1','Yes']]
            ],
        ],
    ],
    'promo' => [
        'desc' => 'Promotion',
        'group' => 'product',
        'readonly' => false,
        'elements' => [
            'sale' => ['desc' => 'Sale', 'type' => 'boolean',
                'options' => [['0','No'],['1','Yes']]],
            'preorder' => ['desc' => 'Pre-order', 'type' => 'boolean',
                'options' => [['0','No'],['1','Yes']]]
        ],
    ],
];

These will show up on the product directly with a Yes / No-option:

And in the API, it will show up like this:

...
"limited_edition_bool": "1",
"promo_sale": "1",
"promo_preorder": "1",
...

Please note that when the option you've selected is 0/false the property will not show up in the API at all.

Attribute groups

The group on the attribute inside the config.php specifies where the attribute should be placed. The following groups exist today:

Group Description
product Listed under General Attributes on all Products.
variation Listed under each Variant on all Products.
order Listed on each Order.
customer Listed under each Customer.
account Listed under each Account (B2B).
sizechart Listed under each size in a sizechart.

Attribute element types

Element-type is inside the elements-property for the attribute config.php:

<?php
$usr_conf['ATTRIBUTE_TYPES'] = [
    'limited_edition' => [
        'desc' => 'This is the attribute',
        'group' => 'product',
        'elements' => [
            'text' => ['desc' => 'This is the element-type', 'type' => 'boolean',
                'options' => [['0','No'],['1','Yes']]
            ],
        ],
    ],
];

The following element types exist today. Not all of them are supported for the Dynamic attributes (which are shown inline on each product/variant), so the support for the different options are listed below:

Type Look Support Options
input Mapped/Dynamic Set class of the input (double the size of the input): 'class' => 'double'
textarea Mapped/Dynamic Set class of the textarea: 'class' => 'double'
readonly Dynamic Allows a field without the ability to edit it. Used for showing up IDs or things that should not be changed.
boolean Mapped/Dynamic Options for the radio inputs (default is always 0): 'options' => [['0','No'],['1','Yes']]
select Mapped/Dynamic Default selected is always first option, so keep it as ['0','Select']
image Mapped Size of the image: 'size' => '600x400'. Allowed image formats: JPG, JPEG, PNG, GIF, SVG
file Mapped No options available

Attributes with multi-select value

Selectable mapped attributes can be configured so that multiple values can be selected at once. This is achieved by adding parameter 'multi' => true to the attribute. For example, a multi-choice Label attribute can be configured like this:

'label' => [
    'desc' => 'Label',
    'group' => 'variation',
    'readonly' => true,
    'multi' => true,
    'elements' => [
        'value' => [
            'desc' => 'Label description',
            'type' => 'text'
        ],
    ],
],

In Centra, the attribute will look like this:

Its values will be returned as an object in API response:

"label": {
    "3": "Eco",
    "1": "Bio"
 },

API-output

The API-output differs between Dynamic and Mapped attributes.

Mapped attributes will always have a parent element named as the attribute-key. This is how the elements look like from the mapped attributes:

<?php
$usr_conf['ATTRIBUTE_TYPES'] = [
    'attribute_field' => [
        'desc' => 'This is the attribute',
        'group' => 'product',
        'readonly' => true,
        'elements' => [
            'text' => ['desc' => 'Text', 'type' => 'input'],
            'textarea' => ['desc' => 'Textarea', 'type' => 'textarea'],
            'boolean' => ['desc' => 'Boolean', 'type' => 'boolean',
                'options' => [['0','No'],['1','Yes']]
            ],
            'select' => ['desc' => 'Select', 'type' => 'select',
                'options' => [['0','Select'],['aa','AA'],['bb','BB']]
            ],
            'image' => ['desc' => 'Image', 'type' => 'image', 'size' => '600x400'],
            'file' => ['desc' => 'File', 'type' => 'file']
        ],
    ],
];

This is how the response from the API looks like:

{
    "attribute_field": {
        "text": "Text",
        "textarea": "Textarea",
        "boolean": "1",
        "select": "bb",
        "image": {
            "type": "image",
            "url": "https://.../client/dynamic/attributes/image1_4265_png.jpg",
            "width": "600",
            "height": "400",
            "mimeType": "image/jpeg"
        },
        "file": {
            "type": "file",
            "url": "https://.../client/dynamic/attributes/6/image1.png"
        }
    }
}

Dynamic attributes however, will be listed inline on the product inside the API.

Remember that only the element with the key text will be shown and only if the value is not 0/false.

<?php
$usr_conf['ATTRIBUTE_TYPES'] = [
    'attribute_name' => [
        'desc' => 'This is the attribute',
        'group' => 'product',
        'readonly' => false,
        'elements' => [
            'text' => ['desc' => 'Text', 'type' => 'input'],
        ],
    ],
];

This is how it looks like in the API:

{
    "attribute_name": "This is the text"
}

The dynamic attribute element types supported are all returning simple strings, so they look the same as per above.

Examples

We recommend using snake_case for all your custom attributes API names. Since Centra uses camelCase, and all the values are mixed up in the API responses, it's helpful to be able to immediately tell which attributes are custom, which also prevents the risk of accidentaly re-using already existing attribute name key.

Product care instructions

A multi-line dynamic text field for entering additional information about the Product. Can also be set up on the Variant level (group => variation).

'pr_care_instructions' => [
    'desc' => 'Product Care Instructions',
    'group' => 'product',
    'readonly' => false,
    'elements' => [
        'text' => [
            'desc' => 'Product Care Instructions',
            'type' => 'textarea'
        ]
    ]
]

This displays like this:

Product category video

File upload is easy to manage for a limited number of videos.

'pr_cat_video' => [
    'desc' => 'Product Category Video',
    'group' => 'product',
    'readonly' => true,
    'elements' => [
        'file' => [
            'desc' => 'Category video',
            'type' => 'file'
        ]
    ]
]

After you add and upload the video files in Catalog -> Attributes, you will see the list of options in the Product page:
ProductCategoryVideo

Product video

When the amount of videos is un-manageable, like one video per product, it might be better to use a dynamic input field to store video URL instead of a file

'pr_video' => [
    'desc' => 'Product Video',
    'group' => 'product',
    'readonly' => false,
    'elements' => [
        'url' => [
            'desc' => 'Product Video URL',
            'type' => 'input'
        ]
    ]
]

This will look like this in the Product page:
ProductVideoURL

Dangerous goods

Required for some products at customs. Might differ between product categories and shipping countries.

'pr_dangerous' => [
    'desc' => 'Dangerous goods',
    'group' => 'product',
    'readonly' => false,
    'elements' => [
        'value' => [
            'desc' => 'Dangerous goods code',
            'type' => 'input'
        ]
    ]
]

It renders as a simple input field in the UI:
DangerousGoods

Showroom swatch

Remember, Variant-level attribute use group variation, not variant.

'sh_swatch' => [
    'desc' => 'Showroom Color Swatch',
    'group' => 'variation',
    'readonly' => true,
    'elements' => [
        'desc' => [
            'desc' => 'Color',
            'type' => 'input'
        ],
        'hex' => [
            'desc' => 'Hex',
            'type' => 'input'
        ],
        'image' => [
            'desc' => 'Image',
            'type' => 'image',
            'size' => '50x50'
        ]
    ]
]

Swatch definitions need to be configured in Catalog -> Attributes:
ShowroomSwatch2

...and then selected on the Variant page:
ShowroomSwatch1

Promotion yes/no

Booleans are normally dynamic, not pre-defined. Remember, default value(s) (index 0) will not be returned in the API.

'var_promo' => [
    'desc' => 'Promotion',
    'group' => 'variation',
    'readonly' => false,
    'elements' => [
        'sale' => [
            'desc' => 'Sale',
            'type' => 'boolean',
            'options' => [['0','No'],['1','Yes']]
        ],
        'preorder' => [
            'desc' => 'Pre-order',
            'type' => 'boolean',
            'options' => [['0','No'],['1','Yes']]
        ]
    ]
]

PromotionYesNo

Product gender

The difference between this and Static attribute is that the select options cannot be adjusted/expanded without a code change.

Please notice, the keys are enums, not integers. It's ['0','Select'], not [0,'Select'].

'pr_gender' => [
    'desc' => 'Product gender',
    'group' => 'product',
    'readonly' => false,
    'elements' => [
        'value' => [
            'desc' => 'Product gender',
            'type' => 'select',
            'options' => [['0','Select'],['fem','Female'],['male','Male'],['unisex','Unisex']],
        ]
    ]
]

The select then looks like this in the UI:
ProductGender

Product material - multi-select

For attributes which are pre-defined, multiple values can be made selectable at once.

'pr_material' => [
    'desc' => 'Product material(s)',
    'group' => 'product',
    'readonly' => true,
    'multi' => true,
    'elements' => [
        'name' => [
            'desc' => 'Material name',
            'type' => 'input'
        ],
        'description' => [
            'desc' => 'Material description',
            'type' => 'textarea'
        ]
    ]
]

Multi-select snippet looks like this in Centra:
ProductMaterialMulti

Double-sized input field

With element class: double you can make your text fields (both input and textarea) twice as wide, so they take up the entire row. For example:

'pr_long_name' => [
    'desc' => 'Long Product Name',
    'group' => 'product',
    'readonly' => false,
    'elements' => [
        'text' => [
            'desc' => 'Long Product Name',
            'type' => 'input',
            'class' => 'double'
        ]
    ]
]

...is displayed like this:
InputClassDouble