optimizely-development

Optimizely CMS Development

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "optimizely-development" with this command: npx skills add twofoldtech-dakota/claude-marketplace/twofoldtech-dakota-claude-marketplace-optimizely-development

Optimizely CMS Development

Overview

This skill covers core Optimizely CMS (formerly Episerver) development patterns including content types, initialization modules, and the content API.

Content Types

Page Types

using EPiServer.Core; using EPiServer.DataAnnotations; using System.ComponentModel.DataAnnotations;

[ContentType( GUID = "f8d47a38-5b23-4c8e-9f12-3a7e8b9c2d1f", DisplayName = "Article Page", Description = "Standard article page with heading and body content", GroupName = "Content")] public class ArticlePage : PageData { [Display( Name = "Heading", Description = "Main heading for the article", GroupName = SystemTabNames.Content, Order = 100)] [Required] public virtual string Heading { get; set; }

[Display(
    Name = "Main Content",
    GroupName = SystemTabNames.Content,
    Order = 200)]
public virtual XhtmlString MainBody { get; set; }

[Display(
    Name = "Published Date",
    GroupName = SystemTabNames.Content,
    Order = 300)]
public virtual DateTime? PublishedDate { get; set; }

}

Block Types

[ContentType( GUID = "a1b2c3d4-e5f6-7890-abcd-ef1234567890", DisplayName = "Hero Block", Description = "Full-width hero section")] public class HeroBlock : BlockData { [Display(Name = "Heading", Order = 10)] [Required] public virtual string Heading { get; set; }

[Display(Name = "Subheading", Order = 20)]
public virtual string Subheading { get; set; }

[Display(Name = "Background Image", Order = 30)]
[UIHint(UIHint.Image)]
public virtual ContentReference BackgroundImage { get; set; }

[Display(Name = "Call to Action", Order = 40)]
public virtual Url CallToActionUrl { get; set; }

}

Content Areas with Restrictions

[Display(Name = "Main Content Area", Order = 100)] [AllowedTypes(typeof(TextBlock), typeof(ImageBlock), typeof(VideoBlock))] public virtual ContentArea MainContentArea { get; set; }

[Display(Name = "Sidebar Blocks", Order = 200)] [AllowedTypes(typeof(TeaserBlock), typeof(LinkListBlock))] [MaxItems(3)] public virtual ContentArea SidebarArea { get; set; }

Initialization Modules

Configurable Module

using EPiServer.Framework; using EPiServer.Framework.Initialization; using EPiServer.ServiceLocation; using Microsoft.Extensions.DependencyInjection;

[InitializableModule] [ModuleDependency(typeof(ServiceContainerInitialization))] public class DependencyResolverInitialization : IConfigurableModule { public void ConfigureContainer(ServiceConfigurationContext context) { context.Services.AddScoped<IArticleService, ArticleService>(); context.Services.AddScoped<ISearchService, SearchService>(); }

public void Initialize(InitializationEngine context)
{
    // Initialization logic
}

public void Uninitialize(InitializationEngine context)
{
    // Cleanup logic
}

}

Content Events Module

[InitializableModule] [ModuleDependency(typeof(EPiServer.Web.InitializationModule))] public class ContentEventsInitialization : IInitializableModule { public void Initialize(InitializationEngine context) { var events = context.Locate.ContentEvents(); events.PublishedContent += OnPublishedContent; events.SavingContent += OnSavingContent; }

private void OnPublishedContent(object sender, ContentEventArgs e)
{
    // Handle content published event
}

private void OnSavingContent(object sender, ContentEventArgs e)
{
    // Handle content saving event
}

public void Uninitialize(InitializationEngine context)
{
    var events = context.Locate.ContentEvents();
    events.PublishedContent -= OnPublishedContent;
    events.SavingContent -= OnSavingContent;
}

}

Content API

IContentLoader (Cached Reads)

public class ArticleService : IArticleService { private readonly IContentLoader _contentLoader;

public ArticleService(IContentLoader contentLoader)
{
    _contentLoader = contentLoader;
}

public T Get&#x3C;T>(ContentReference contentLink) where T : IContent
{
    return _contentLoader.Get&#x3C;T>(contentLink);
}

public IEnumerable&#x3C;T> GetChildren&#x3C;T>(ContentReference parentLink) where T : IContent
{
    return _contentLoader.GetChildren&#x3C;T>(parentLink);
}

// Batch loading - more efficient than loading one by one
public IEnumerable&#x3C;IContent> GetItems(IEnumerable&#x3C;ContentReference> contentLinks)
{
    return _contentLoader.GetItems(contentLinks, new LoaderOptions());
}

}

IContentRepository (Write Operations)

public class ContentManager { private readonly IContentRepository _contentRepository;

public ContentManager(IContentRepository contentRepository)
{
    _contentRepository = contentRepository;
}

public ContentReference CreatePage&#x3C;T>(ContentReference parentLink, string name) where T : PageData
{
    var page = _contentRepository.GetDefault&#x3C;T>(parentLink);
    page.Name = name;
    return _contentRepository.Save(page, SaveAction.Publish);
}

public void UpdateContent(IContent content)
{
    var writableContent = content.CreateWritableClone();
    // Make changes
    _contentRepository.Save(writableContent, SaveAction.Publish);
}

}

Scheduled Jobs

[ScheduledPlugIn( DisplayName = "Content Cleanup Job", Description = "Removes expired content", GUID = "12345678-1234-1234-1234-123456789012")] public class ContentCleanupJob : ScheduledJobBase { private readonly IContentRepository _contentRepository;

public ContentCleanupJob(IContentRepository contentRepository)
{
    _contentRepository = contentRepository;
}

public override string Execute()
{
    var processedCount = 0;

    // Job logic here
    OnStatusChanged($"Processing... {processedCount} items");

    return $"Completed. Processed {processedCount} items.";
}

}

Property Value Converters

public class TagListPropertyConverter : PropertyValueConverterBase { public override object Convert(object value, Type targetType) { if (value is string tags) { return tags.Split(',').Select(t => t.Trim()).ToList(); } return new List<string>(); } }

Best Practices

  • Always use GUIDs on content types for serialization

  • Use IContentLoader for reads (cached)

  • Use IContentRepository for writes only

  • Batch load content instead of loading in loops

  • Bound queries with Take() to prevent loading thousands of items

  • Use constructor injection instead of ServiceLocator

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Coding

umbraco-development

No summary provided by upstream source.

Repository SourceNeeds Review
General

frontend-razor

No summary provided by upstream source.

Repository SourceNeeds Review
General

optimizely-content-cloud

No summary provided by upstream source.

Repository SourceNeeds Review
General

optimizely-experimentation

No summary provided by upstream source.

Repository SourceNeeds Review