Get the FREE Ultimate OpenClaw Setup Guide →

orchardcore-display-management

Scanned
npx machina-cli add skill CrestApps/CrestApps.AgentSkills/orchardcore-display-management --openclaw
Files (1)
SKILL.md
6.0 KB

Orchard Core Display Management - Prompt Templates

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, and Update.
  • 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}_Edit for editor.
  • Use Initialize<TModel> to create shapes with a view model.
  • Register drivers in Startup.cs using services.AddContentPart<TPart>().UseDisplayDriver<TDriver>().
  • 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="mb-3">
    <label asp-for="{{PropertyName}}" class="form-label">{{DisplayLabel}}</label>
    <input asp-for="{{PropertyName}}" class="form-control" />
    <span asp-validation-for="{{PropertyName}}" class="text-danger"></span>
</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.

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;
    }
}

Source

git clone https://github.com/CrestApps/CrestApps.AgentSkills/blob/main/src/CrestApps.AgentSkills/orchardcore/orchardcore-display-management/SKILL.mdView on GitHub

Overview

This skill teaches how to implement Orchard Core's display management system, covering display drivers, display managers, shapes, display types, shape table providers, placement, and editor/display mode patterns. It explains how to create a custom DisplayDriver<TPart>, bind data to view models, name shapes, and register drivers so parts render in chosen zones and modes.

How This Skill Works

A DisplayDriver overrides Display, Edit, and Update to return shapes via IDisplayResult. Shapes are created with Initialize<TModel> to bind a view model and are placed using Location calls (e.g., Detail, Summary). Names follow the convention {PartName} for display and {PartName}_Edit for editor. Classes should be sealed, and drivers are registered in Startup.cs with services.AddContentPart<TPart>().UseDisplayDriver<TDriver>().

When to Use It

  • When a content part requires bespoke visuals beyond default rendering
  • When you need to render a part in multiple display zones (Detail, Summary) with different layouts
  • When editing a part you want a tailored editor UI via a dedicated ViewModel
  • When you want to bind user input from the editor back to the part (UpdateAsync)
  • When wiring up and registering the display driver in Startup for a new Part

Quick Start

  1. Step 1: Create a sealed DisplayDriver class that inherits ContentPartDisplayDriver<YourPart> and implement Display, Edit, and Update methods
  2. Step 2: In Display, return Initialize<YourViewModel>("YourPart", model => { ... }).Location("Detail", "Content:5").Location("Summary", "Content:5"); and in Edit return Initialize<YourViewModel>("YourPart_Edit", ...)
  3. Step 3: Register the driver in Startup.cs with services.AddContentPart<YourPart>().UseDisplayDriver<YourPartDisplayDriver>();

Best Practices

  • Seal all DisplayDriver classes to prevent unintended inheritance
  • Implement Display, Edit, and Update and return IDisplayResult for each
  • Use Initialize<TModel> to create shapes and bind a ViewModel
  • Follow shape naming conventions: {PartName} for Display and {PartName}_Edit for Editor
  • Register the driver in Startup.cs with services.AddContentPart<TPart>().UseDisplayDriver<TDriver>()

Example Use Cases

  • BlogPostPart: Display shows Title and Summary in Detail and Summary views; Editor uses BlogPostPart_Edit shape for editing
  • ProductPart: Display renders Price and Availability; Editor allows updating Price via a dedicated view model
  • EventPart: Display includes EventDate and Location; Editor provides a tailored form for editing event details
  • NewsletterSubscriberPart: Display shows Email; Editor enables editing the subscriber email in a structured editor shape
  • AuthorProfilePart: Display combines Avatar and DisplayName in the profile view, with an editor for updating profile fields

Frequently Asked Questions

Add this skill to your agents
Sponsor this space

Reach thousands of developers