Creating Products - Part 1

Managing Product Categories

Introduction

In a previous post and follow-up, I provided some background on using Liferay's Batch APIs to import products. I realize that for anyone that is new to Liferay's commerce capabilities this might be a little like trying to run before you walk so in this series of posts I am going to take a step back and walk through the process of creating and importing products in a little more detail.  

We're going to walk through the process step-by-step, using the Minium B2B store. If you want to follow along you'll need a relatively recent release of Liferay Portal or Liferay DXP (7.4+) and you'll want to create a new site with the Minium Accelerator. If you're new to working with Accelerators, take a look at the Accelerators article on learn.liferay.com to get started.

First Things First

Before we get to the products themselves, we need to do a little ground work to ensure an optimal experience for our customers. Some of these steps could be skipped and the data could be created while importing products, but if you do that you won't always have access to the same configuration options that you would have by addressing each item, one at a time.

So what types of preliminary work needs to be done and what's the payoff? Well, by defining data structures such as categories and specifications up front you'll be able to include those details in the product import in a single call. Additionally, you'll be able to create category based navigation experiences in your storefront and provide the ability to filter products by specification values. We'll also be creating Options and importing Product Images.  

Categories

First, let's start with categories since they are such a critical part of most commerce experiences. Could you imagine shopping for clothes online and not being able to specify if you were browsing for men's or women's clothing?, or if you looking for tops or bottoms? Whether it's part of the navigation or a filter you use on search results, proper categorization is essential.

I won't go through all aspects of working with categories and vocabularies in Liferay, we have some very good documentation that covers the basics (e.g. Defining Categories and Vocabularies), but I will point out a couple of things that are relevant when working with Liferay's commerce features.

First, when we initially introduced Liferay Commerce as a new product, we also introduced some enhancements to categories that were available after the Commerce modules were deployed.  Now that Liferay Commerce has been fully merged into Liferay DXP, these features are available to everyone, but many people don't know about them.  Categories in Liferay now support both configurable friendly URLs and images. Both of these are really useful when building out a storefront that's both easy to navigate and optimized for SEO.

Secondly, because Commerce products are not scoped to a single site, the categories can't be scoped to a single site either, they must be created in the Global scope in order to work with Commerce features such as category navigation and category filtering of Products.

For this extended example, we're going to be introducing shop clothing as new line of products for our Minium automotive store. It is possible that you might want to create a new Vocabulary for clothing, but we're going to keep it simple and just add a new top level category called Shop Wear in the existing Minium vocabulary that was defined when we ran the Minium Accelerator.

Introducing the Taxonomy API

To create categories at scale or based on data in another system, such as a PIM or ERP, you'll want to take advantage of Liferay's Headless APIs to create and manage vocabularies and categories.  To get started, ensure you are logged in as an Administrator and navigate to the Liferay API Explorer (e.g. http://localhost:8080/o/api).  

Looking through the different applications listed under the REST Applications it might not be immediately clear which application you should use because there is no mention of vocabulary or category.  Instead they are available under the /headless-admin-taxonomy/v1.0 application.  Once that application is selected you'll see that we have options to manage vocabularies (TaxonomyVocabulary), categories (TaxonomyCategory), and tags (Keyword).  

Taking a closer look at the TaxonomyCategory endpoints you'll see several options for creating new categories, but the one that's most promising for us is the /headless-admin-taxonomy/v1.0/taxonomy-vocabularies/{vocabularyId}/taxonomy-categories endpoint.  To use this API we'll need to know the Vocabulary ID for the Minium vocabulary. You can get this through the UI by navigating to the Categorization -> Categories menu in the Global site (http://localhost:8080/group/global/~/control_panel/manage/-/categories_admin/vocabularies) and then selecting the Minium category. The vocabularyId will be the last part of the URL.

If you were trying to get the vocabularyId programmatically from another system you could use the Headless APIs to GET a list of all vocabularies using the /headless-admin-taxonomy/v1.0/sites/{siteId}/taxonomy-vocabularies endpoint, but don't forget you'll need to use the siteId for the Global site.

With the Minium vocabularyId in hand, we can now create the JSON payload we'll need to POST to our endpoint.  Whenever I need to create a JSON payload for Liferay's API I always start by sending a GET to the same endpoint and then examining one of the items that's returned.  You can remove the actions and creator sections and also any id or date that Liferay will determine during the import.  If we strip away what's not needed, we'll end up with the following payload:   

{
  "description": "The ultimate in comfort and durability for an affordable price",
  "description_i18n": {
    "en_US": "The ultimate in comfort and durability for an affordable price.",
    "es_ES": "Lo último en comodidad y durabilidad a un precio asequible."
  },
  "externalReferenceCode": "EXT-CATEGORY-SHOP-WEAR",
  "name":"Shop Wear",
  "name_i18n": {
    "en_US": "Shop Wear",
    "es_ES": "Ropa de Tienda"
  }
}

Note that there is currently a gap in the the headless APIs and they don't support the newer commerce related features so if you want to set a specific friendly URL and associate one or more images to your category you'll need to do that through the UI. There are Feature Requests open for managing both images (LPD-33004) and friendly URLs (LPD-33005) through the APIs so hopefully this gap will soon be closed.

The good news is that for this example, Liferay will automatically provide a localized friendly URL that makes sense (e.g. /shop-wear and /ropa-de-tiena) but if you wanted more control you could update it through the UI.

Lastly, let's go ahead and add an image to the category. This is not required, but later we're going to create a category navigation page where each category will have a card that displays the category name, description, and image if available so let's take care of the image now. Until LPD-33004 gets addressed, we'll have no choice to but to do this bit through the UI so let's navigate to the Global Site and then in the left hand menu select Categorization → Categories. Next, under the Global Vocabularies, select Minium and then click the kebab menu next to our Shop Wear category and select Edit.

Tip: If you're trying to edit a category and there is no kebab menu, double check what site you are in. The Global Vocabularies and Categories will show up in all sites, but are only editable when you are in the Global site. If you see a little lock icon next to the Vocabulary name, you're in the wrong site.

From here, you can navigate to the Images tab and click the New button to upload an image. Feel free to grab any image you have handy, or grab an appropriate image from a site like Unsplash or Pexels.

While I'm in here, I'm also going to add images for the rest of the Minium categories. To make life easier, I'll use the Category images provided with the Speedwell Accelerator: Brake System, Engine, Exhaust System, Suspension, Transmission, and Turbocharger.

One More Thing...

As my good friend José María Muñoz likes to say, one more thing before we wrap up the topic of categories and that's to share a little known feature called Properties. Properties are just name/value pairs of data that can be accessed programmatically through services and Headless APIs. These can be really useful if we are integrating with an external system that is providing additional data that we need to store in Liferay or perhaps we need a place to store extra data that might need to be displayed about a Category or for storing data that might impact if a category should be displayed or hidden or if it should be displayed in a different way (e.g. featuredCategory = true).

Properties can be set through the UI or they can also be set through the Headless APIs. To do that, I'll update my earlier JSON to include some properties.

{
  "description": "The ultimate in comfort and durability for an affordable price",
  "description_i18n": {
    "en_US": "The ultimate in comfort and durability for an affordable price.",
    "es_ES": "Lo último en comodidad y durabilidad a un precio asequible."
  },
  "externalReferenceCode": "EXT-CATEGORY-SHOP-WEAR",
  "name":"Shop Wear",
  "name_i18n": {
    "en_US": "Shop Wear",
    "es_ES": "Ropa de Tienda"
  },
  "taxonomyCategoryProperties": [
    {
      "key": "featuredCategory",
      "value": "false"
    },
    {
      "key": "newCategory",
      "value": "true"
    }
  ]
}

If you've already created the category and just want to update the property values, the Taxonomy endpoints support the PATCH operation so you could also PATCH the following to the /headless-admin-taxonomy/v1.0/taxonomy-categories/{categoryId} endpoint:  

{
  "externalReferenceCode": "EXT-CATEGORY-SHOP-WEAR",
  "taxonomyCategoryProperties": [
    {
      "key": "featuredCategory",
      "value": "false"
    },
    {
      "key": "newCategory",
      "value": "true"
    }
  ]
}

Conclusion

And with that, we've reached the end of part 1. Even if we haven't actually touched any products yet I still think we accomplished quite a bit. We now know how to create and manage categories through the UI and through our Headless API. We also know how to get the most out of categories by using some more advanced aspects of categories such as configurable friendly URLs, category images, and category properties.

In our next post, we will continue laying the ground work for adding our new products by learning how to work with Specifications and Specification Groups.