sitecore-classic

twofoldtech-dakota's avatarfrom twofoldtech-dakota

Apply when working with Sitecore 10.x projects, Helix architecture, MVC renderings, or Sitecore APIs

⭐0stars🔀0forks📁View on GitHub🕐Updated Jan 10, 2026⬇️1downloads

When & Why to Use This Skill

This Claude skill is a comprehensive development assistant for Sitecore 10.x projects, specifically tailored for the Helix architecture. It provides expert guidance on .NET MVC renderings, Sitecore API integration, and best practices for building scalable, maintainable enterprise CMS solutions. By enforcing dependency rules and providing optimized code patterns for search, caching, and serialization, it helps developers reduce technical debt and improve application performance.

Use Cases

  • Architecting Helix-compliant solutions by correctly separating concerns into Foundation, Feature, and Project layers.
  • Optimizing data access by replacing slow Sitecore.Query and GetDescendants calls with efficient Solr Content Search patterns.
  • Implementing robust Dependency Injection (DI) using IServicesConfigurator for service registration and constructor injection in controllers.
  • Managing complex environment-specific configurations through advanced Sitecore XML patching and role-based settings.
  • Streamlining DevOps workflows using Sitecore Content Serialization (SCS) and CLI commands for automated item deployment.
namesitecore-classic
descriptionApply when working with Sitecore 10.x projects, Helix architecture, MVC renderings, or Sitecore APIs

Bundled Skills

This plugin includes the following additional skills for comprehensive development context:

Skill Purpose
frontend-classic CSS/SASS organization, JavaScript/jQuery patterns, BEM naming
frontend-razor Razor view syntax, layouts, partials, tag helpers
backend-csharp C#/.NET DI patterns, service architecture, async/await
fullstack-classic jQuery AJAX integration, form handling, anti-forgery tokens

These skills are automatically included when you install the Sitecore Classic Analyzer plugin.

Sitecore 10.x Development Patterns

Helix Architecture

Layer Responsibilities

Foundation Layer

  • Cross-cutting concerns shared across features
  • Examples: Logging, Serialization, DI registration, Indexing, ORM
  • No business logic, only technical infrastructure
  • Can reference other Foundation modules

Feature Layer

  • Business capabilities and features
  • Examples: Navigation, Search, Forms, Checkout, Articles
  • Each feature is independent and self-contained
  • Can reference Foundation modules only
  • NEVER reference other Feature modules

Project Layer

  • Tenant/site-specific implementations
  • Examples: Website, Corporate, MobileApp
  • Assembles features for specific sites
  • Can reference Feature and Foundation modules

Dependency Rule

Project → Feature → Foundation

Features must NEVER reference other Features. If shared logic is needed, extract to Foundation.

Folder Structure

src/
├── Foundation/
│   └── {Module}/
│       ├── code/
│       │   ├── DependencyInjection/
│       │   ├── Services/
│       │   └── Foundation.{Module}.csproj
│       └── serialization/
│           └── {Module}.module.json
├── Feature/
│   └── {Module}/
│       ├── code/
│       │   ├── Controllers/
│       │   ├── Models/
│       │   ├── Services/
│       │   ├── Repositories/
│       │   └── Feature.{Module}.csproj
│       └── serialization/
│           ├── Templates/
│           ├── Renderings/
│           └── {Module}.module.json
└── Project/
    └── {Site}/
        ├── code/
        │   ├── Layouts/
        │   └── Project.{Site}.csproj
        └── serialization/
            ├── Content/
            └── {Site}.module.json

Dependency Injection

Service Registration

using Microsoft.Extensions.DependencyInjection;
using Sitecore.DependencyInjection;

public class RegisterDependencies : IServicesConfigurator
{
    public void Configure(IServiceCollection services)
    {
        // Transient: New instance each time
        services.AddTransient<ISearchService, SearchService>();

        // Scoped: One instance per HTTP request
        services.AddScoped<INavigationService, NavigationService>();

        // Singleton: One instance for application lifetime
        services.AddSingleton<ICacheService, CacheService>();
    }
}

Config Registration

<?xml version="1.0" encoding="utf-8"?>
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
  <sitecore>
    <services>
      <configurator type="Foundation.DI.RegisterDependencies, Foundation.DI" />
    </services>
  </sitecore>
</configuration>

Constructor Injection

public class NavigationController : Controller
{
    private readonly INavigationService _navigationService;
    private readonly ILogger<NavigationController> _logger;

    public NavigationController(
        INavigationService navigationService,
        ILogger<NavigationController> logger)
    {
        _navigationService = navigationService;
        _logger = logger;
    }

    public ActionResult Index()
    {
        var datasource = RenderingContext.Current.Rendering.Item;
        if (datasource == null)
        {
            _logger.LogWarning("Navigation datasource is null");
            return new EmptyResult();
        }

        var model = _navigationService.GetNavigation(datasource);
        return View(model);
    }
}

Content Access Patterns

public class SearchRepository : ISearchRepository
{
    private readonly ISearchIndex _index;

    public SearchRepository(ISearchIndexResolver indexResolver)
    {
        _index = indexResolver.GetIndex("sitecore_web_index");
    }

    public IEnumerable<ArticleSearchResult> GetArticles(
        ID templateId,
        string language,
        int maxResults = 100)
    {
        using (var context = _index.CreateSearchContext())
        {
            return context.GetQueryable<ArticleSearchResult>()
                .Where(x => x.TemplateId == templateId)
                .Where(x => x.Language == language)
                .OrderByDescending(x => x.Created)
                .Take(maxResults)
                .ToList();
        }
    }
}

Avoid Sitecore.Query (Slow)

// BAD - Tree traversal, O(n) where n = tree size
var items = item.Axes.SelectItems(".//*[@@templateid='{GUID}']");

// BAD - Even "fast:" queries traverse the tree
var items = Database.SelectItems("fast:/sitecore/content//*");

// GOOD - Use Content Search instead
var items = searchContext.GetQueryable<SearchResultItem>()
    .Where(x => x.TemplateId == templateId)
    .ToList();

Avoid GetDescendants (Memory Heavy)

// BAD - Loads entire subtree into memory
var allItems = rootItem.GetDescendants().ToList();

// GOOD - Use Content Search with path filter
var items = searchContext.GetQueryable<SearchResultItem>()
    .Where(x => x.Paths.Contains(rootItem.ID))
    .Take(1000)
    .ToList();

Caching

HTML Cache (Rendering Level)

Configure in rendering item or config:

<r>
  <d id="{FE5D7FDF-89C0-4D99-9AA3-B5FBD009C9F3}">
    <r uid="{RENDERING-UID}"
       s:caching="1"
       s:varybydata="1"
       s:varybydevice="0"
       s:varybylogin="0"
       s:varybyuser="0"
       s:varybyquerystirng="0"
       s:timeout="01:00:00" />
  </d>
</r>

Custom Cache

public class NavigationCache : CustomCache
{
    public NavigationCache(string name, long maxSize)
        : base(name, maxSize)
    {
    }

    public NavigationModel Get(string cacheKey)
    {
        return GetObject<NavigationModel>(cacheKey);
    }

    public void Set(string cacheKey, NavigationModel model, TimeSpan duration)
    {
        SetObject(cacheKey, model, duration);
    }
}

Register cache:

public class RegisterCaches : IServicesConfigurator
{
    public void Configure(IServiceCollection services)
    {
        services.AddSingleton<NavigationCache>(provider =>
            new NavigationCache("NavigationCache", StringUtil.ParseSizeString("50MB")));
    }
}

Configuration Patching

Basic Patch

<?xml version="1.0" encoding="utf-8"?>
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
  <sitecore>
    <settings>
      <setting name="MySetting" value="MyValue" />
    </settings>
  </sitecore>
</configuration>

Environment-Specific Settings

<?xml version="1.0" encoding="utf-8"?>
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/"
               xmlns:env="http://www.sitecore.net/xmlconfig/env/">
  <sitecore>
    <settings>
      <!-- Only in Production -->
      <setting name="Analytics.Enabled" env:require="Production">
        <patch:attribute name="value">true</patch:attribute>
      </setting>

      <!-- Only in Development -->
      <setting name="Analytics.Enabled" env:require="Development">
        <patch:attribute name="value">false</patch:attribute>
      </setting>
    </settings>
  </sitecore>
</configuration>

Role-Specific Settings

<?xml version="1.0" encoding="utf-8"?>
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/"
               xmlns:role="http://www.sitecore.net/xmlconfig/role/">
  <sitecore>
    <settings>
      <!-- Only on Content Management servers -->
      <setting name="Preview.Enabled" role:require="ContentManagement">
        <patch:attribute name="value">true</patch:attribute>
      </setting>

      <!-- Only on Content Delivery servers -->
      <setting name="Preview.Enabled" role:require="ContentDelivery">
        <patch:attribute name="value">false</patch:attribute>
      </setting>
    </settings>
  </sitecore>
</configuration>

Pipeline Processors

Custom Processor

public class EnrichContextProcessor : HttpRequestProcessor
{
    public override void Process(HttpRequestArgs args)
    {
        // Early exit for efficiency
        if (Context.Item == null) return;
        if (Context.Site == null) return;
        if (Context.PageMode.IsExperienceEditor) return;

        // Processor logic here
        EnrichContext();
    }

    private void EnrichContext()
    {
        // Custom enrichment logic
    }
}

Config Registration

<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
  <sitecore>
    <pipelines>
      <httpRequestBegin>
        <processor type="Feature.Context.EnrichContextProcessor, Feature.Context"
                   patch:after="processor[@type='Sitecore.Pipelines.HttpRequest.ItemResolver, Sitecore.Kernel']" />
      </httpRequestBegin>
    </pipelines>
  </sitecore>
</configuration>

Solr Index Configuration

Custom Index

<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
  <sitecore>
    <contentSearch>
      <configuration>
        <indexes>
          <index id="custom_articles_index">
            <configuration ref="contentSearch/indexConfigurations/defaultSolrIndexConfiguration">
              <documentOptions>
                <fields hint="raw:AddComputedIndexField">
                  <field fieldName="article_author" returnType="string">
                    Feature.Articles.ComputedFields.ArticleAuthor, Feature.Articles
                  </field>
                  <field fieldName="article_category" returnType="stringCollection">
                    Feature.Articles.ComputedFields.ArticleCategories, Feature.Articles
                  </field>
                </fields>
              </documentOptions>
            </configuration>
          </index>
        </indexes>
      </configuration>
    </contentSearch>
  </sitecore>
</configuration>

Computed Field

public class ArticleAuthor : IComputedIndexField
{
    public string FieldName { get; set; }
    public string ReturnType { get; set; }

    public object ComputeFieldValue(IIndexable indexable)
    {
        var item = (indexable as SitecoreIndexableItem)?.Item;
        if (item == null) return null;

        var authorItem = item.GetReferenceField("Author")?.TargetItem;
        return authorItem?["Name"];
    }
}

Sitecore Content Serialization (SCS)

module.json Structure

{
  "namespace": "Feature.Navigation",
  "items": {
    "includes": [
      {
        "name": "templates",
        "path": "/sitecore/templates/Feature/Navigation",
        "allowedPushOperations": "CreateUpdateAndDelete"
      },
      {
        "name": "renderings",
        "path": "/sitecore/layout/Renderings/Feature/Navigation",
        "allowedPushOperations": "CreateUpdateAndDelete"
      },
      {
        "name": "settings",
        "path": "/sitecore/system/Settings/Feature/Navigation",
        "allowedPushOperations": "CreateUpdateAndDelete"
      }
    ]
  }
}

CLI Commands

# Pull items from Sitecore to disk
dotnet sitecore ser pull

# Push items from disk to Sitecore
dotnet sitecore ser push

# Validate serialization
dotnet sitecore ser validate

Glass Mapper Patterns

Model Definition

[SitecoreType(TemplateId = "{GUID}", AutoMap = true)]
public class ArticlePage
{
    [SitecoreId]
    public virtual Guid Id { get; set; }

    [SitecoreField("Title")]
    public virtual string Title { get; set; }

    [SitecoreField("Content")]
    public virtual string Content { get; set; }

    [SitecoreField("Author")]
    public virtual Author Author { get; set; }

    [SitecoreChildren]
    public virtual IEnumerable<RelatedArticle> RelatedArticles { get; set; }
}

Service Usage

public class ArticleService : IArticleService
{
    private readonly ISitecoreService _sitecoreService;

    public ArticleService(ISitecoreService sitecoreService)
    {
        _sitecoreService = sitecoreService;
    }

    public ArticlePage GetArticle(Guid id)
    {
        return _sitecoreService.GetItem<ArticlePage>(id);
    }
}

Avoid N+1 Queries

// BAD - N+1 queries with lazy loading
foreach (var article in articles)
{
    var author = article.Author; // Lazy load for each article
}

// GOOD - Eager load or use Content Search
var articleIds = articles.Select(a => a.Id).ToList();
var authors = searchContext.GetQueryable<AuthorSearchResult>()
    .Where(x => articleIds.Contains(x.ArticleId))
    .ToList();