---
title: Conventions API
slug: cms-12/docs/conventions-api
docTags: 
createdAt: 2026-08-10T15:56:02.000Z
---

Get the `ConventionRepository` singleton instance to configure conventions.

:::hint{type="info"}
**Note**
Perform this configuration in an `IInitializableModule` to make sure the conventions are synched correctly to Graph.
:::

```csharp
[ModuleDependency(typeof (InitializationModule))]
public class GraphConventions: IInitializableModule {
  public void Initialize(InitializationEngine context) {
    context.Locate.Advanced.GetInstance < ConventionRepository > ()
      .IncludeAbstract < SitePageData > ();
  }
  public void Uninitialize(InitializationEngine context) {}
}
```

:::hint{type="info"}
**Note**
Content types and content data are not resynced automatically when conventions are changed, and the site is restarted. After changing conventions in code and redeploying the site, you should re-run the Optimizely Graph synchronization job so data is consistent with your configurations. Not doing so will result in unpredictable outcomes.
:::

## Exclude content types

You can exclude content types from being synced to Optimizely Graph schema, and contents of the excluded content types will not be synced from Optimizely Graph.

Example: exclude `StandardPage` and `OrderBlock`.

```csharp
  conventionRepo.ExcludeContentType < StandardPage > ()
    .ExcludeContentType < OrderBlock > ();
```

When this happens `StandardPage` and `OrderBlock` will not be included in the GraphQL schema and there will not be contents of type `StandardPage` and `OrderBlock` synced to Graph..

![](https://api.archbee.com/api/optimize/BrbvVORKJ5iIeSMZye5kI/BOy3Jo0LAX6MhpiTK9e_S_7fc03c8d2eddd1116d0d15edb0f4f4859b93e00cd20ca3b971dac47c23ea6042-explorer.png)

When you add contents of excluded content types `ContentArea` or `ContentReference` and other reference fields of another type (such as adding a `StandardPage` to a `ContentArea` field of a `StartPage`), the contents of excluded content types will not be included in the `ContentArea`.

For excluded block types, the block properties of that type are still available in the content, because the block properties are part of the content. If the blocks are created as standalone contents, they are excluded from synchronization to Optimizely Graph.

## Exclude all content types except some

The following code excludes all content types except for some content types as an alternative way to configure.

```csharp
  conventionRepo.ExcludeAllContentTypes()
    .Except < StandardPage > ()
    .Except < OrderBlock > ();
```

## Exclude fields

You can exclude fields from content types. When a field is excluded, it is not synced to Optimizely Graph and is not included in the GraphQL schema.  The following example configures an Optimizely Graph integration to exclude `ContentAreaItem1` and `MainBody` properties from `StandardPage` content type.

```csharp
  conventionRepo.ForInstancesOf < StandardPage > ()
    .ExcludeField(p => p.ContentAreaItem1)
    .ExcludeField(p => p.MainBody);
```

## Set indexing type for fields

Use the `ConventionRepository` to set the indexing type for code fields. This method overrides settings from the CMS UI, the `[Searchable]` attribute, and Optimizely Graph's `PropertyIndexingType` attributes.

```csharp
  conventionRepo.ForInstancesOf < StandardPage > ()
    .Set(page => page.Keywords, IndexingType.Searchable)
    .Set(page => page.Price, IndexingType.Queryable)
    .Set(page => page.Quantity, IndexingType.OnlyStored);
```

There are three `IndexingTypes` when configuring using Conventions API.

- **Searchable** – The property is searchable using full-text search. **Searchable** is only applicable to leaf properties of primitive types (`string`, `int`, `datetime`, and so on).
- **Queryable** – The property can be filtered using operators like `eq`, `gt`, `gte`, but not searchable when doing full-text search.
- **OnlyStored** – The property can be projected in GraphQL, but it is not searchable nor filterable.

## Include fields

Conventions API lets you add calculated fields to the content when synced to Optimizely Graph. You can implement the field as a method on the `ContentType` class.

The following code shows an example with a block type called `OrderBlock`.

```csharp
[ContentType]
public class OrderBlock: BlockData {
  public virtual string OrderDetails {
    get;
    set;
  }
  public virtual int Quantity {
    get;
    set;
  }

  public virtual double Price {
    get;
    set;
  }

  public double TotalPrice() {
    return Quantity * Price;
  }
}
```

In this example, in CMS the `OrderBlock` content type has properties: `OrderDetails`, `Quantity`, and `Price`.

The method `TotalPrice` calculates the total price by multiplying `Quantity` and `Price`.

You can add `TotalPrice` as a calculated field when synchronizing `OrderBlock` contents by configuring this convention.

```csharp
  conventionRepo.ForInstancesOf < OrderBlock > ()
    .IncludeField(p => p.TotalPrice());
```

Then, when an `OrderBlock` is created (as shown)...

![](https://api.archbee.com/api/optimize/BrbvVORKJ5iIeSMZye5kI/-Q_tEfdqXPw1j5gCPCZ-K_666ec2ccc4cd2c428e4200e2e5aa3835c32981bfddd17d77f54c27d28d09c874-image-2024-10-29-17-17-12.png)

...and then synced to Optimizely Graph, you can query for `TotalPrice` value.

![](https://api.archbee.com/api/optimize/BrbvVORKJ5iIeSMZye5kI/2oiwOrpZReFRiUs28EMXF_ee3e765ff3422c6bceb4def264c533cd93c6c90f09bd567cc63a445f0541715b-image-2024-10-29-17-19-41.png)

:::hint{type="info"}
**NOTE**
Dynamic fields use lambdas in `IncludeField`, which may not support all expression variations. Because calculated fields are only in Optimizely Graph, implement on-page editing to view them in the CMS editor by showing them in the frontend site's preview.
:::

:::hint{type="info"}
**WARNING**
You should use simple methods like in the example that run quickly to avoid issues when synchronizing contents to Optimizely Graph.

Use `IncludeField` to add any form of data to the content item that does not belong to CMS Content. Do not make the method return CMS data like `ContentReference`, `ContentArea`, `Blob`, or `Blocks` because they will not work like real CMS properties and many features associated with those data types will not work.

`IncludeField` will not allow adding methods that return the following CMS types. You should not use the following CMS data types with `IncludeField`.

- `Blob`
- `ContentArea`
- `ContentAreaItem`
- `ContentReference`
- `LinkItem`
- `LinkItemCollection`
- `PageData`
- `BlockData`
- `MediaData`
- `XhtmlString`
:::

## Example of multiple language support with calculated fields

You can give calculated fields specific values for different languages. The following code adds a field that returns the `TermsAndConditions` link.

```csharp
[ContentType]
public class StandardPage: MyAbstractPage2, ISearchPage {
  //... other properties

  public string TermsAndConditions() {
    var language = this.Language.Name;
    var tncLink = "https://ourcorp/tnc";
    var tnc = "Terms and conditions";
    switch (language) {
    case "sv":
      tnc = "villkor";
      break;
    case "vi":
      tnc = "Điều khoản và điều kiện";
      break;
    }
    return $ "{tnc}: {tncLink}";
  }
}
```

The method can return different texts depending on the current language, the default text is in English.

The following code configures to include this `TermsAndConditions` field.

```csharp
conventionRepo.ForInstancesOf < StandardPage > ()
  .IncludeField(p => p.TermsAndConditions());
```

When a `StandardPage` has multiple versions in different languages, the `TermsAndConditions` field will change accordingly.

![](https://api.archbee.com/api/optimize/BrbvVORKJ5iIeSMZye5kI/Z86GcEyT5qS5fTJ2tqBP4_d38ea05de05156fab6712a03962abc55fb9a33da789be9391703b1d5b9bd255d-image-2024-10-29-17-33-1.png)

## Include abstract types in GraphQL

When creating content types from code in CMS 12, you can use abstract classes as base classes for content types. Abstract classes are not added to GraphQL schema by default. You can use Conventions API to add the abstract classes to Optimizely Graph, then you can query contents by both the content type and the abstract types.

The following example shows when `StandardPage` is extended from `MyAbstractPage2`, then `MyAbstractPage2` is extended from `MyAbstractPage`.

```csharp
public abstract class MyAbstractPage: PageData {
  [Display(
    GroupName = SystemTabNames.Content,
    Order = 310)]
  [CultureSpecific]
  public virtual XhtmlString MainBody {
    get;
    set;
  }
}

public abstract class MyAbstractPage2: MyAbstractPage {
  [Display(
    GroupName = SystemTabNames.Content,
    Order = 310)]
  [CultureSpecific]
  public virtual XhtmlString MainBody2 {
    get;
    set;
  }
}

[ContentType(GUID = "9CCC8A41-5C8C-4BE0-8E73-520FF3DE8267")]
public class StandardPage: MyAbstractPage2 {
  //Standard Page fields.
}

You can configure to include MyAbstractPage2 and MyAbstractPage using conventions API

//Configure in IInitializableModule
conventionRepo
  .IncludeAbstract < MyAbstractPage > ()
  .IncludeAbstract < MyAbstractPage2 > ();
```

After running the sync job, the abstract types are now listed in the schema.

![](https://api.archbee.com/api/optimize/BrbvVORKJ5iIeSMZye5kI/CQ3SCR4y16jjc6IgBOnys_30b98c0fd2dc124fed489099a4078bc02e4b5643e3e6e484554b0214a1b11060-image-2024-10-29-17-59-54.png)

You can query for standard page using either `StandardPage`, `MyAbstractPage`, or `MyAbstractPage2`.

When using abstract types, you can use inline fragments to cast the data to other types in the inheritance tree because, in GraphQL, these types are also marked as abstract. This works because abstract classes have all fields of more specific classes, so it is supported by GraphQL.

![](https://api.archbee.com/api/optimize/BrbvVORKJ5iIeSMZye5kI/Czr554qThTAhf2ymzyBXI_87cff8badccb0aaf5d00443b608e815f858ade7476ae36c5602e684305ba97bb-image-2024-10-30-9-44-57.png)

![](https://api.archbee.com/api/optimize/BrbvVORKJ5iIeSMZye5kI/xdzBXN-_PPrQrC6F4-e4Z_6363b8dc01629ad125dc970f8f265843c6c077001fcfbfe261ff02e12b60b216-image-2024-10-29-18-2-4.png)

## Include interface types in GraphQL

You can include interface types in the GraphQL schema, aside from abstract types. Given that `StandardPage` also implements `ISearchPage` interface, see the following code.

```csharp
public interface ISearchPage {
  string Keywords {
    get;
    set;
  }
}

[ContentType(GUID = "9CCC8A41-5C8C-4BE0-8E73-520FF3DE8267")]
public class StandardPage: MyAbstractPage2, ISearchPage {
  //Standard Page fields.
}
```

Use `IncludeInterface<T>` to add the interface to GraphQL.

```csharp
conventionRepo.IncludeInterface<ISearchPage>();
```

After contents are synced, you can also query using the `interface` type.

:::hint{type="info"}
**Note**
`Interface` types are not abstract types, so you cannot cast it to other types like `MyAbstractPage2`, `MyAbstractPage`, and `StandardPage`. This is because `interface` can have fields that are not in some classes in the chain of inheritance, so making interface an abstract type will cause validation errors from GraphQL when both `MyAbstractPage` and `ISearchPage` are queried.
:::

![](https://api.archbee.com/api/optimize/BrbvVORKJ5iIeSMZye5kI/W__7_wDThylyHdxSuqkl5_7f30b9402c1a37b8d590b5e558cf3e29fa3d0707f27e920ca393eb63c9ec4693-image-2024-10-30-10-10-22.png)

![](https://api.archbee.com/api/optimize/BrbvVORKJ5iIeSMZye5kI/wD1QFBc0c_nvBhNFcJDeN_3bcec5d80768c21a110d9fe8106449008f3d2cb22d168ab6f8a15b1fe61e8b44-image-2024-10-30-10-6-18.png)
