This project is read-only.

Alternate by Zone

Nov 22, 2011 at 8:43 PM

I'm already overriding the view for "Parts.BetterMenu" and "Parts.BetterMenuItem" in my Theme. I'd really like to also have something like "Parts.BetterMenu-[Zone]" and I figured this would be simple with the WidgetAlternates feature released by in Orchard 1.3. I ran into some issues though. I do not find any zone alternates for the BetterMenu part. 

Orchard.DesignerTools.WidgetAlternatesFactory.cs has the following code (this is actually from the latest changeset on the 1.x branch as it was patched by Sebastien recently):

using Orchard.DisplayManagement.Implementation;
using Orchard.Environment.Extensions;
using Orchard.ContentManagement;
using Orchard.Widgets.Models;

namespace Orchard.DesignerTools.Services {
    public class WidgetAlternatesFactory : ShapeDisplayEvents {
        public override void Displaying(ShapeDisplayingContext context) {
            context.ShapeMetadata.OnDisplaying(displayedContext => {
                // We don't want the "Widget" content item itself, but the content item that consists of the Widget part (e.g. Parts.Blogs.RecentBlogPosts)
                if (displayedContext.ShapeMetadata.Type != "Widget") {
                    // look for ContentItem property
                    ContentItem contentItem = displayedContext.Shape.ContentItem; <-- this is null for "Parts_BetterMenu" and "Parts_BetterMenuItem"

                    // if not, check for ContentPart 
                    if (contentItem == null) {
                        ContentPart contentPart = displayedContext.Shape.ContentPart; <-- this is also null ...
                        if (contentPart != null) {
                            contentItem = contentPart.ContentItem;
                    if (contentItem != null) {
                        // Is the contentItem a widget? (we could probably test for the stereotype setting, don't know if that is more efficient than selecting the WidgetPart)
                        var widgetPart = contentItem.As<WidgetPart>();
                        if (widgetPart != null) {
                            var zoneName = widgetPart.Zone;
                            var shapeName = displayedContext.ShapeMetadata.Type;
                            var contentTypeName = contentItem.ContentType;

                            // Add 2 alternates for flexible widget shape naming:
                            // [ShapeName]-[ZoneName].cshtml: (e.g. "Parts.Blogs.RecentBlogPosts-myZoneName.cshtml")
                            // [ShapeName]-[ContentTypeName]-[ZoneName].cshtml: (e.g. "Parts.Common.Body-RecentBlogPosts-myZoneName.cshtml")
                            displayedContext.ShapeMetadata.Alternates.Add(shapeName + "__" + contentTypeName + "__" + zoneName);
                            displayedContext.ShapeMetadata.Alternates.Add(shapeName + "__" + zoneName);


When the displayContext.Shape.ShapeMetadata.Type == "Parts_BetterMenu" our shape has a null ContentItem property. The ContentPart property is also null. In effect, this entire block gets skipped and the alternate "Parts.BetterMenu-[Zone].cshtml" is not created. 

I noticed the structure of the BetterMenu Widget is nested a bit lower than some widgets. We have something like:

  • Zone [ZoneName]
    • Parts_Contents_Publish [empty]
    • Content <------------------------------------ typically widget parts fall here
      • Parts_Contents_Publish [empty]
      • Parts_BetterMenu
        • Parts_BetterMenuItem
        • Parts_BetterMenuItem
        • Parts_BetterMenuItem (... and so on)

I think that this may have something to do with how RelatedContent is used to form a relationship between the BetterMenu and the core Navigational structure within Orchard.

Any ideas on how we could make sure the BetterMenu part gets picked up by the WidgetAlternates feature or otherwise some work around to get a Parts.BetterMenu-[Zone].cshtml.

My ultimate goal here is to alternate the BetterMenu for a local aside navigation. Before displaying the menu in the aside zone, I want to trim down the model to only contain menu items that are immediate children of the selected parent item.



Nov 27, 2011 at 6:44 PM
Edited Nov 27, 2011 at 6:44 PM

Hi Matthew, I will try to look into this at some point.  I have done some tricky stuff with the shape rendering.  I created a work item here that you can follow.