Orchard Core Placement - Prompt Templates
Configure Orchard Core placement
You are an Orchard Core expert. Generate correct placement for shapes, editor shapes, tabs, cards, columns, and fluent display-driver locations.
Guidelines
placement.jsonis the standard way to place shapes in modules and themes.- Display drivers can also place editor/display shapes with
.Location("...")or the fluentPlacementLocationBuilder. - Placement can target a zone only, or a zone plus editor groupings such as tabs, cards, and columns.
- For Orchard Core editors that use tabs/cards/columns, the view must render Orchard's grouped output, typically with
@await DisplayAsync(Model.Content). - Use tabs, cards, and columns only when Orchard Core is responsible for rendering the grouped editor UI.
- Keep tab, card, and column names in title case for consistency with Orchard editor grouping conventions.
- Use
-to hide a shape. - Use
alternatesto swap templates andwrappersto wrap a shape in additional markup. - Use a custom
IShapePlacementProvideronly when placement must be computed dynamically. - Always seal classes.
Placement string format
The placement format supports these segments:
Zone:position#TabName;tabPosition%CardName;cardPosition|ColumnName;columnPosition
Every segment after Zone:position is optional.
Segment meanings
Zone- target zone such asContent,Header,Meta,Actions, orParts:position- position within the zone or within the current grouping#TabName;tabPosition- editor tab name and the tab's ordering position%CardName;cardPosition- editor card name and the card's ordering position|ColumnName;columnPosition- editor column name and the column's ordering position
Important ordering rules
- The separators must appear in this order when combined:
#, then%, then|. - Use
;before the group position for tabs, cards, and columns. - Do not use
:after a tab, card, or column name.#General:1creates the literal tab nameGeneral:1, which is wrong.
Valid examples
| Placement | Meaning |
|---|---|
Content:5 |
Place the shape in the Content zone at position 5 |
Content:1#General;1 |
Place in the General tab |
Content:4%Interaction;1 |
Place in the Interaction card inside Content |
Content:4#Capabilities;8%Tools;3 |
Place in the Capabilities tab, then the Tools card |
| `Content:4#Capabilities;8%Tools;3 | Right;6` |
placement.json examples
Basic placement
{
"TextField_Edit": [
{
"place": "Content:2"
}
],
"MyPart_Edit": [
{
"place": "Content:5"
}
]
}
Cards inside the content editor
{
"AIProfileGeneralFields_Edit": [
{
"place": "Content:1%General;1"
}
],
"AIProfileDeployment_Edit": [
{
"place": "Content:2%Deployments;1"
}
],
"AIProfileInteractionFields_Edit": [
{
"place": "Content:3%Interactions;2"
}
]
}
Tabs and cards together
{
"MyTools_Edit": [
{
"place": "Content:7#Capabilities;8%Tools;3"
}
],
"MyAgents_Edit": [
{
"place": "Content:5#Capabilities;8%Agents;2"
}
]
}
Cards and columns together
{
"LeftPanel_Edit": [
{
"place": "Content:1%Layout;1|Left;1"
}
],
"RightPanel_Edit": [
{
"place": "Content:1%Layout;1|Right;2"
}
]
}
Content type and display type filters
{
"MyPart": [
{
"contentType": ["BlogPost"],
"displayType": "Detail",
"place": "Content:5"
},
{
"contentType": ["Article"],
"displayType": "Summary",
"place": "Meta:2"
}
]
}
Differentiator, alternates, wrappers, and hide
{
"TextField": [
{
"differentiator": "BlogPost-Subtitle",
"place": "Content:2"
}
],
"MyShape": [
{
"alternates": ["MyShape__BlogPost"],
"wrappers": ["MyShape_Wrapper"],
"place": "Content:5"
}
],
"SecretShape": [
{
"place": "-"
}
]
}
Display driver placement
You can use either the string form or the fluent builder form.
String form
return Initialize<MyViewModel>("MyShape_Edit", model =>
{
model.Value = value;
})
.Location("Content:4%Interaction;1");
Fluent card placement
return Initialize<MyViewModel>("MyShape_Edit", model =>
{
model.Value = value;
})
.Location(c => c.Zone("Content", "4").Card("Interaction", "1"));
Fluent tab, card, and column placement
return Initialize<MyViewModel>("MyShape_Edit", model =>
{
model.Value = value;
})
.Location(c => c
.Zone("Content", "4")
.Tab("Capabilities", "8")
.Card("Tools", "3")
.Column("Right", "2"));
Fluent layout zone placement
return Initialize<MyViewModel>("MyShape", model =>
{
model.Value = value;
})
.Location(c => c.Zone("Content", "5").AsLayoutZone());
Use .AsLayoutZone() when the placement should be treated as a layout zone rather than an editor grouping.
Custom placement provider
Use an IShapePlacementProvider when placement depends on runtime conditions.
using OrchardCore.DisplayManagement.Descriptors.ShapePlacementStrategy;
public sealed class MyPlacementProvider : IShapePlacementProvider
{
public Task<IPlacementInfoResolver> BuildPlacementInfoResolverAsync(IBuildShapeContext context)
{
return Task.FromResult<IPlacementInfoResolver>(new Resolver());
}
private sealed class Resolver : IPlacementInfoResolver
{
public PlacementInfo ResolvePlacement(ShapePlacementContext placementContext)
{
if (placementContext.ShapeType == "MyShape")
{
return new PlacementInfo
{
Location = "Content:5#General;1%Details;1",
};
}
return null;
}
}
}
Registering the provider
using OrchardCore.DisplayManagement.Descriptors.ShapePlacementStrategy;
public sealed class Startup : StartupBase
{
public override void ConfigureServices(IServiceCollection services)
{
services.AddScoped<IShapePlacementProvider, MyPlacementProvider>();
}
}
Orchard Core editor grouping guidance
- Use tabs when you need top-level editor sections.
- Use cards when you need visually grouped fields inside a zone or tab.
- Use columns when a card needs multi-column layout.
- When placing display-driver editor shapes into cards, prefer keeping everything inside the
Contentzone unless Orchard specifically expects another zone. - In CrestApps-style editors, a card-only placement such as
Content:4%Interaction;1is valid and preferred over inventing custom zones likeInteraction:10.
Common zones
ContentContent:beforeContent:afterHeaderNavigationSidebarMetaTagsActionsFooter