CtrlK
BlogDocsLog inGet started
Tessl Logo

orchardcore-display-management

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 write a display driver.

71

Quality

86%

Does it follow best practices?

Run evals on this skill

Adds up to 20 points to the overall score

View guide

SecuritybySnyk

Passed

No findings from the security scan

SKILL.md
Quality
Evals
Security

OrchardCore Display Management

This skill guides you through OrchardCore's display system following project conventions.

OrchardCore renders content by building shapes (dynamic view models) from drivers, then placing each shape into a zone of the layout. Drivers decide what shapes exist and their default location; placement.json overrides where they go, whether they show, and which template renders them.

Mental model

ContentItem ──drivers──▶ shapes ──placement.json──▶ zones ──templates──▶ HTML
  • Shape — a dynamic object with a ShapeType and Metadata. The shape type (e.g. TextField, Parts_Contents_Publish, ContentPart) selects the template and the placement rule.
  • DriverDisplayDriver / ContentPartDisplayDriver / ContentFieldDisplayDriver. Returns IDisplayResults from Display, Edit, UpdateAsync, each with a default .Location(...).
  • Placementplacement.json at the root of a module or theme. Filters shapes and rewrites their location/visibility/template.
  • Zone — named region of the layout (Content, Header, Footer, Actions, …) or an editor group (tab/card/column).

Decide: driver vs placement

Want to…Use
Reposition / hide a shape someone else builtplacement.json
Move a shape to a layout zoneplacement.json (place starts with /)
Swap the template or add alternatesplacement.json (shape / alternates)
Lay out the admin editor (tabs/cards/columns)placement.json groupings
Produce a new shape from your part/fielddisplay driver
Read/write the editor modeldisplay driver (Edit / UpdateAsync)

Prefer placement.json for layout — no rebuild needed, theme can override.

Workflow A: place a shape

Step 1: Find the shape type and differentiator

The placement property name is the shape type, not the part name. A part without its own driver renders as ContentPart (differentiator = part name). A field renders as its field type (TextField) with differentiator {PartName}-{FieldName}.

See references/placement.md for the full differentiator table.

Step 2: Add a rule to placement.json

{
  "TextField": [
    {
      "differentiator": "Article-Subtitle",
      "displayType": "Detail",
      "place": "Content:2"
    }
  ]
}

Step 3: Verify

Run the site, view the content item. Use ?display debug shapes or the template's shape tracing to confirm the shape type. Wrong type → no rule matches.

Workflow B: write a display driver

Step 1: Inherit the right base

Base classFor
ContentPartDisplayDriver<TPart>a content part
ContentFieldDisplayDriver<TField>a content field
SectionDisplayDriver<TModel, TSection>settings sections
DisplayDriver<TModel>anything else

Step 2: Implement Display / Edit / Update

public sealed class TextFieldDisplayDriver : ContentFieldDisplayDriver<TextField>
{
    public override IDisplayResult Display(TextField field, BuildFieldDisplayContext context)
    {
        return Initialize<DisplayTextFieldViewModel>(GetDisplayShapeType(context), model =>
        {
            model.Field = field;
            model.Part = context.ContentPart;
            model.PartFieldDefinition = context.PartFieldDefinition;
        })
        .Location(OrchardCoreConstants.DisplayType.Detail, "Content")
        .Location(OrchardCoreConstants.DisplayType.Summary, "Content");
    }

    public override IDisplayResult Edit(TextField field, BuildFieldEditorContext context)
    {
        return Initialize<EditTextFieldViewModel>(GetEditorShapeType(context), model =>
        {
            model.Field = field;
            model.Part = context.ContentPart;
            model.PartFieldDefinition = context.PartFieldDefinition;
        });
    }

    public override async Task<IDisplayResult> UpdateAsync(TextField field, UpdateFieldEditorContext context)
    {
        await context.Updater.TryUpdateModelAsync(field, Prefix, f => f.Text);
        return Edit(field, context);
    }
}

Step 3: Register the driver

In Startup.cs:

services.AddContentPartDisplayDriver<MyPart, MyPartDisplayDriver>();
// or for a field:
services.AddContentFieldDisplayDriver<TextField, TextFieldDisplayDriver>();

See references/drivers.md for shape-type helpers, the fluent .Location API, and registration variants.

Quick Reference

Placement rule keys

KeyPurpose
placeZone:Position. - hides, /Zone targets a layout zone
displayTypeMatch Detail, Summary, SummaryAdmin, DetailAdmin, Edit
differentiatorDistinguish reused shapes (field/part name)
contentTypeMatch content type / stereotype (Art* wildcard, or array)
contentPartMatch content items containing a part
pathMatch request path
alternatesAdd alternate shape types
wrappersWrap the shape in other shapes
shapeSubstitute a different shape type

Position values

before < 0/empty < 1 < 1.1 < 2 < 10 < after. Numeric, not alphabetic. Dot notation inserts between (5.1 is between 5 and 6).

Editor grouping modifiers

ModifierGroupExample
#TabParts:0#Media;1
%CardParts:0%Details;2
|ColumnParts:0|Left_9;1 (_9 = width, ;1 = order)

;N after a group name = group order. _N after a column name = Bootstrap grid width (12-col).

Common zones

ZonePurpose
ContentMain content shapes
Header / FooterLayout regions
ActionsAdmin list row buttons
PartsEditor parts container
MetaMetadata block

Gotchas

  • Hiding a whole editor row → target ContentPart_Edit with differentiator {ContentType}-{PartName}, not the inner XxxPart_Edit.
  • Shape type ≠ part type. No driver → shape is ContentPart. Summary display of a dynamic part → ContentPart_Summary.
  • Field display modes are stricter: shape type needs _Display, differentiator is {Part}-{Field}-{FieldType}_Display__{Mode}.
  • Placement precedence: startup project → active theme → modules (by dependency). A theme can override any module's placement.
  • Same position value → registration order decides; use distinct positions when order matters.

References

  • references/placement.md — placement.json filters, differentiators, layout zones, editor groupings
  • references/drivers.md — driver base classes, shape helpers, fluent Location API, registration
  • src/docs/reference/modules/Placement/README.md (repo) — official placement reference
  • src/docs/reference/modules/DisplayManagement/README.md (repo) — display management reference
  • src/docs/reference/modules/Templates/README.md (repo) — shape differentiators and alternates
  • AGENTS.md (repo root) — build commands
Repository
OrchardCMS/OrchardCore
Last updated
First committed

Is this your skill?

If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.