Like most modern ecommerce platforms, commercetools allows merchants to define their own custom product types, along with attributes that help distinguish these types.
In this post, we’re going to detail the steps for creating product types and attributes in commercetools using the REST API.
But First
Before we talk about how to create custom types and attributes, it’s important to understand some commercetools terminology:
- Product Type – A set of attributes that define a template for all products of that type
- Product Attribute – A field that can be associated with a product type
- Product Attribute Type – The data type of an attribute (e.g. string, boolean, date, etc.)
- Product – An instance of a product type (i.e. an actual product that a merchant would sell)
- Product Variant – One instance of a particular product that shares many common attributes with other variants of the product but has a few attributes that are unique to the variant (e.g. men’s shoes might be a product but specific sizes might be variants of a shoe)
When thinking about how to model products in commercetools, a merchant should consider the following important points:
- Having few product types with many attributes can impact performance of the site. Why? When products are returned to the client, all the associated attributed is returned. This can make API responses heavier than necessary since certain views of an ecommerce store may only need to render some of the attributes. Ideally, there would be more product types with fewer attributes. Think about it this way, if you sell shirts, socks and jewelry but only have one product type for all three, you’ll return empty attributes for jewelry that would only apply to shirts and socks.
- When a new product is created, a product type must be selected for that product. Once created, the product type cannot be changed later
- You can use product attributes to help represent products in different ways in your store, but it may be advantageous to instead use product categories to accomplish this.
- You can add product attributes at any time to a product type. You can also remove them but note that any existing products with values for these attributes will have those values removed. This deletion cannot be undone.
Merchants also need to think carefully about product variants during their initial modeling:
- Product URL slugs, display names and search keywords all exist at the product level, not the product variant. This is particularly important in the context of Search Engine Optimization (SEO). If a product variant needs to have its own SEO juice it may make more sense to model this as a product not a variant.
- For commercetools search, product names are weighted 6 times more than other product attributes. So, if there’s a particular variant that should appear in search over other variants, it may be worth modeling as a separate product.
- All variants of a product share the same tax category. In some situations, this may be undesirable. Again, this may be a situation where variants aren’t optimal.
Creating a New Product Type with Custom Attributes
Now that we’ve laid the groundwork for product types, attributes and products, let’s talk about how to create them with commercetools. In true headless fashion, all of this is done using the commercetools REST API.
The product type creation endpoint takes the format of:
{{host}}/{{project-key}}/product-types
By sending a POST request to the commercetools API with the above endpoint (substitute your commercetools hostname and project key, accordingly) and the correct body schema, a new product type will be defined in your store.
At a minimum, the body requires the following elements:
- name – Name of the product type; this will be displayed in the commercetools admin when creating new/searching for products
- description – A user-friendly description for the product type (also shown in the commercetools admin)
- attributes – an array of product attribute definitions. See below for details
An additional element named “key” can be included in the payload. This is a unique identifier for the product type (e.g. “argondigital-producttype-industrial-filter”). This is very useful if, in the future, you’ll need to programmatically access your product types.
Product types wouldn’t be very interesting without attributes. As mentioned above, these are defined as an array in the POST payload. Each attribute defined has the following required elements in the JSON payload:
- name – A unique identifier for the product attribute. Note: this is unique across all product type definitions!
- type – The data type for the attribute. For example, you may have an attribute that’s represented as a boolean or you may have a numeric data type. For the full list of data types, see https://docs.commercetools.com/api/projects/productTypes#attributetype
- label – A user-friendly label for the product attribute
- isRequired – Indicates whether or not a value is required for the attribute when creating a product
- attributeConstraint – Indicates how an attribute can be set across product variants
- inputHint – Can be used by UIs to determine how to render input fields for the attribute. By default, the commercetools admin UI only considers this for text-based attributes
- isSearchable – Determines whether or not the attribute should be stored in the search index for full-text and faceted searching
When defining product attributes, consider the following:
- Attributes of the “enum” type must have a corresponding “values” array. Each value specified must have a “key” and “label” attribute. The key is unique and the label is a user-friendly label for that item. If you render an enum in a dropdown, users will see the “label” for each item but the actual value set of the product attribute is the corresponding key.
- Carefully think through which attributes really need to be searchable. Indicating “true” for isSearchable on all attributes can have a negative impact on site performance.
- Attribute labels, as well as enum values, can be localized.
- attributeConstraint took some getting used to. This really applies to how a value is set for either the product or each variant of the product. If you know an attribute value will be the same for all variants, the value specified for attributeConstraint should be “SameForAll”. If your variants have truly unique values for this type of attribute, the value for attributeConstraint should be “CombinationUnique”.
- It is possible to nest product type attributes – we won’t be covering that in this post.
Full documentation around product type attributes can be found here.
Here’s a complete example of a POST payload for creating a new product type:
{
"name": "ArgonDigital Product Type - Industrial Filter",
"description": "Custom product type that has properties specific to industrial filters.",
"key": "argondigital-producttype-industrial-filter",
"attributes": [
{
"type":
{
"name": "enum",
"values": [
{
"key": "pleated_media",
"label": "Pleated Media"
},
{
"key": "panel_filter",
"label": "Panel Filter"
},
{
"key": "oils_and_lubricants",
"label": "Oils and Lubricants"
}]
},
"isSearchable": true,
"inputHint": "SingleLine",
"name": "filter_type",
"label":
{
"en": "Filter Type"
},
"isRequired": true,
"attributeConstraint": "None"
},
{
"type":
{
"name": "text"
},
"isSearchable": false,
"inputHint": "SingleLine",
"name": "operating_temperature_range",
"label":
{
"en": "Operating Temperature Range"
},
"isRequired": false,
"attributeConstraint": "None"
},
{
"type":
{
"name": "number"
},
"isSearchable": false,
"inputHint": "SingleLine",
"name": "outer_dimension",
"label":
{
"en": "Outer Dimension"
},
"isRequired": true,
"attributeConstraint": "None"
},
{
"type":
{
"name": "text"
},
"isSearchable": true,
"inputHint": "MultiLine",
"name": "notes",
"label":
{
"en": "Product Notes"
},
"isRequired": false,
"attributeConstraint": "None"
}]
}
Updating an Existing Product Type
What if you’ve already got a product type defined but need to alter the type definition and/or attributes? No problem – the commercetools API fully supports an update to existing product types.
There are two ways to update an existing type:
- By the “key” you specified for the product type. The format of this request would use this pattern – {{host}}/{{project-key}}/product-types/key={{product-type-key}}
- By the unique ID that commercetools generated for your product type when you first created it. The format of this request would use this pattern – {{host}}/{{project-key}}/product-types/{{product-type-id}}
Both of these methods require a POST request to the corresponding endpoint.
You may be wondering why commercetools isn’t using a PUT request to update a product type. Updates can be complex and there are a handful of different operations you may want to perform on the product type. As such, a proper PUT endpoint wouldn’t really make sense, particularly if you’re only changing a single aspect of the type with your request. Why should you need to PUT all of the product type elements in order to change one component of the type?
So, how do you indicate what you want to change on the type? This is done using an array of “actions” that are included in the POST payload.
In the following example, we’re changing the description of an existing product type using the endpoint:
{{host}}/{{project-key}}/product-types/key=argondigital-producttype-industrial-filter
{
"version" : 1,
"actions" : [ {
"action" : "changeDescription",
"description" : "This is a new description for this product type that we're updating via the update product type endpoint."
} ]
}
The “changeDescription” action is they key element here. This tells commercetools that we’re expecting to update the description field for the specified product type.
Note: it is possible to make more than one update at a time for a given product type simply by including multiple “action” items in the “actions” array.
For a full list of the possible actions, refer to – https://docs.commercetools.com/api/projects/productTypes#update-actions
It’s also worth noting the “version” element that’s included in the payload. This is a required element any time an update request is made. The version number used should match the current version of the product type definition. Note: if you didn’t specify a version when creating the product type, commercetools will assign “1” as the version.
A few notes about updating product types:
- You *must* specify the current version of the product type in the payload when making an update to an existing product type definition. If you don’t supply this or if there’s a mismatch between the version supplied and the version in the catalog, an error will be thrown and the product type definition will not be updated.
- commercetools will automatically increment the version of the product type when making updates.
- You cannot change the data type for an existing attribute.
Wrapping Up
The product modeling process in commercetools can take some getting used to, particularly if you’re used to creating new product types and attributes using an admin GUI, as is the case in many other modern ecommerce platforms
However, what commercetools lacks in terms of usability for managing product types it more than makes up for in the flexibility and power of its product definition capabilities. By leveraging product types, attributes and variants, merchants can model any type of product to be sold. Whether it’s a simple physical product, a digital download, or a highly complex set of configurable product variants, commercetools is up for the job.
This post is one in a series of posts that we’re writing about commercetools. If you have any questions about commercetools as a platform, modeling products and attributes or would like to discuss any other ecommerce challenges you might be facing, feel free to drop us a line. We’d love to chat!