Module: Commerce content modeling
36 of 38 Pages
Content querying and content modeling training guides
With any content management platform, you must decide how to structure data. If you are a developer, you may feel tempted to leave content modeling totally in the hands of solution architects or project managers, but it is important to understand how modeling decisions affect both your development tasks and the ease of delivering a functional project.
When you design infrastructure-specific content types that exist within a digital experience platform like Xperience by Kentico, it is important to consider the strengths and friction points of that platform: will the design allow editors to easily work with the content? Does the platform have a straightforward way to query and display a given model, or will it create extra development work?
With the Training guides commerce implementation, our content modeling approach had the following goals:
- Store products in the Content hub, using page wrappers to display them in web channels
- Use separate content items to represent product variants
- Ensure developers can easily query products of multiple content types based on a variety of parameters
- Minimize unused, inapplicable fields during the editing process to prevent confusion
Let’s outline scenarios that prioritize editor usability and data querying efficiency, then examine the solution the Training guides model uses to balance them.
Choose a balanced modeling strategy
Easiest model for editors
Each product and variant type has a dedicated content type in Xperience. When an editor wants to create a new Dog collar product, they add a new item of the Dog collar type instead of Product.
Parent product types have their own dedicated fields for variants, with the Combined content selector scoped to their specific variant type (e.g., the Cat food product only allows Cat food variant items as variants).
There are no fields that only apply in certain scenarios. For example, abstract parent products do not have a Product price field whose value is ignored in favor of variant prices. If a product or variant has a field, it does something.
Drawbacks for developers
- Developers must account for several content types to cover each type’s unique fields.
- Finding the parent products of a filtered set of variants (e.g., all products available in the color red) is difficult and inefficient.
- Querying references requires the name of the linking content type and of its field, which are different across each content type (e.g., DogCollarVariants, DogHarnessVariants, DogBandanaVariants, etc.).
- As a result, developers must check every parent product type individually.
Easiest model for developers
There is one dedicated type that represents all products and variants. By filling in descriptions, names, and various other attributes, editors use this type to represent any category of product. Whether stock or price should be tracked by parent product or variant does not matter because they both use the same type, which contains all fields they could possibly need, and fallbacks are possible through linked items of the same type. It is up to editors to recognize or indicate when each field should apply.
Because there is one product content type, developers always know which content type field holds variants, so retrieving parent products for a mixed set of variants is straightforward.
Drawbacks for editors
- Editors have to deal with fields that only apply in certain contexts, which cannot always be hidden with visibility conditions, leading to confusion.
- E.g., both parent products and variants have a price field, and both cannot apply at once.
- Variants for products are difficult to find during selection, and editors must sift through every product in the whole project to find them.
- Products are difficult to find in the Content hub without searching for them by name.
The middle path
Product attributes exist across several reusable field schemas, which apply to product and variant types where applicable. These schemas add fields to content types and also indicate whether a product belongs to a given category in code based on which schemas are present. For example:
public bool ProductHasVariants(IProductSchema product)
{
if (product is IProductParentSchema parentProduct)
{
return parentProduct.ProductParentSchemaVariants.Any();
}
return false;
}
Each product and variant type has a dedicated content type in Xperience. When an editor wants to create a new Dog collar product, they add a new item of the Dog collar type instead of Product. Each of these types implements reusable schemas with the fields it needs.
Developers can easily filter queries by linking references, because parent products will always link their variants via a single schema field (ProductParentSchemaVariants).
Reduced drawbacks
- Similar to the developer model, editors must look through every content item that uses the variant schema when selecting existing variants for a parent product. However, having separate content types reduces friction.
- They can easily sort content items, filtering by types and taxonomy tags to mitigate the issue and find the groups of variants they need.
- Smart folders can automatically sort product categories for even faster access during selection and editing.
- As in the editor model, developers need to implement type-specific logic, but schemas mitigate the issue.
- Most of the code logic relies on the schemas, and developers only need to dive into type-specific fields occasionally, such as when assembling view models.
private async Task<ProductViewModel> GetCatFoodViewModel(CatFood catFoodProduct, CatFoodVariant? catFoodVariant)
{
// Shared logic that does most of the work based on shared schemas
var model = await GetGenericProductViewModel(catFoodProduct, catFoodVariant);
// Small addition to include a type-specific field that is not from a schema
model.ProductOtherDetails = new HtmlString
(("Ingredients:<br/>" + string.Join("<br/>", catFoodVariant?.CatFoodVariantFormulation
.Select(formulation => formulation.PetFoodFormulationIngredients) ?? []))
?? string.Empty);
return model;
}
Training guides commerce schemas
You likely noticed that the Training guides product model relies heavily on reusable field schemas. The schemas act as building blocks to create our individual product content types, and allow us to compose most of each content type with minimal type-specific fields. Let’s take a closer look at how they work.
Product schema - IProductSchema
Indicates that a type represents a product in code, and provides basic fields that all parent products, variants, and basic products should have:
- Product name - The name of a product or variant
- Product images - One or more images of a product or variant
- Product text - Description of a product or variant
Product parent schema - IProductParentSchema
Designates a type as a parent product with variants in code, and provides the field to hold the variants:
- Variants - One or more content items that use the Product variant schema, representing the parent product’s variants
Product variant schema - IProductVariantSchema
Signifies that a type represents a product variant in code and allows items in the Variants selector of parent products:
- Variant code name - A unique code name used for URLs and variant selection
Product price schema - IProductPriceSchema
Specifies that a product or variant has a price (assignable to top-level product or variant):
- Price - The price of the product or variant
- Discount category - One or more taxonomy tags, representing discount categories for promotions
Product SKU schema - IProductSkuSchema
Provides a SKU code field for products or variants and indicates that stock should be tracked for the class in code:
- SKU Code - A unique stock-keeping unit code identifying the product or variant
Product shipping schema - IProductShippingSchema
Indicates that a product or variant has shipping-related attributes, allowing for physical and digital variants of the same product:
- Product requires shipping - Whether and how the product requires shipping (e.g., to customer, to store, both, no shipping required)
- Shipping weight - The weight of the product, including packaging
- Weight unit - The unit of the shipping weight (e.g., kg, g, lb, oz)
Amount schema - IAmountSchema
Specifies that a product or variant is available in a certain measured amount (e.g., 100mL, 5lb):
- Amount - The numerical value of the amount
- Product measurement unit - The unit that the numerical value applies to
Color/Pattern schema - IColorPatternSchema
Assigns a color and/or pattern to a product or variant:
- Color/Pattern - One or more taxonomy tags representing the color and/or pattern
Material schema - IMaterialSchema
Includes a material attribute for a product or variant:
- Material - Taxonomy tag(s) representing the material
Size schema - ISizeSchema
Designates that a product or variant comes in a certain size:
- Size - A taxonomy tag representing the size of the product or variant
Application
Let’s contextualize these schemas with an example. Imagine you are creating content types to represent T-shirt products and their variants. (We’ll use a ✓ icon to indicate that a given schema is broadly recommended, and a ? icon to indicate that a schema could apply depending on the given scenario.)
- T-shirt (parent product)
- ✓ Product schema for basic name, image, etc.
- ✓ Product parent schema so we can create variants for different sizes and colors
- ? Product price schema to store price if all sizes and colors cost the same, and should not be possible to separately discount
- ? Product shipping schema to set shipping info if the weight difference between shirt sizes is not large enough to affect shipping costs
- ✓ Material schema so customers can filter the product listing by material
- T-shirt variant
- ✓ Product schema for basic name, image, etc. (each color variant, at least, will need its own name and image)
- ✓ Product variant schema to make the different sizes and colors selectable as variants of a parent product
- ✓ Product SKU schema to track the available stock of a specific variant
- ? Product price schema to store price if sizes and colors have different prices, or should be possible to separately discount
- ? Product shipping schema to set shipping info if the different variants will have different shipping costs
- ✓ Color/pattern schema to represent the color of a specific variant and allow filtering in product listings
- ✓ Size schema to represent the size of a specific variant and allow filtering in product listings
Let’s examine how these might apply at a more general level, with the terminology from earlier:
- Parent products should implement the Product schema and the Product parent schema, but not the Product variant schema.
- Variants should implement the Product schema and the Product variant schema, but not the Product parent schema.
- Basic products should implement the Product schema but neither the Product parent schema nor the Product variant schema.
Tips for commerce schemas
- Add your own schemas for attributes that are not here but could be shared by multiple products, such as:
- A Manufacturer schema with a field linking to details about the brand, typically applied to parent products to avoid redundant entry on variants
- An Accessory schema that allows selection of bundled add-on products
- A Product image schema, if you prefer to specify which product and variant types provide images, instead of including them by default in the Product schema
- If manufacturers have different requirements for the same category of product, consider creating multiple content types, e.g.:
- T-shirt (price by variant)
- T-shirt (flat price)