orchardcore-theme-creator
Creates new Orchard Core themes with proper structure, manifest, layouts, and assets. Use when the user needs to create a new theme, customize layouts, or set up frontend assets.
SKILL.mdsrc/CrestApps.AgentSkills/orchardcore/orchardcore-theme-creator/SKILL.md
GitHubOrchard Core Theme Creator
Step-by-step creation of a theme project for an Orchard Core site built on NuGet packages. For shape overrides, alternates, placement, and admin theme customization once the theme exists, use orchardcore-theming.
Prerequisites
- .NET SDK 10.0+.
- An Orchard Core web project (startup project) that references
OrchardCore.Application.Cms.Targets(seeorchardcore-setup). - Node.js and Yarn only when the theme compiles SCSS or scripts (see
orchardcore-asset-manager).
Theme Creation Workflow
Step 1: Scaffold the project
Use the Orchard Core project templates:
dotnet new install OrchardCore.ProjectTemplates
dotnet new octheme -n Contoso.Theme -o src/Themes/Contoso.Theme
dotnet sln add src/Themes/Contoso.Theme/Contoso.Theme.csproj
dotnet add src/Contoso.Web/Contoso.Web.csproj reference src/Themes/Contoso.Theme/Contoso.Theme.csproj
octheme creates Manifest.cs, the project file, and a Views/Layout.liquid (pass --AddLiquid false to skip the Liquid files and --OrchardVersion to pick the Orchard Core package version). Create the theme folder next to the web project, not inside it, and reference it from the web project; a theme that is not referenced by the startup project is never discovered.
Step 2: Project file
The theme project references OrchardCore.Theme.Targets, which marks the assembly as a theme. Use the Razor SDK when the theme has .cshtml files:
<Project Sdk="Microsoft.NET.Sdk.Razor">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<AddRazorSupportForMvc>true</AddRazorSupportForMvc>
</PropertyGroup>
<ItemGroup>
<FrameworkReference Include="Microsoft.AspNetCore.App" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="OrchardCore.Theme.Targets" Version="3.*" />
<PackageReference Include="OrchardCore.ContentManagement" Version="3.*" />
<PackageReference Include="OrchardCore.DisplayManagement" Version="3.*" />
<PackageReference Include="OrchardCore.ResourceManagement" Version="3.*" />
</ItemGroup>
</Project>
A Liquid-only theme can use Microsoft.NET.Sdk; switch to Microsoft.NET.Sdk.Razor as soon as you add Razor views.
Step 3: Manifest.cs
using OrchardCore.DisplayManagement.Manifest;
[assembly: Theme(
Name = "Contoso Theme",
Author = "Contoso",
Website = "https://contoso.com",
Version = "1.0.0",
Description = "The Contoso front-end theme.",
BaseTheme = "TheTheme",
Tags = ["Bootstrap"]
)]
- The theme ID is the assembly name (
Contoso.Theme);Nameis only the display name. BaseThemetakes the ID of another theme (TheTheme,TheBlogTheme,TheAgencyTheme,TheComingSoonTheme,TheAdmin,SafeMode, or one of yours). Templates andplacement.jsonrules of the base theme apply unless your theme overrides them; static files keep their own URL (~/TheTheme/...). Omit it for a standalone theme.- Add the
Admintag (ManifestConstants.AdminTag) toTagsfor an admin theme so it is offered as an admin theme, and usually setBaseTheme = "TheAdmin". Dependencies = ["OrchardCore.Menu"]enables features the theme needs.ManifestConstants.OrchardCoreTeam,OrchardCoreWebsite, andOrchardCoreVersiondescribe Orchard Core's own themes; use your own author, website, and version.
Shipping extra features with the theme: a theme assembly can also declare [assembly: Feature(Id = "Contoso.Theme.Widgets", Name = "...", Category = "Theming")] (from OrchardCore.Modules.Manifest). In Orchard Core 4.0 the theme still appears on the Themes page and the extra features appear on the Features page; bind their services with [Feature("Contoso.Theme.Widgets")] on a Startup class.
Step 4: Views/_ViewImports.cshtml (Razor themes)
@inherits OrchardCore.DisplayManagement.Razor.RazorPage<TModel>
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@addTagHelper *, OrchardCore.DisplayManagement
@addTagHelper *, OrchardCore.ResourceManagement
Add @addTagHelper *, OrchardCore.Menu when the layout uses the <menu> tag helper (and reference the OrchardCore.Menu package). A missing @inherits line causes build errors in Razor views.
Step 5: Create the layout
Views/Layout.cshtml (or Views/Layout.liquid) is the site layout:
<!DOCTYPE html>
<html lang="@Orchard.CultureName()" dir="@Orchard.CultureDir()">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>@RenderTitleSegments(Site.SiteName, "before")</title>
<style asp-name="bootstrap" version="5" at="Head"></style>
<style asp-name="Contoso.Theme" asp-src="~/Contoso.Theme/css/site.min.css" debug-src="~/Contoso.Theme/css/site.css" depends-on="bootstrap:5" at="Head"></style>
<script asp-name="bootstrap" version="5" at="Foot"></script>
<script asp-name="Contoso.Theme" asp-src="~/Contoso.Theme/js/site.min.js" debug-src="~/Contoso.Theme/js/site.js" at="Foot"></script>
<resources type="Header" />
@await RenderSectionAsync("HeadMeta", required: false)
</head>
<body>
@await RenderSectionAsync("Header", required: false)
<main class="container">
@await RenderSectionAsync("Messages", required: false)
@await RenderBodyAsync()
</main>
@if (IsSectionDefined("Footer"))
{
<footer class="container">
@await RenderSectionAsync("Footer", required: false)
</footer>
}
<resources type="FootScript" />
</body>
</html>
The Liquid equivalent:
<!DOCTYPE html>
<html lang="{{ Culture.Name }}" dir="{{ Culture.Dir }}">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>{% page_title Site.SiteName, position: "before" %}</title>
{% style name: "bootstrap", version: "5", at: "Head" %}
{% script name: "bootstrap", version: "5", at: "Foot" %}
{% resources type: "Header" %}
{% render_section "HeadMeta", required: false %}
</head>
<body>
{% render_section "Header", required: false %}
<main class="container">
{% render_section "Messages", required: false %}
{% render_body %}
</main>
{% render_section "Footer", required: false %}
{% resources type: "FootScript" %}
</body>
</html>
RenderBodyAsync()/{% render_body %}renders theContentzone;RenderSectionAsync(name, required: false)/{% render_section %}renders any other zone.<zone name="...">and{% zone %}only add content to a zone, they never render one.<resources type="Header" />renders the meta, link, stylesheet, and head script resources (Meta,HeadLink,Stylesheet,HeadScriptcan also be rendered separately);<resources type="FootScript" />renders the foot scripts.- Shapes that register resources must render before
<resources type="Header" />; pre-render such shapes into a variable at the top of the layout. - Require every script the theme uses. Orchard Core 4.0 no longer loads jQuery through admin or module scripts; add
<script asp-name="jQuery" at="Foot"></script>only if the theme needs it.
Step 6: Static files and thumbnail
- Files under the theme's
wwwroot/are served at~/{ThemeId}/..., for example~/Contoso.Theme/css/site.css. - Add
wwwroot/Theme.pngto show a thumbnail on Design → Themes. - To reference resources by name everywhere, define them in a resource manifest registered from a theme
Startupwithservices.AddResourceConfiguration<T>()(seeorchardcore-theming).
Step 7: Add assets (optional)
Assets/
├── scss/site.scss
├── js/site.js
└── package.json
Assets.json
See references/assets.md for the files and orchardcore-asset-manager for which parts of the asset pipeline work outside the Orchard Core repository.
Step 8: Build and activate
dotnet build
dotnet run --project src/Contoso.Web
Enable and select the theme on Design → Themes, or from a recipe:
{
"steps": [
{
"name": "feature",
"enable": ["Contoso.Theme"]
},
{
"name": "themes",
"site": "Contoso.Theme",
"admin": "TheAdmin"
}
]
}
Quick Reference
Common Zones
| Zone | Purpose |
|---|---|
HeadMeta |
Meta/link tags rendered inside <head> |
Header |
Site header |
Navigation |
Main menu |
Messages |
Alerts/notifications |
BeforeContent / AfterContent |
Around the main content |
Content |
Main content (rendered by RenderBodyAsync) |
Sidebar |
Side widgets |
Footer |
Site footer |
A layout zone is filled by widgets (Layers), placement.json rules whose place starts with /, or <zone> blocks in views. For widgets, also list the zone names on Design → Settings → Zones (see orchardcore-layers).
Built-in Base Themes
| Theme ID | Description |
|---|---|
TheTheme |
Default Bootstrap front-end theme |
TheBlogTheme |
Blog theme (Liquid) |
TheAgencyTheme |
Agency/business theme |
TheComingSoonTheme |
Coming soon page |
TheAdmin |
Admin theme |
SafeMode |
Minimal fallback theme |
Naming Conventions
| Item | Convention |
|---|---|
| Theme project and ID | Company.ThemeName (PascalCase) |
| Static file URL | ~/Company.ThemeName/... |
| Resource names | Theme ID or Company.ThemeName.Part |
| CSS / JS entry | site.css / site.js |
Inside the Orchard Core repository
Only when contributing a theme to Orchard Core itself: put it under src/OrchardCore.Themes/, use ProjectReferences to src/OrchardCore/OrchardCore.Theme.Targets instead of packages, use ManifestConstants in the manifest, and build assets with the repository's yarn build -n <name>.
References
references/theme-structure.md- Directory layout and templatesreferences/assets.md- SCSS, JS, and asset pipeline