Wrapping up content item zones in custom markup

When it comes to rendering a given content item, Orchard splits it in a couple of zones, like Header, Content and Footer. The markup produced by each of the parts contained in an item is then dispatched to one of those zones. That is what Placement.info files are mainly used for – they tell the rendering engine in which zone to put a given shape’s final markup.

But what to do if you’d like to have the whole zone (eg. a Header) wrapped up in some custom markup? And what’s more – you’d like it to do in unobtrusive way, so no matter how the whole item is rendered (whether there are some shape alternates or not) – you want a given zone to be always displayed as you want it to be.

I’ve recently came up with a nice technique for doing that. First of all – zones inside a given content item are nothing more than… ordinary shapes! So you are free to attach a wrapper to them, like:

public class Shapes : IShapeTableProvider
{
    public void Discover(ShapeTableBuilder builder)
    {
        builder.Describe("Content")
            .OnDisplaying(displaying =>
            {
                // displaying.Shape.Header is the header zone shape!
                var theHeader = displaying.Shape.Header;
                // assign a custom wrapper directly to the header
                theHeader.Metadata.Wrappers.Add("MyHeaderWrapper");
            });
    }
}

The only thing left is to create the MyHeaderWrapper.cshtml:

<div class="my-custom-header">
    @DisplayChildren(Model)
</div>

Note the call to DisplayChildren. We remember that the wrapper wraps the whole zone (so Model contains the zone shape), right? And zones are containers for other shapes, so we have to display the contained children – that’s what DisplayChildren is intended for (using Display would run you into the StackOverflowException! Orchard would then try to render your wrapper, and your wrapper, and your wrapper and so on).

That’s all!

Now, when you try to open eg. a page, by default you’ll see the markup like this:

<article class="content-item page">
    <header>
        <div class="my-custom-header">
            Here comes the whole current header
        </div>
    </header>
    <p>Page content</p>
</article>

You’re free to apply this technique to any available zone (like Header, Content, Footer etc.) and to any available content item stereotype (like Content, Widget and so on) For the purpose of this article I just used Content stereotype and it’s Header zone.

blog comments powered by Disqus