Separate your product catalog from commerce.
"Do you know what sets us apart from our competitors?" This is our usual opener when we introduce Commerce Layer. "Well, we believe that the product catalog shouldn't just 'live' next to the commerce engine." A pause follows, often filled with intrigued looks. "Ehm, huh?!" And that's where our conversation begins.
This approach may seem unconventional when thinking about the traditional commerce data model. Yet, it's not the first time the industry had to pivot the perspective on content. Recall the early 2010s, when everyone embraced "Headless" CMSs designed to feed Single Page Applications (SPAs) with APIs. This innovation required a mental shift: content authors were no longer creating pages; they were creating content. Now, let's extend this philosophy: Product is also content. Bear with me.
Content data vs. commerce logic
Imagine crafting a digital brochure focused solely on showcasing your products, without direct sales capabilities. I have personally always believed that products should be treated as any other content, housed within the CMS, unless a Product Information Management (PIM) system is necessary. In this case, we could make the argument that all product data is just content aimed directly at the end-user.
If we continue with this line of thinking, we can divide the data that comprise our digital experience into two broad categories: content data and commerce logic. Commerce logic encompasses the necessary details for performing operations around purchasing products and orders. In contrast, content data is purely for the end-user's experience.
This dichotomy underpins Commerce Layer's philosophy: separate the logic that is essential for order fulfillment from the content designed for the end-user experience. Logic data lives in the commerce engine. Content lives elsewhere, outside the commerce engine. This separation not only enhances data management, but also simplifies transforming our brochure into a fully-functional commerce platform by integrating the necessary logic data into Commerce Layer.
Delivery vs. transactional APIs
Another distinction that further supports the separation of data types is the difference between caching strategies.
- Content data gets fetched via a Delivery API, characterized by a heavy caching strategy to optimize performance over “freshness” of data.
- Data calculated by commerce logic, like the price, requires fast delivery of the latest version.
Commerce Layer utilizes a distinct caching strategy for commerce data combined to laser-focused payloads to ensure rapid delivery to the user.
Integrating your product catalog into your CMS
We’ve built a high growth, global business on this philosophy. Since day one, our founders Filippo and Massimo believe that Commerce Layer should focus on managing transactional data. And our growing list of customers all subscribe to our way. But the way to achieve this clean separation of content and commerce, specifically related to managing a product catalog associated with your SKUs, is not apparent to everyone. This is the motivation behind our CMS Commerce project: to define and share a product catalog content model that aligns with Commerce Layer's vision and can be easily adopted within a CMS.
We kickstarted this initiative with a content modeling session with Fabrizio Picca, Tom Smith from Sanity.io, and me. The idea was inspired by Filippo's insights on product catalogs. We focused on how to manage variant attributes versus product attributes. We also discussed the optimal way to store essential data like prices and SKUs.
The resulting content model is structured as follows:
- Catalog: A catalog is a collection of products, often tailored for different markets or seasons. It acts as a container for your product offerings, allowing for organization and easy management within a specific context.
- Taxonomy: A taxonomy is a hierarchical system for classifying and organizing content. It is used to group products into category systems, such as 'Audience' or 'Genre', which can then be broken down into more specific subcategories or taxons.
- Taxon: A taxon is an individual category within a taxonomy. Taxons can be nested, allowing you to create a detailed structure for product classification.
- Product: A product acts as a set of common information for its different variants. For example, consider a “Book” as our product. Its attributes might contain “Author”, “Description”, or “Publisher”.
- Variant: A variant is a specific version of a product, which might differ in size, color, or other attributes. Each variant is a unique combination of these attributes and is typically associated with a unique SKU. The variant is the actual product the merchant is selling. In the “Book” example, a variant could have a “Type” attribute, being “Hardcover”, “Paperback”, and “Digital”.
This model is dynamic. It allows for customization of certain content type names, indicated by the square brackets in the diagram, catering to different terminologies or preferences. For instance, "Taxonomy" and "Taxon" could be alternatively termed "Category System" and "Category" for those unfamiliar with the original nomenclature. Moreover, this flexibility empowers businesses to tailor their product catalogs to specific needs, such as distinguishing a “Book” product type with unique attributes like “Author”.
The app/plugin architecture
The architectural design for implementing this model across different CMS platforms was a collaborative effort between me and Fabrizio. After consulting with CMS experts and earning a Contentstack certification, we were ready to begin development. We initially focused on Sanity, Contentful, and Contentstack, each requiring a unique approach.
Sanity
Sanity’s overall experience is developer-centric. Much of its capabilities are extendable with an npm plugin-based architecture. They have an excellent tool to start creating plugins: the @sanity/plugin-kit. This npm package initializes a project to build a custom plugin and offers documentation on how to test it within a Sanity project.
After we prepared the plugin scaffolding, we had to
- Translate the content model to Sanity’s document types.
- Make the schema easily extendable. Remember we want product data to be tailored to the specific case, like “Book” vs. “Product”.
- Export TypeScript types to guarantee the configuration of the plugin was straight-forward.
We created a schema.ts
file, which leverages Sanity’s defineType
function to create the documents types, all wrapped in a getSchema(config: PluginConfiguration): SanityDocument[]
function.
The plugin configuration, which allows to extend schema information like how to name a “Product”, looks like this:
import { FieldDefinition } from 'sanity';
export type SanityCommercePluginConfig = {
productLabel?: string;
variantLabel?: string;
taxonomyLabel?: string;
taxonLabel?: string;
productAttributes?: FieldDefinition[];
variantAttributes?: FieldDefinition[];
};
Installation and usage
https://www.sanity.io/plugins/sanity-commerce
Use the plugin by installing it in your Sanity project root:
# use npm, pnpm, or yarn
pnpm install @commercelayer/sanity-plugin-commerce
Then add it to your sanity.config.ts
file:
import { defineConfig } from 'sanity';
import {
sanityCommerce,
SanityCommercePluginConfig,
} from '@commercelayer/sanity-plugin-commerce';
const sanityCommerceConfig: SanityCommercePluginConfig = {
// ...configure the plugin here.
};
export default defineConfig({
// ... other config settings.
plugins: [sanityCommerce(sanityCommerceConfig)],
});
Configuration
Let’s continue to use our “Book” product example as a reference. An example configuration for the plugin might look like this:
const sanityCommerceConfig: SanityCommercePluginConfig = {
productLabel: 'Book',
variantLabel: 'Book Variant',
taxonomyLabel: 'Category System',
taxonLabel: 'Category',
productAttributes: [
{
name: 'author',
title: 'Author',
type: 'string'
},
{
name: 'publisher',
title: 'Publisher',
type: 'string'
],
variantAttributes: [
{
name: 'type',
title: 'Type',
type: 'string',
options: {
list: [
{ title: 'Hardcover', value: 'hardcover' },
{ title: 'Paperback', value: 'paperback' },
{ title: 'Digital', value: 'digital' },
],
},
},
],
};
Hit save, and you will have the content model ready in your Sanity Studio, here used to populate the Book product catalog.
Contentful
Contentful’s platform is different from Sanity. It can be extended using custom applications that enhance different aspects of its UI. Contentful also has a great tool to boost our application development, using the Create Contentful App CLI. To keep it as simple as possible, we want the user to configure only a few fields and run the tool. Therefore, the configuration screen is the only view needed to build a product catalog in Contentful.
When a user hits the “Add to Contentful” button on the repository, we want them to:
- Install the app
- Add some initial configuration like the names of the Content Types.
- Save the configuration and get the Content Model ready.
- Edit the rest of the attributes leveraging the amazing UI Contentful offers.
To build the UI we used the @contentful/f36-components
package, which exports Contentful-looking components such as Form
, Paragraph
, TextInput
, etc.
Contentful offers a @contentful/app-sdk
package, which we used in conjunction with the useSDK
hook from @contentful/react-apps-toolkit
. This provided access to the management APIs exposed by the App SDK and enabled us to create the function, which writes all the Content Types.
Now we can configure the app, hit save, and voilà, our product catalog content model is now in Contentful:
Contentstack
The initial idea for Contentstack was to create an application, similar to Contentful. I’ve obtained the market apps certification using their new course, and we started working on the app.
Soon after we started, by using their amazing CLI’s app:create
command, we realized that Contentstack’s app SDK does not expose their Management SDK, which is not meant to work on a browser. That’s ok though! We can still leverage Contentstack’s CLI to run a migration command on a JSON content model.
The idea is simple: Expose two methods, login
and migrate
.
The user has to
- Clone the repository
- Get the Stack API Key from Contentstack since it’s going to be an authenticated request and add it to a
.env
file.. We don’t need the Management Token. - Change content type files in the
./data
folder according to your products’ attributes and names. - Run
pnpm run migrate
.
Once you open Contentstack, you should see the content model there:
What’s next?
Beyond expanding to other CMS platforms, our plans include enhancing the content model to support complex product data and operations. Leveraging your CMS as a product catalog is not only feasible, it's a strategic choice. With Commerce Layer's focus on optimizing the commerce engine, we're dedicated to enhancing performance and features, allowing for a more integrated and efficient digital commerce experience
These three examples get you started, but are by no means the final product. But, it does show you how easily you can configure a CMS to manage a product catalog. Ideally, you spend some time white boarding your Taxonomy and Taxons, building out your ideal product catalog strategy, and then go from there. We can help you think through this if you want, just find me on #community. I’ll join any jam session you want to set up and help you think through it.
Furthermore, this exercise gives you three distinct options that might help you choose a CMS. All of them are quite feasible, but if you prefer one path over the other, you know know how each CMS platform plugin or app works. Again, if you have questions about which CMS pathway might be best for you, please reach out. Slack is probably best, but I’m on LinkedIn and email.