---
title: Catalog content
slug: commerce-connect-14/docs/catalog-content
docTags: 
createdAt: 2026-07-23T10:25:34.370Z
---

## Access catalog content as IContent

Optimizely Commerce Connect provides a content provider that can serve any catalog content as IContent. That means you can use an `IContentRepository` to work with the content as you do in the Optimizely Content Management System (CMS).

Sample code

```csharp
public ContentReference CreateNewSku(ContentReference linkToParentNode)
      {
        var contentRepository = ServiceLocator.Current.GetInstance<IContentRepository>();
        //Create a new instance of CatalogContentTypeSample that will be a child to the specified parentNode.
        var newSku = contentRepository.GetDefault<CatalogContentTypeSample>(linkToParentNode);
        //Set some required properties.
        newSku.Code = "MyNewCode";
        newSku.SeoUri = "NewSku.aspx";
        //Set the description
        newSku.Description = "This new SKU is great";
        //Publish the new content and return its ContentReference.
        return contentRepository.Save(newSku, SaveAction.Publish, AccessLevel.NoAccess);
      }
```

For information about displaying Commerce Connect content, see [Commerce Connect rendering templates](docId\:vlysddL29BglPu_Z3o0DW).

## Content model

Connect a content type to the meta-class to get the full feature set. Do that by creating a model class that inherits from the appropriate type in the `EPiServer.Commerce.Catalog.ContentTypes` namespace and decorating it with the `CatalogContentTypeAttribute` attribute.

Sample code

```csharp
using EPiServer.Commerce.Catalog.ContentTypes;
using EPiServer.Commerce.Catalog.DataAnnotations;
using EPiServer.Core;
using EPiServer.DataAnnotations;

namespace CodeSamples.EPiServer.Commerce.Catalog.Provider
  {
    [CatalogContentType(
      GUID = "7B6B3E60-BFD8-4AD6-BA94-C9728F727988",
      MetaClassName = "CatalogContentTypeSample",
      DisplayName = "Content Type Sample",
      Description = "A customize for variation content"
    )]
    public class CatalogContentTypeSample : VariationContent
      {
        [CultureSpecific]
        [Tokenize]
        [Encrypted]
        [UseInComparison]
        [IncludeValuesInSearchResults]
        [IncludeInDefaultSearch]
        [SortableInSearchResults]
        public virtual string Description { get; set; }

        public virtual int Size { get; set; }

        [DecimalSettings(18, 0)]
        public virtual decimal Discount { get; set; }
      }
  }
```

The following types are available when you create Commerce Connect models.

| Type name          | Description                      |
| ------------------ | -------------------------------- |
| `VariationContent` | A type for variant/SKU models.   |
| `ProductContent`   | A type for product models.       |
| `BundleContent`    | A type for bundle models.        |
| `PackageContent`   | A type for package models.       |
| `NodeContent`      | A type for category/node models. |
| `CatalogContent`   | A type for catalog models.       |

You should not inherit from the following types because they exist only to show various states in the system:

| Type name          | Description                                                                                                          |
| ------------------ | -------------------------------------------------------------------------------------------------------------------- |
| `EntryContentBase` | A base type for `VariationContent`, `ProductContent`, `BundleContent`, `PackageContent` and `DynamicPackageContent`. |
| `NodeContentBase`  | A base type for `NodeContent` and `CatalogContent`.                                                                  |
| `RootContent`      | The virtual root in Optimizely's hierarchical representation of Commerce Connect content.                            |

During synchronization, specific CLR types generate meta-fields of a specific `MetaDataPlus` type. You can modify the default mapping by using the `BackingTypeAttribute`. The following table shows mappings for all supported types.

**Maps for all supported types**

| CLR Type           | MetaDataPlus Type                                              |
| ------------------ | -------------------------------------------------------------- |
| `Byte`             | `Integer` (`SmallInt`, `TinyInt` and `Int` are also supported) |
| `Int16`            | `Integer` (`SmallInt`, `TinyInt` and `Int` are also supported) |
| `Int32`            | `Integer` (`SmallInt`, `TinyInt` and `Int` are also supported) |
| `Int64`            | `Integer` (`SmallInt`, `TinyInt` and `Int` are also supported) |
| `Double`           | `Float`                                                        |
| `Single`           | `Float`                                                        |
| `Float`            | `Float`                                                        |
| `Decimal`          | `Decimal`                                                      |
| `String`           | `LongString` (`ShortString` and `Text` are also supported)     |
| `Boolean`          | `Boolean`                                                      |
| `DateTime`         | `DateTime` (`Date` and `SmallDateTime` are also supported)     |
| `Url`              | `Url`                                                          |
| `XhtmlString`      | `LongHtmlString`                                               |
| `ContentReference` | `ShortString`                                                  |
| `PageReference`    | `ShortString`                                                  |

## Customized Commerce-specific attributes

Any attribute you can use in the CMS can also be used in Commerce Connect content type models. You can decorate your model with the following Commerce Connect-specific attributes:

- `CatalogContentTypeAttribute`
  To connect the content type to an existing meta-class, use the `CatalogContentTypeAttribute`. Connect them by defining the name of the meta-class that should be connected to the content type.

Sample code

```csharp
using EPiServer.Commerce.Catalog.ContentTypes;
using EPiServer.Commerce.Catalog.DataAnnotations;

namespace CodeSamples.EPiServer.Commerce.Catalog.Provider
  {
    [CatalogContentType(MetaClassName = "WineSKU")]
    public class CatalogContentTypeAttributeSample : VariationContent
      {
      }
  }
```

- `EncryptedAttribute` – Use to declare a property to enable Use Encryption. This encrypts the value when stored in MetaDataPlus.
- `UseInComparisonAttribute` – Use an attribute to declare a property to be used for comparison.
- `IncludeInDefaultSearchAttribute` – Use to declare a property to include the value in default search results. This will be used by the search provider system.
- `IncludeValuesInSearchResultsAttribute` – Use to declare a property to be included in search results. This will be used by the search provider system.
- `SortableInSearchResultsAttribute` – Use to declare a property to be flagged as index sortable. This will be used by the search provider system.
- `TokenizeAttribute` – Use to declare a property to be tokenized (word breaking).
- `DecimalSettingsAttribute` – Use to declare a property to have precision and scale.

## Commerce Connect-specific types

The types you can represent in `MetaDataPlus` are not directly mapped to a CLR type. Properties that are backed by meta-fields of these `MetaDataPlus` types need to be specified beyond return type. The following table lists such `MetaDataPlus` types and additional requirements.

:::hint{type="info"}
**Note**
The use of Commerce Connect-specific types is not supported within blocks.
:::

| MetaDataPlus Type                                   | CLR Type            | Additional Requirements                                               |
| --------------------------------------------------- | ------------------- | --------------------------------------------------------------------- |
| \`Dictionary\`                                      | \`string\`          | Decorated with \`\[BackingType(typeof(PropertyDictionarySingle))]\`   |
| \`Dictionary, multiline\`                           | \`ItemCollection \` | Decorated with \`\[BackingType(typeof(PropertyDictionaryMultiple))]\` |
| \`StringDictionary\` (new in Commerce Connect 13.1) | \`IDictionary \`    | Decorated with \`\[BackingType(typeof(PropertyStringDictionary))]\`   |

:::hint{type="info"}
**Note**
To define a property that maps to a `StringDictionary` metafield, use this example:
`[BackingType(typeof(PropertyStringDictionary))]`
`public virtual IDictionary<string, string> StringDict { get; set; }`
:::

To change the values of that `StringDictionary` metafield, update the property as a normal dictionary. Example:
`content.StringDict = new Dictionary<string, string>() {{ "abc", "xyz" }, {"hello", "world"}};`

See also [New feature in Customized Commerce 13.1: StringDictionary support for catalog content](https://world.optimizely.com/blogs/Quan-Mai/Dates/2019/3/new-feature-in-commerce-13-1-stringdictionary-support/)

## Limits in synchronization

The synchronization of catalog models works the same way as with content types in the CMS, except the data is backed in `MetaDataPlus`. However, there are some limitations due to technical differences. The following are not done automatically. They require manual steps:

- Change a property type – Causes an exception.
- Rename a model class – Unless specified by the `CatalogContentTypeAttribute`, adds a meta-class, but the old one is left in the system.
- Rename a property – Adds a meta field, but the old one is left in the system.
- Remove a property.

Different properties with the same name must have identical definitions. For example, you cannot have a property called *Description* on two different classes and make it culture-specific on one, but not the other. This is because, in `MetaDataPlus`, meta fields are shared across meta classes. Hence, they can only have one definition. See [Synchronization](docId\:tuj89esBBi8aLWv5x8Cl4).

## List properties

Beginning with CMS 11, Commerce Connect has a `PropertyValueList` that lets editors input multiple primitive values. Available types are:

- `Int`
- `String`
- `Double`
- `DateTime`

You can add a list as a property in your model.

Sample code

```text
[BackingType(typeof(PropertyIntegerList))]
    [Display(Name = "List of int", Order = 5)]
    public virtual IList<int> IntList { get; set; }

    [BackingType(typeof(PropertyDateTimeList))]
    [Display(Name = "List of date time", Order = 8)]
    public virtual IList<DateTime> DateTimeList { get; set; }

    [BackingType(typeof(PropertyStringList))]
    [Display(Name = "List of string", Order = 6)]
    public virtual IList<string> StringList { get; set; }

    [BackingType(typeof(PropertyDoubleList))]
    [Display(Name = "List of double", Order = 7)]
    public virtual IList<double> DoubleList { get; set; }
```

Sample results

![](https://api.archbee.com/api/optimize/BrbvVORKJ5iIeSMZye5kI/lDeYiB8Cb9hP_4tqcudps-20260723-094554.png)
