Orchard Core Display Management - Prompt Templates
SkillDev toolsLets your agent change how OrchardCore pages render, like positioning, hiding, or moving content parts and fields.
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the Orchard Core Display Management - Prompt Templates skill
About this capability
Controls how OrchardCore renders content — placement.json rules, display drivers, shapes, zones, alternates, and editor groupings (tabs/cards/columns). Use when the user needs to position or hide a part/field, move a shape to another zone, add alternates or wrappers, build admin editor layouts, or w
What this skill tells your AI
The instructions your AI receives, as published by orchardcms/orchardcore in .agents/skills/orchardcore-display-management/SKILL.md and read by ahel’s review.
Create Display Drivers and Shapes
You are an Orchard Core expert. Generate display drivers, shapes, and display management code for Orchard Core.
Guidelines
- Every content part that needs custom rendering requires a
DisplayDriver. - Display drivers inherit from
ContentPartDisplayDriver<TPart>. - Drivers handle three operations:
Display,Edit, andUpdate. - Each operation returns
IDisplayResult(shapes to render). - View models are used to pass data between drivers and views.
- Shape names follow the convention
{PartName}for display and{PartName}_Editfor editor. - Use
Initialize<TModel>to create shapes with a view model. - Register drivers in
Startup.csusingservices.AddContentPart<TPart>().UseDisplayDriver<TDriver>(). - For non-content-item models rendered through
DisplayDriver<TModel>, the root shape still needs its own wrapper template for each display type you build (for example,CampaignAction.Edit.cshtmlforCampaignAction_EditandCampaignAction.SummaryAdmin.cshtmlforCampaignAction_SummaryAdmin). - When driver results are placed into zones with
.Location("Content:1"),.Location("Actions:5"), or similar, the wrapper template must render those zones (Model.Content,Model.Actions,Model.Meta, etc.) or the child shapes will never appear. - For ALL admin editor views (
*.Edit.cshtmlincluding*Settings.Edit.cshtml), use theocat-*(Orchard Core Admin Theme) CSS classes instead of rawmb-3,form-label, or hard-coded grid classes. Useocat-wrapperfor the outer row,ocat-labelfor labels,ocat-endfor the input column,ocat-end-offsetfor checkbox-only rows/headings/buttons with no left label,ocat-limited-wrapper+ocat-limitedfor narrow-width fields. Do NOT apply these classes to frontend views (Login, Register, etc.) or Admin Menu node editing (needs full width). - The former
@Orchard.GetWrapperClasses(),@Orchard.GetLabelClasses(),@Orchard.GetEndClasses()helper methods andTheAdminThemeOptionsclass have been removed. Use the staticocat-*CSS classes directly. - Always seal classes.
Content Part Display Driver Pattern
using OrchardCore.ContentManagement.Display.ContentDisplay;
using OrchardCore.ContentManagement.Display.Models;
using OrchardCore.DisplayManagement.ModelBinding;
using OrchardCore.DisplayManagement.Views;
public sealed class {{PartName}}DisplayDriver : ContentPartDisplayDriver<{{PartName}}>
{
public override IDisplayResult Display({{PartName}} part, BuildPartDisplayContext context)
{
return Initialize<{{PartName}}ViewModel>("{{PartName}}", model =>
{
model.{{PropertyName}} = part.{{PropertyName}};
model.ContentItem = part.ContentItem;
})
.Location("Detail", "Content:5")
.Location("Summary", "Content:5");
}
public override IDisplayResult Edit({{PartName}} part, BuildPartEditorContext context)
{
return Initialize<{{PartName}}ViewModel>("{{PartName}}_Edit", model =>
{
model.{{PropertyName}} = part.{{PropertyName}};
model.ContentItem = part.ContentItem;
});
}
public override async Task<IDisplayResult> UpdateAsync({{PartName}} part, UpdatePartEditorContext context)
{
var model = new {{PartName}}ViewModel();
await context.Updater.TryUpdateModelAsync(model, Prefix);
part.{{PropertyName}} = model.{{PropertyName}};
return Edit(part, context);
}
}
View Model Pattern
using OrchardCore.ContentManagement;
public class {{PartName}}ViewModel
{
public string {{PropertyName}} { get; set; }
public ContentItem ContentItem { get; set; }
}
Display Shape View (Views/{{PartName}}.cshtml)
@model {{Namespace}}.ViewModels.{{PartName}}ViewModel
<p>@Model.{{PropertyName}}</p>
Editor Shape View (Views/{{PartName}}_Edit.cshtml)
@model {{Namespace}}.ViewModels.{{PartName}}ViewModel
<div class="ocat-wrapper" asp-validation-class-for="{{PropertyName}}">
<label asp-for="{{PropertyName}}" class="ocat-label">{{DisplayLabel}}</label>
<div class="ocat-end">
<input asp-for="{{PropertyName}}" class="form-control" />
<span asp-validation-for="{{PropertyName}}"></span>
</div>
</div>
Registering a Display Driver
using OrchardCore.ContentManagement;
using OrchardCore.ContentManagement.Display.ContentDisplay;
public sealed class Startup : StartupBase
{
public override void ConfigureServices(IServiceCollection services)
{
services.AddContentPart<{{PartName}}>()
.UseDisplayDriver<{{PartName}}DisplayDriver>();
}
}
Content Part with Handler Pattern
using OrchardCore.ContentManagement;
using OrchardCore.ContentManagement.Handlers;
public sealed class {{PartName}}Handler : ContentPartHandler<{{PartName}}>
{
public override Task InitializingAsync(InitializingContentContext context, {{PartName}} part)
{
part.{{PropertyName}} = "default value";
return Task.CompletedTask;
}
}
Display Types
Orchard Core uses display types to differentiate how content is rendered:
Detail— Full content display (e.g., a blog post page).Summary— Abbreviated display (e.g., in a list).SummaryAdmin— Admin-specific summary view.Edit— Editor form for the content part.
Wrapper Templates for DisplayDriver<TModel>
CRITICAL: When you use DisplayDriver<TModel> (not ContentPartDisplayDriver), Orchard Core resolves a root shape for each display type. If this root shape template does not exist, you get InvalidOperationException: The shape type '{ModelName}_Edit' is not found. You must create wrapper templates for every display type the driver builds shapes for.
Required wrapper templates per display type:
| Display type built by driver | Required wrapper template file |
|---|---|
Edit (via Edit() / BuildEditorAsync) | Views/{ModelName}.Edit.cshtml |
SummaryAdmin (via DisplayAsync + Location("Content:1")) | Views/{ModelName}.SummaryAdmin.cshtml |
| Detail | Views/{ModelName}.cshtml |
| Summary | Views/{ModelName}.Summary.cshtml |
The wrapper template renders the zones that child shapes are placed into. If the wrapper doesn't render a zone (e.g., Model.Content, Model.Actions, Model.Meta), the child shapes placed in those zones will be silently dropped.
Example driver:
internal sealed class CampaignActionDisplayDriver : DisplayDriver<CampaignAction>
{
public override Task<IDisplayResult> DisplayAsync(CampaignAction model, BuildDisplayContext context)
{
return CombineAsync(
View("CampaignAction_Fields_SummaryAdmin", model)
.Location(OrchardCoreConstants.DisplayType.SummaryAdmin, "Content:1"),
View("CampaignAction_Buttons_SummaryAdmin", model)
.Location(OrchardCoreConstants.DisplayType.SummaryAdmin, "Actions:5")
);
}
public override IDisplayResult Edit(CampaignAction model, BuildEditorContext context)
=> Initialize<CampaignActionViewModel>("CampaignActionFields_Edit", m => { })
.Location("Content:1");
}
Required wrapper templates:
Views/CampaignAction.Edit.cshtmlfor the rootCampaignAction_Editshape.Views/CampaignAction.SummaryAdmin.cshtmlfor the rootCampaignAction_SummaryAdminshape.
Minimal edit wrapper:
@if (Model.Content != null)
{
@await DisplayAsync(Model.Content)
}
Summary admin wrapper with zones:
<div class="row g-0">
<div class="col-lg col-12">
@if (Model.Content != null)
{
@await DisplayAsync(Model.Content)
}
@if (Model.Meta != null)
{
@await DisplayAsync(Model.Meta)
}
</div>
<div class="col-lg-auto col-12">
@if (Model.Actions != null)
{
@await DisplayAsync(Model.Actions)
}
</div>
</div>
Child shape file-name mapping:
CampaignAction_Fields_SummaryAdmin→Views/Items/CampaignAction.Fields.SummaryAdmin.cshtmlCampaignAction_Buttons_SummaryAdmin→Views/Items/CampaignAction.Buttons.SummaryAdmin.cshtmlCampaignActionFields_Edit→Views/CampaignActionFields.Edit.cshtml
Placing Shapes in Zones
Use .Location() to place shapes in zones with positions:
return Initialize<MyViewModel>("MyShape", model => { ... })
.Location("Detail", "Content:5") // Detail view, Content zone, position 5
.Location("Summary", "Meta:5") // Summary view, Meta zone, position 5
.Location("SummaryAdmin", "Actions:5"); // Admin summary, Actions zone, position 5
Content Field Display Driver
using OrchardCore.ContentManagement.Display.ContentDisplay;
using OrchardCore.ContentManagement.Display.Models;
public sealed class {{FieldName}}FieldDisplayDriver : ContentFieldDisplayDriver<{{FieldName}}Field>
{
public override IDisplayResult Display({{FieldName}}Field field, BuildFieldDisplayContext context)
{
return Initialize<{{FieldName}}FieldViewModel>(
GetDisplayShapeType(context),
model =>
{
model.Field = field;
model.Part = context.ContentPart;
model.PartFieldDefinition = context.PartFieldDefinition;
})
.Location("Detail", "Content")
.Location("Summary", "Content");
}
}
Shape Table Provider
Override shape rendering behavior:
using OrchardCore.DisplayManagement.Descriptors;
public sealed class MyShapeTableProvider : IShapeTableProvider
{
public ValueTask DiscoverAsync(ShapeTableBuilder builder)
{
builder.Describe("Content")
.OnDisplaying(context =>
{
// Add alternates, wrappers, etc.
context.Shape.Metadata.Alternates.Add("Content__{{ContentType}}");
});
return ValueTask.CompletedTask;
}
}
Shape Debug Information
You can instruct Orchard Core to write HTML comments around rendered shapes. This makes it easier to identify which Razor or Liquid template produced a specific fragment in the page output.
Enable directly through options:
services.Configure<ShapeRenderingOptions>(options =>
options.WriteShapeDebugInformation = true);
When OrchardCore.Settings is enabled, the site's debug settings configure the same ShapeRenderingOptions.WriteShapeDebugInformation value.
When enabled, rendered shapes are wrapped with HTML comments:
<!--shape-start type:Menu bindings:Menu__Main=>Themes/Contoso/Views/Menu-Main.cshtml (razor)-->
...
<!--shape-end type:Menu-->
The start comment contains the shape type and the binding that was used. Razor bindings report the .cshtml path, while Liquid bindings report a virtual .liquid source. This is useful during development to trace which template is responsible for each fragment of the rendered page.
Signals
- GitHub stars
- 8k
- Forks
- 3k
- Last commit
- Sep 2026
Advanced
- Catalog kind
- skill
- Gateway key
orchardcore-display-management- Source
- github.com/orchardcms/orchardcore