Customizing Widget Headers

Topics: Customizing Orchard
May 18, 2011 at 1:22 PM

I'm trying to get a better understanding of the widget rendering system. One of the things I haven't quite figured out is how the Widget.Wrapper template gets called and how the model for it is built. It's fairly short, so I'll just paste it here:

@using Orchard.ContentManagement;
@using Orchard.Widgets.Models;
@{
    var title = ((IContent)Model.ContentItem).As<WidgetPart>().Title;
    var tag = Tag(Model, "article");
}
@tag.StartElement
    @if (HasText(title) || Model.Header != null) {
    <header>
        @if (HasText(title)) {
        <h1>@title</h1>
        }
        @Display(Model.Header)
    </header>
    }
    @Display(Model.Child)
    @if(Model.Footer != null) {
    <footer>
        @Display(Model.Footer)
    </footer>
    }
@tag.EndElement

So, the title comes from the Title property defined on the WidgetPart. I get that. It appears then that the actual content of a widget instance (for example, an HtmlWidget) gets put into Model.Child, so it renders there in the middle between the <header> and <footer> sections. Is that right? If so, my next question concerns those header and footer sections. How would I get something into the Model.Header or Model.Footer so that they would render. I have a situation where I actually would like to render something exactly where the @Display(Model.Header) is being called in this template, but not sure how to get it there. Thanks.

Coordinator
May 18, 2011 at 7:16 PM

Placement.info should do the trick I think.

May 18, 2011 at 9:27 PM

I guess I'm not familiar with using Placement.info in this way. Can you provide an example? Let's say you add an HTML widget to the Default layer, and the AsideSecond zone. You give it a Title of "Contact Us", so that renders between the <h1> tags in the Widget.Wrapper template. How do you place some other content where it's Displaying Model.Header?

Coordinator
Jun 1, 2011 at 12:44 AM

Sorry I didn't get back to you earlier. Here is a placement that would move the body of the HtmlWidget to the Header:

<Placement>
  <Match ContentType="HtmlWidget">
    <Place Parts_Common_Body="Header:1"/>
  </Match>
</Placement>

In other words, it works for widgets the same way it works for other content types. Placement just moves shapes around local zones.

Jun 1, 2011 at 1:41 PM

No problem, thanks for the reply. We ended up defining our own widget type so that we could completely control the rendering. Also, if I remember right, we decided that we were going to want to use it in more than one place, so it was more convenient to have a specific widget defined anyway. This brings up a good point about HTML widgets though ... it would be nice to be able to name & save them so that they can be reused in different layers/zones without having to copy/paste. I can file that as a feature suggestion if you don't already have one for that issue.

However, even though we solved our problem another way this is still interesting to me. What we were trying to do at the time was not move the body shape into the header, we were trying to place some additional content in the header while leaving the body where it was. The way that Widget.Wrapper template is built it appears that it's possible for the model to have a Header and Footer in addition to the Title and Child content, but I wasn't seeing any easy way to add anything there for the HtmlWidget (now that I think about it some more, maybe it's not really intended for the HtmlWidget).

Jun 1, 2011 at 3:15 PM

kevink: this sounds pretty much like one of the general scenarios I'm trying to solve with the Mechanics module. It has a feature called Paperclips that allows you to push content into zones, based on their attachment to the currently viewed content. You can build all the connectors up out of your own content types. So for instance you could create your own "Block" content type that just had BodyPart. Then create a "HeaderContent" connector type, and give that connector the PaperclipPart and specify "Header:5" for the Layout placement. So then you can create as many Blocks as you want, and attach them to any pages that you like - the block will appear in the header on those pages. Connectors are actually content items in their own right (with ConnectorPart) so you can build any number of types of connections you like, with whatever parts and properties you need. Mechanics is basically a set of components that let you build arbitrary many-to-many relationships, and then do useful layout and UI tasks based on those connectors. There are many other interesting uses :)