Creating Products - Part 2

Managing Product Specifications

Introduction

Welcome back to the second part of our series about creating and importing products with Liferay.  In the previous post, we talked about getting started with the Minium accelerator and then created our categories.  In this post we're going to take a closer look at setting up specifications prior to importing our products. 

When we talk about specifications, we're talking about product attributes or qualities that help to define or describe the product and that are intrinsic to the product. Changing these attributes would typically mean that we're talking about a different product. Some good examples of this would be the material that a product is made from, the physical dimensions of the product or the country of origin.

Providing sufficient attributes in our store front makes it easier for customers to find the right product and ensure the proper fit. Specifications are indexed so they can make it easier to search for products using product attributes as part of your search terms.  Liferay also provides an out-of-the-box Specification Facet widget which allows you to refine your search results to just those products that meet your needs. And finally, I am sure have probably all had a need to compare two  similar products to determine which is the right choice. Those product comparison experiences typically display product specifications side-by-side so you can compare and contrast multiple products at once.  

When working with more complicated products, it's easy to have a lot of specifications, so Liferay also provides you with specification groups that allow you to group similar specifications together. These specification groups are used by the out-of-the-box search facets and product renderers and Liferay provides APIs to retrieve specifications by group so you can also create your own experiences. A good example of a specification group might be dimension which could be used to group the length, width, and depth specifications.

Specifications or Categories?

Before we get into creating our specifications and specification groups, I'd like to address a common question that comes up when introducing specifications. Why should we use specifications for some product attributes and not categories? For example, we could create a vocabulary for all of the possible materials or countries of origin and when creating products you could just select the right category. Wouldn't that work? Well yes, it would and in some cases it might not be a bad idea so let's take a deeper look.  

So what are the advantages of using specifications for product attributes? First, specification values support free-form text, so as you create or import new products with new values you can easily enter those values without the need for any help from an administrator to first create a category.  This is also useful for specifications where there might be really high number of values that would be unwieldy to manage as categories.   Another advantage with specifications is that the UI is purpose built to leverage specifications.  For example, they are automatically displayed when viewing products on a Product Display Page (PDP) in Liferay or when comparing products with the Product Comparison Table widget.  Both of these experiences can be extended with your own implementation,  so you could get the category values to display, but it requires a little bit more work.  And if you're using specifications for some things and categories for others it's going to take even more work to blend those two together if required for your UI.  Lastly, I personally think it's easer to add and manage specifications when managing products through the backend, especially when there are a lot of different specifications to manage.  If all of the data is coming from an external systems such as a PIM or ERP, this might not be a concern but if you're going to manage this data in Liferay, it is something you should consider.  

So then, what are the advantages of using categories for product attributes? For one thing, categories are cross cutting and can be used to describe more than just products. You could use the same vocabulary to organize any type of content. Categories are also fixed which means you can't create a new one while creating a new product. While this might be a negative in some situations it also means you won't end up with a products that are categorized using aluminum and others categorized as aluminium.  Also, while the UI for Product Details and Product Comparison don't expose categories by default Liferay does provide a category navigation mechanism which makes it really easy to build category based navigation and listing pages.  

So which one should you use? In the end it's really going to depend on the specifics of your use case and your products.  And in some cases, the right approach just might be to use both.  For example if the material that a product is made from is a really important factor to selecting the right product, then it might make sense to have a vocabulary for material and then build a category navigation into your storefront so that customers can navigate their way to the right products based on the material.  It also wouldn't hurt to have material also listed as a specification, so if they find a couple of similar products, they can easily do a side-by-side comparison and easily see material listed along side the rest of the product specifications.  

Note:  In the 2024Q3 release you will be able to define Specification values with Picklists, so you no longer have to worry about typos or inconsistency when defining Specifications.  https://learn.liferay.com/w/commerce/product-management/creating-and-managing-products/products/using-specifications-with-picklists

Creating or Importing Specification Groups

Alright, now that we have a better understanding of specifications, let's start our setup by addressing the specification groups. We are starting with specification groups because when you define a new specification you can assign it to a default specification group so it's best to have the specification groups already defined and available before you import the specifications. Specification groups are a really simple data model with only a few fields to fill out. If we're working through the UI, you'll access specification groups through the Commerce > Product Management > Specifications widget and then selecting the Specification Group tab.

To define our specification group we can provide a localizable title and description, a numeric priority, and a key which must be a unique identifier. The priority is used for sorting with the smaller numbered priority appearing first and you can use decimals if you need to squeeze new specification group between two existing groups. The key is an alphanumeric field which can't contain any spaces. If you are creating the specification group through the UI, the Key is automatically created as you type the Title, but it can always be overridden if necessary. Unlike many of the other data models we'll be talking about during this series, there is no External Reference Code or ERC for either specification groups or specifications so the Key value is what we'll need to use to make sure we're uniquely identifying data if we're integrating with an external system.

If you are integrating with an external system and need to create or maintain Specification Groups through the API, Liferay provides several convenient endpoints to do so. Unfortunately, they aren't very conveniently named and you'll find them in API Explorer in the headless-commerce-admin-catalog/v1.0 application under a section called OptionCategory


Looking through the available endpoints we can see there are a couple options to POST a new specification group.  If we just have one to create we can use the /v1.0/optionCategories/ endpoint.  If we have many, then using the /v1.0/optionCategories/batch endpoint. For our shop wear example, we only have one new specification group called Fabric Details, so we'll use the former.  

To understand what we need our payload to look like, I always like to use the API Explorer and use the GET on the same endpoint that I am working with.  In the response, there will be a JSON array of items that were created by the Minium accelerator and from that array I will pick one as an example to  to examine:  

{
  "description": {},
  "id": 32888,
  "key": "quantity",
  "priority": 0,
  "title": {
    "en_US": "Quantity"
  }
}

In this case, the only field we'd need to remove would be the id which will be provided by Liferay upon a successful import.  We're also not going to be using description so I'll omit it for now. So using the API Explore we can post the following payload  to create our new specification group:  

{
  "key": "fabric-details",
  "priority": 10,
  "title": {
    "en_US": "Fabric Details",
    "es_ES": "Detalles de la Tela"
  }
}

Creating or Importing Specifications

With our specification groups defined, we can now start define any new specifications that are needed for our shop wear line of products.  Just like the specification group, the specifications are also a very simple data model with many of the same fields.  Working through the UI, we're going to use the same Specification widget (Commerce > Product Management > Specifications), but now we'll be working through the Specification Labels tab.  

To define our specification label we provide a localizable label and description, a numeric priority, and a key.  These are very similar to what we've seen with specification group.  Additionally, we have the option to indicate if this specification label should be used in the Specification Facet widget and with which specification group it should be listed. 

Just like before, with the specification group, we can also create and manage these values through our headless APIs.  And I know what you're probably already thinking.  If the specification group is found in the headless-commerce-admin-catalog/v1.0 application under a section called OptionCategory, then the specification must be found under a section called Option, right? Well, not quite they are actually found in a section called Specifications ¯\_(ツ)_/¯


And by now, you can probably guess that we could POST to the /v1.0/specifications endpoint to create new specification labels one at a time or we could use the /v1.0/specifications/batch endpoint to create specification labels en masse.   

A quick GET to the /v1.0/specifications endpoint provides us with an array of items from which we can extract one to examine in order to determine what our payload should look like.    

{
      "description": {},
      "facetable": false,
      "id": 32893,
      "key": "quantity",
      "optionCategory": {
        "description": {},
        "id": 32888,
        "key": "quantity",
        "priority": 0,
        "title": {
          "en_US": "Quantity"
        }
      },
      "priority": 0,
      "title": {
        "en_US": "Quantity"
      }
    }

We can again remove the id field when creating our payload since Liferay will generate that when we import.  We can also omit the description as we're not going to use a description for specification label in our design.  The optionCategory is a little tricky because you might think you could just provide the key or id values, but with a little trial and error will find you need the id, the key and at least the empty title object.  

​In this case, let's use the batch end point so we can create a few different specification labels related to fabric details.  We'll use fabric type label to track if the garment is made of cotton, polyester, or perhaps a blend of different types and we'll use care instructions to track how the garment should be laundered.  In the case of fabric type, we'll want to make sure that this is included in the Specification Facet widget, because it is likely that someone might have a need to filter products based on the type and there probably won't be too many different variations.  However, for the care instructions we will exclude them from the Specification Facet Widget.  They are important and should be displayed on the product detail page, but probably aren't something that you would use to filter products.  Also, with different products possibly coming from different suppliers it's possible that there might be a lot of very similar care instructions with only slight differences which would be overwhelming in a Specification Facet.  With this in mind, we can POST the following payload to the /v1.0/specifications/batch endpoint: 

[
  {
    "facetable": true,
    "key": "fabric-type",
    "optionCategory": {
      "id": 37323,
      "key": "fabric-details",
      "title": {}
    },
    "priority": 10,
    "title": {
      "en_US": "Fabric Type",
      "es_ES": "Tipo de tela"
    }
  },
  {
    "facetable": false,
    "key": "care-instruction",
    "optionCategory": {
      "id": 37323,
      "key": "fabric-details",
      "title": {}
    },
    "priority": 20,
    "title": {
      "en_US": "Care Instructions",
      "es_ES": "Instrucciones de cuidado"
    }
  }
]

It's important to note that while it's possible to create Specifications "on-the-fly" as Products are being created through the UI or the API. However, if you do so, you won't have the ability to set some of the default values like the priority or if the specification should be used for faceted search.

One More Thing...

And of course, before we wrap things up I have one more thing that might be useful to consider when working with specifications.  While they might seem simple, specifications actually support some more complex aspects of Liferay assets such as custom fields on both the specification label and on the specification value that's specific to a product. 

Custom fields on a specification label might be useful  if you have some specifications that should only display in certain situations (e.g. printOnly, displayDetailView, displaySummaryView). You could extend the specification label data model with a flag that could be checked in the Product Detail widget or the Product Comparison Table widget.  And, all Custom Fields are automatically included in our headless APIs so the data would also be available to any external system or view that's consuming our headless APIs. 

An interesting use case for extending specification values with custom fields is the ability to provide SKU specific specification values.  By default the specification values are defined at the product level and they are shared by all SKUs.  Liferay allows you to have multiple specification entries with the same specification label on a single product so you could use a custom field to associate each of the specification entries with a specific SKU and then you would just need to provide your own  Product Detail template to show the right specification based on the selected SKU.  

Conclusion

So that wraps up our second installment and we're a little bit closer to actually importing products.  I know that was a pretty long post so thanks for sticking around.  Hopefully you have a deeper understanding of the benefits you get from properly using Liferay product specifications.  You should also know how to create and manage both specifications and specification groups and import that data from an external system.  And lastly you should know how and when to extend the out-of-the-box data model for specifications.  

Next time we're going to take a closer look at a somewhat related concept, product options.  With product options you can not only support simple product variations such as size or color, but you can also support more complex use cases such as customizable products and configurable product bundles.