ContentType inheritance and default AssetFolder - ContentManagement API and ContentDefinition API

Vote:
 

Hi all,

I found two problems with ContentManagement API and ContentDefinition API which I can't seem to find solution.

1. Content types inheritance - content type definition can only use supported base types and content only accepts on content type.

As an example let's say I have 30 different page types and want to use SEO properties in all of them. With code it's easy to achieve this - just inherit SEO class. With API I don't see any option to have the same logic. I can neither set my custom type through ContentDefinition API for content type definition nor set multiple contentTypes through ContentManagement API for content (it disregards multiple values).

Is there any way to achieve this purely through API?

2. Default asset folder - "For This Page" not set for created page automatically and cannot be set through API.

As an example I want to create new page with ContentArea, then create few new blocks in that ContentArea. Through CMS the blocks will be created in "For This Page" asset folder, but it seems there is no way to achieve this through API.

I tried different approaches, but without any success. Creating block or SysContentAssetFolder folder with page as parent, with Content Assets (default "For This Page" folder) as parent, "For All Sites" as parent and nothing worked. It seems that it's not possible to set ContentOwnerID for the asset folder.

Is there any way to have "For This Page" set purely through API?

 

Thanks for any help that anyone can provide with this!

 

#334243
Edited, Dec 12, 2024 11:12
Soren S - Dec 13, 2024 12:14
I don't trust ChatGPT too much as it has been wrong many times previously,, but at least it gives this long answer with different explanations on the way too, and from a first view it seems as a reasonable answer:

In Optimizely CMS, the limitation you’re encountering is a common challenge when trying to replicate object-oriented inheritance with the `ContentManagement` API and `ContentDefinition` API. Unfortunately, these APIs do not directly support complex inheritance scenarios like those you describe. However, there are strategies to implement reusable SEO properties across multiple page types using these APIs.

Here’s how you can address this:
---
### 1. **Using a Metadata Extension with Blocks**
You can define an SEO block and associate it with all your page types using the `ContentDefinition` API. While this does not directly enable inheritance, it provides a reusable way to manage SEO properties.

#### Steps:
1. Create an SEO block with the required properties (e.g., `MetaTitle`, `MetaDescription`, etc.).
2. Add a property of type `ContentReference` or `Block` to each page type definition to reference the SEO block.

This way, you centralize your SEO logic in the block and can attach it to all relevant pages. This is still manageable via the `ContentManagement` API.

---
### 2. **Use Property Groups**
`Property Groups` are a feature in Optimizely CMS that allow you to define a group of properties that can be reused across multiple content types. Unfortunately, these are not fully supported out of the box in the public API but can be mimicked using:

- Custom property registration.
- Metadata definition via the `ContentDefinition` API.

---
### 3. **Dynamic Property Injection**
Create a helper class that dynamically injects SEO properties into content types at runtime. This allows you to simulate inheritance:

- Define an interface (e.g., `ISeoProperties`) with your SEO properties.
- Use `ContentType` attributes to inject properties dynamically.

For example:
```csharp
[ContentType(DisplayName = "SEO Page", GUID = "....", Description = "Page with SEO properties")]
public class SeoPage : PageData, ISeoProperties
{
public virtual string MetaTitle { get; set; }
public virtual string MetaDescription { get; set; }
}
```

Then dynamically associate these properties via a helper using the `ContentManagement` API.

---
### 4. **Custom Initialization via API Extensions**
You could leverage event hooks or initialization modules to extend all page types with SEO properties dynamically. For example:

- Use the `IContentModelUsage` service to loop through all registered page types.
- Inject SEO properties programmatically at runtime.

```csharp
foreach (var contentType in contentModelUsageService.List())
{
if (contentType.BaseType == typeof(PageData))
{
// Add SEO properties to this content type
}
}
```

---

### 5. **Flatten the Hierarchy Using Mixins**
Mixins in Optimizely can allow you to decouple the SEO properties from the content type. Mixins let you define shared functionality without inheritance, and you can use the `ContentDefinition` API to associate them programmatically.

---

### Why APIs Limit Direct Inheritance
The limitation you are experiencing with the APIs stems from how Optimizely CMS is architected to work with dynamic content definitions. Content types in Optimizely are stored and managed as data, and this restricts classical inheritance mechanisms.

---

### Recommendation
The most effective and maintainable approach for your case would likely be **option 1 (SEO Block)** or **option 5 (Mixins)**. Both methods allow for reusability, are manageable through the APIs, and adhere to Optimizely's extensibility patterns.
Vote:
 

Haven't tried it via the API, but something similar to option 1 in that previous comment might work -- 

1) Create an SEO block with the required properties (e.g., `MetaTitle`, `MetaDescription`, etc.) (same as above)

2) Then, via Content Definitions API, add a property to each page type, using type "PropertyBlock" (second from the bottom in this table) -- I think that should surface the SEO block properties on all instances of that page type. (A negative is that you'd have to do this for each of the 30 different page types. But the positive is that if you ever wanted to add a new SEO property, you should be able to just update the SEO Block Type and it'll apply everywhere.)

#334539
Dec 19, 2024 5:13
Vote:
 

Thanks for all the answers.

For option 1 I tried approach of using PropertyBlock and althought it will require a little bit of work, it is working as explained. I think that will have to sufficient if there's not other way to achieve it through API.

For option 2 the workaround which I'll use is to create and use normal folders.

 

 

#335339
Jan 08, 2025 8:58
* You are NOT allowed to include any hyperlinks in the post because your account hasn't associated to your company. User profile should be updated.