Manage the Product Catalog
Why catalog structure matters
Section titled “Why catalog structure matters”Your product catalog is the data backbone of your storefront. A well-structured catalog makes products easy to find, keeps pricing and inventory accurate, and gives content authors the building blocks they need for product pages. A poorly structured catalog creates confusion — products in wrong categories, missing variants, inconsistent pricing — that directly impacts revenue.
This guide walks you through creating a catalog structure from scratch: categories, products, variants, prices, and inventory.
What you will do
Section titled “What you will do”- Create a catalog container
- Add categories to organize products
- Create products with variants
- Set up pricing for variants
- Configure inventory levels
Create a catalog
Section titled “Create a catalog”A catalog is the top-level container for your products. Most sites have one primary catalog, though you can create multiple catalogs for different regions, brands, or seasons.
In the Commerce UI:
- Navigate to Commerce > Catalog Management
- Click New Catalog
- Enter a name (e.g., “Main Catalog”) and a default language
- Set the catalog as active to make it available on the storefront
using Mediachase.Commerce.Catalog;
using Mediachase.Commerce.Catalog.Dto;
var catalogDto = new CatalogDto();
var catalogRow = catalogDto.Catalog.NewCatalogRow();
catalogRow.Name = "Main Catalog";
catalogRow.StartDate = DateTime.UtcNow;
catalogRow.EndDate = DateTime.UtcNow.AddYears(10);
catalogRow.IsActive = true;
catalogRow.DefaultLanguage = "en";
catalogRow.SortOrder = 0;
catalogRow.IsPrimary = true;
catalogDto.Catalog.AddCatalogRow(catalogRow);
CatalogContext.Current.SaveCatalog(catalogDto); Add categories
Section titled “Add categories”Categories organize products into a browsable hierarchy. Think of them as the navigation structure of your storefront.
Planning your category structure:
| Approach | Example | Best for |
|---|---|---|
| By product type | Shoes > Running > Trail | Broad catalogs with diverse product types |
| By use case | Outdoor > Hiking > Essentials | Experience-driven brands |
| By audience | Men > Footwear, Women > Footwear | Fashion and apparel |
Keep your hierarchy no deeper than three or four levels. Deeply nested categories make navigation harder and dilute SEO value.
In the Commerce UI:
- Right-click your catalog in the tree
- Select New Category
- Enter a name and URL segment
- Add a description and category image (these appear on category landing pages)
- Set the sort order to control display position
using EPiServer;
using EPiServer.Commerce.Catalog.ContentTypes;
using EPiServer.Core;
using EPiServer.DataAccess;
using EPiServer.Security;
public void CreateCategory(
IContentRepository repo,
ContentReference parentLink)
{
var category = repo.GetDefault<NodeContent>(parentLink);
category.Name = "Running Shoes";
category.DisplayName = "Running Shoes";
category.Code = "running-shoes";
repo.Save(category, SaveAction.Publish, AccessLevel.NoAccess);
} Create products and variants
Section titled “Create products and variants”Products represent what you sell. Variants represent the specific options a customer chooses (size, color, configuration).
The relationship:
- A product holds shared information: name, description, images, brand
- A variant holds purchasable specifics: SKU, size, color, weight, individual images
A customer never buys a “product” — they buy a variant. A “Classic Running Shoe” product might have 12 variants (3 colors x 4 sizes).
In the Commerce UI:
- Navigate to the category where the product belongs
- Click New Product
- Fill in the product name, code, and description
- Save the product
- Under the product, click New Variant for each purchasable option
- For each variant, set the SKU code, and any distinguishing properties (size, color)
public void CreateProductWithVariants(
IContentRepository repo,
ContentReference categoryLink)
{
// Create the product
var product = repo.GetDefault<ProductContent>(categoryLink);
product.Name = "Trail Runner Pro";
product.Code = "trail-runner-pro";
product.DisplayName = "Trail Runner Pro";
var productRef = repo.Save(product,
SaveAction.Publish, AccessLevel.NoAccess);
// Create variants under the product
var sizes = new[] { "8", "9", "10", "11" };
var colors = new[] { "Black", "Blue" };
foreach (var color in colors)
{
foreach (var size in sizes)
{
var variant = repo.GetDefault<VariationContent>(
productRef);
variant.Name = $"Trail Runner Pro - {color} {size}";
variant.Code = $"TRP-{color[0]}-{size}";
repo.Save(variant,
SaveAction.Publish, AccessLevel.NoAccess);
}
}
} Set up pricing
Section titled “Set up pricing”Pricing in Commerce is separate from the product definition. This separation allows multiple prices per variant based on currency, customer group, quantity, and date range.
In the Commerce UI:
- Open a variant
- Navigate to the Pricing tab
- Click Add Price
- Set the currency, amount, and optionally:
- Customer group for tiered pricing (e.g., “Wholesale” at 30% discount)
- Minimum quantity for volume discounts
- Valid from / Valid to for time-limited promotions
using Mediachase.Commerce;
using Mediachase.Commerce.Pricing;
public void SetPricing(
IPriceDetailService priceService,
string variantCode)
{
var prices = new List<IPriceDetailValue>
{
new PriceDetailValue
{
CatalogKey = new CatalogKey(variantCode),
MarketId = new MarketId("US"),
CustomerPricing = CustomerPricing.AllCustomers,
MinQuantity = 0,
UnitPrice = new Money(129.99m, Currency.USD),
ValidFrom = DateTime.UtcNow,
ValidUntil = null
},
new PriceDetailValue
{
CatalogKey = new CatalogKey(variantCode),
MarketId = new MarketId("US"),
CustomerPricing = new CustomerPricing(
CustomerPricing.PriceType.PriceGroup,
"Wholesale"),
MinQuantity = 10,
UnitPrice = new Money(89.99m, Currency.USD),
ValidFrom = DateTime.UtcNow,
ValidUntil = null
}
};
priceService.Save(prices);
} Pricing best practices:
- Always set a default “all customers” price as the baseline
- Use date-bounded prices for promotions instead of manually changing prices
- Test pricing changes in a staging environment before publishing to production
Configure inventory
Section titled “Configure inventory”Inventory tracks how many units of each variant are available, per warehouse.
In the Commerce UI:
- Open a variant
- Navigate to the Inventory tab
- Select a warehouse
- Enter the available quantity, reorder minimum, and backorder settings
using Mediachase.Commerce.InventoryService;
public void SetInventory(
IInventoryService inventoryService,
string variantCode,
string warehouseCode)
{
var inventory = new InventoryRecord
{
CatalogEntryCode = variantCode,
WarehouseCode = warehouseCode,
PurchaseAvailableQuantity = 150,
PurchaseAvailableUtc = DateTime.UtcNow,
BackorderAvailableQuantity = 50,
BackorderAvailableUtc =
DateTime.UtcNow.AddDays(14),
IsTracked = true
};
inventoryService.Save(new[] { inventory });
} | Setting | Purpose |
|---|---|
| Purchase available quantity | Units currently in stock and ready to ship |
| Backorder quantity | Units available for backorder when stock is depleted |
| Backorder available date | When backordered items are expected to be available |
| Is tracked | Whether Commerce decrements inventory on purchase (set to false for digital goods) |
Common issues
Section titled “Common issues”| Issue | Cause | Fix |
|---|---|---|
| Product not appearing on storefront | Product or variant not published | Publish both the product and its variants |
| Price showing as $0 | No price entry for the active market/currency | Add a price for the correct market and currency |
| ”Out of stock” when inventory exists | Variant linked to wrong warehouse | Verify warehouse assignment matches market configuration |
| Category page is empty | Products added to wrong category node | Move products to the correct category in the catalog tree |