
Orchardcore Widgets
- 1 installs
- 13 repo stars
- Updated August 3, 2026
- crestapps/crestapps.agentskills
Build reusable Orchard Core widgets for page content and layout composition.
About
OrchardCore Widgets skill guides agents through widget development, registration, and rendering in Orchard Core applications.
- Widget registration and lifecycle
- Widget rendering patterns
Orchardcore Widgets by the numbers
- 1 all-time installs (skills.sh)
- Ranked #1,912 of 2,245 Frontend Development skills by installs in the Skillselion catalog
- Data as of Aug 4, 2026 (Skillselion catalog sync)
npx skills add https://github.com/crestapps/crestapps.agentskills --skill orchardcore-widgetsAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 1 |
|---|---|
| repo stars | ★ 13 |
| Last updated | August 3, 2026 |
| Repository | crestapps/crestapps.agentskills ↗ |
What it does
Build reusable Orchard Core widgets for page content and layout composition.
Files
Orchard Core Widgets - Prompt Templates
Create and Manage Widgets
You are an Orchard Core expert. Generate widget definitions, layer configurations, and zone placement for Orchard Core.
Guidelines
- Widgets are content types with the
Widgetstereotype. - Widgets are placed in zones defined by the theme layout.
- Layers control when widgets are visible using rule expressions.
- Enable
OrchardCore.WidgetsandOrchardCore.Layersfor widget support. - Each widget is a content item that can be edited from the admin panel.
- Layer rules use JavaScript-like expressions to control visibility.
- Use
FlowPartto allow widgets inside content items. WidgetsListParteditor wrapper placement usesContentPart_Editwith differentiator{ContentType}-{PartName}.WidgetsListPartdoes not render its own front-end display shape; it injects widgets directly into layout zones.
Enabling Widget Features
{
"steps": [
{
"name": "Feature",
"enable": [
"OrchardCore.Widgets",
"OrchardCore.Layers",
"OrchardCore.Flows"
],
"disable": []
}
]
}Creating a Widget Content Type
public sealed class Migrations : DataMigration
{
private readonly IContentDefinitionManager _contentDefinitionManager;
public Migrations(IContentDefinitionManager contentDefinitionManager)
{
_contentDefinitionManager = contentDefinitionManager;
}
public async Task<int> CreateAsync()
{
await _contentDefinitionManager.AlterTypeDefinitionAsync("{{WidgetName}}", type => type
.DisplayedAs("{{WidgetDisplayName}}")
.Stereotype("Widget")
.WithPart("{{WidgetName}}", part => part
.WithPosition("0")
)
);
await _contentDefinitionManager.AlterPartDefinitionAsync("{{WidgetName}}", part => part
.WithField("{{FieldName}}", field => field
.OfType("{{FieldType}}")
.WithDisplayName("{{FieldDisplayName}}")
.WithPosition("0")
)
);
return 1;
}
}Layer Configuration via Recipe
{
"steps": [
{
"name": "Layers",
"Layers": [
{
"Name": "Always",
"LayerRule": {
"Conditions": [
{
"Name": "BooleanCondition",
"Value": true
}
]
},
"Description": "Widgets on this layer are always displayed."
},
{
"Name": "Homepage",
"LayerRule": {
"Conditions": [
{
"Name": "UrlCondition",
"Value": "^/$"
}
]
},
"Description": "Widgets on this layer are displayed on the homepage."
},
{
"Name": "Authenticated",
"LayerRule": {
"Conditions": [
{
"Name": "IsAuthenticatedCondition",
"Value": true
}
]
},
"Description": "Widgets on this layer are displayed for authenticated users."
}
]
}
]
}Layer Rule Expressions
Common layer rule conditions:
UrlCondition- Match by URL pattern (regex):^/$(homepage),^/blog/.*(blog section).IsAuthenticatedCondition- Visible for authenticated users.IsAnonymousCondition- Visible for anonymous users.RoleCondition- Visible for specific roles.CultureCondition- Visible for specific cultures.BooleanCondition- Always true/false.JavascriptCondition- Custom JavaScript expression.
Placing Widgets in Zones
Widgets are assigned to zones and layers via the admin UI or recipes:
{
"steps": [
{
"name": "Content",
"data": [
{
"ContentItemId": "widget-hero-banner",
"ContentType": "HeroBanner",
"DisplayText": "Welcome Banner",
"Latest": true,
"Published": true,
"LayerMetadata": {
"Layer": "Homepage",
"Zone": "Header",
"Position": 0
},
"HeroBanner": {
"Heading": {
"Text": "Welcome to Our Site"
},
"Description": {
"Html": "<p>Your one-stop solution.</p>"
}
}
}
]
}
]
}Widget Template (Liquid)
Create a template at Views/Widget-{{WidgetName}}.liquid:
<div class="widget widget-{{ Model.ContentItem.ContentType | downcase }}">
<h3>{{ Model.ContentItem.Content.{{WidgetName}}.Heading.Text }}</h3>
<div class="widget-body">
{{ Model.ContentItem.Content.{{WidgetName}}.Body.Html }}
</div>
</div>Widget Template (Razor)
Create a template at Views/Widget-{{WidgetName}}.cshtml:
@model OrchardCore.ContentManagement.ContentItem
<div class="widget">
<h3>@Model.Content.{{WidgetName}}.Heading.Text</h3>
<div class="widget-body">
@Html.Raw(Model.Content.{{WidgetName}}.Body.Html)
</div>
</div>FlowPart for Inline Widgets
Allow widgets inside content items using FlowPart:
await _contentDefinitionManager.AlterTypeDefinitionAsync("Page", type => type
.WithPart("FlowPart")
);FlowPart allows editors to add widgets inline within content item editing.
WidgetsListPart Editor Placement
To hide or move the whole WidgetsListPart editor row in the admin UI:
{
"ContentPart_Edit": [
{
"differentiator": "PlacementTest-WidgetsListPart",
"place": "-"
}
]
}If the part is attached as a named part, replace WidgetsListPart with the part name.
Common Built-in Widget Types
HtmlWidget- Renders custom HTML content.LiquidWidget- Renders Liquid template content.MenuWidget- Renders a menu.ContainerWidget- Contains other widgets in a layout.
Widget Best Practices
- Use the
Widgetstereotype for all widget content types. - Keep widget templates small and focused.
- Use layer rules to control visibility instead of conditional logic in templates.
- Test widgets across different zones and screen sizes.
- Use
FlowPartfor content-embedded widgets.
Widget Examples
Example 1: Hero Banner Widget
Migration
public int Create()
{
_contentDefinitionManager.AlterTypeDefinition("HeroBanner", type => type
.DisplayedAs("Hero Banner")
.Stereotype("Widget")
.WithPart("HeroBanner", part => part
.WithPosition("0")
)
);
_contentDefinitionManager.AlterPartDefinition("HeroBanner", part => part
.WithField("Heading", field => field
.OfType("TextField")
.WithDisplayName("Heading")
.WithPosition("0")
)
.WithField("Subheading", field => field
.OfType("TextField")
.WithDisplayName("Subheading")
.WithPosition("1")
)
.WithField("BackgroundImage", field => field
.OfType("MediaField")
.WithDisplayName("Background Image")
.WithPosition("2")
)
.WithField("CallToAction", field => field
.OfType("LinkField")
.WithDisplayName("Call to Action")
.WithPosition("3")
)
);
return 1;
}Liquid Template (Views/Widget-HeroBanner.liquid)
<section class="hero-banner"
style="background-image: url('{{ Model.ContentItem.Content.HeroBanner.BackgroundImage.Paths[0] | asset_url | append: '?width=1920&height=600&rmode=crop' }}')">
<div class="container text-center">
<h1>{{ Model.ContentItem.Content.HeroBanner.Heading.Text }}</h1>
{% if Model.ContentItem.Content.HeroBanner.Subheading.Text %}
<p class="lead">{{ Model.ContentItem.Content.HeroBanner.Subheading.Text }}</p>
{% endif %}
{% if Model.ContentItem.Content.HeroBanner.CallToAction.Url %}
<a href="{{ Model.ContentItem.Content.HeroBanner.CallToAction.Url }}"
class="btn btn-primary btn-lg">
{{ Model.ContentItem.Content.HeroBanner.CallToAction.Text | default: "Learn More" }}
</a>
{% endif %}
</div>
</section>Example 2: Layer and Widget Placement Recipe
{
"steps": [
{
"name": "Layers",
"Layers": [
{
"Name": "Always",
"LayerRule": {
"Conditions": [
{
"Name": "BooleanCondition",
"Value": true
}
]
},
"Description": "Always visible"
},
{
"Name": "Homepage",
"LayerRule": {
"Conditions": [
{
"Name": "UrlCondition",
"Value": "^/$"
}
]
},
"Description": "Homepage only"
}
]
}
]
}Widget Content Item
{
"steps": [
{
"name": "Content",
"data": [
{
"ContentItemId": "widget-hero-home",
"ContentType": "HeroBanner",
"DisplayText": "Welcome Banner",
"Latest": true,
"Published": true,
"LayerMetadata": {
"Layer": "Homepage",
"Zone": "Header",
"Position": 0
},
"HeroBanner": {
"Heading": { "Text": "Welcome to Our Site" },
"Subheading": { "Text": "Discover amazing content" },
"CallToAction": {
"Url": "/about",
"Text": "Learn More"
}
}
}
]
}
]
}