Orchard CMS:当每个页面的特定内容分布在不同的列中时,我是否必须为每个页面添加一个新图层?

问题描述:

假设我希望每个页面都有一个不同的主图像,位于页面标题上方.另外,我需要在左侧栏中放置特定于页面的图像,在右侧栏中放置特定于页面的文本.在左右栏,我也想要图层特定的内容.

Lets say I want a different main image for each page, situated above the page title. Also, I need to place page specific images in the left bar, and page specific text in the right bar. In the right and left bars, I also want layer specific content.

如果不为站点中的每个页面都创建一个层,我无法看到如何实现这一点,但是我最终得到了大量的层,这些层只为一个看起来过于复杂的页面提供服务.

I can't see how I can achieve this without creating a layer for each and every page in the site, but then I end up with a glut of layers that only serve one page which seems too complex.

我错过了什么?

如果有办法使用内容部分来做到这一点,如果您能指点我的教程、博客、视频来帮助我解决这个问题,那就太好了.

If there is a way of doing this using Content parts, it would be great if you can point me at tutorials, blogs, videos to help get my head round the issue.

注意:

Sitefinity 在这类事情上做得很好,但我发现 Orchard 创建模块要简单得多,而且我发现它是 MVC 更容易.

Sitefinity does this sort of thing well, but I find Orchard much simpler for creating module, as well as the fact that it is MVC which I find much easier.

果园是免费的,我理解(并欣赏)这一点.只是希望随着产品的发展,这种事情会变得更容易?

Orchard is free, I understand (and appreciate) that. Just hoping that as the product evolves this kind of thing will be easier?

换句话说,我希望世界上最好的...

In other words, I'm hoping for the best of all worlds...

1.5 的工作中有一个功能可以使这更容易,但与此同时,您已经可以很容易地使用它,只需要一点点的代码.您应该首先将您需要的字段添加到您的内容类型中.然后,您将使用放置将它们发送到*布局区域.开箱即用,放置仅针对本地内容区域,但这是我们可以通过 Pete Hurst(又名 randompete)编写的一些代码来解决的问题.代码如下:

There is a feature in the works for 1.5 to make that easier, but in the meantime, you can already get this to work quite easily with just a little bit of code. You should first add the fields that you need to your content type. Then, you are going to send them to top-level layout zones using placement. Out of the box, placement only targets local content zones, but this is what we can work around with a bit of code by Pete Hurst, a.k.a. randompete. Here's the code:

ZoneProxyBehavior.cs:
=====================

using System;
using System.Collections.Generic;
using System.Linq;
using ClaySharp;
using ClaySharp.Behaviors;
using Orchard.Environment.Extensions;

namespace Downplay.Origami.ZoneProxy.Shapes {
    [OrchardFeature("Downplay.Origami.ZoneProxy")]
    public class ZoneProxyBehavior : ClayBehavior {

        public IDictionary<string, Func<dynamic>> Proxies { get; set; }

        public ZoneProxyBehavior(IDictionary<string, Func<dynamic>> proxies) {
            Proxies = proxies;
        }

        public override object GetMember(Func<object> proceed, object self, string name) {

            if (name == "Zones") {
                return ClayActivator.CreateInstance(new IClayBehavior[] {                
                    new InterfaceProxyBehavior(),
                    new ZonesProxyBehavior(()=>proceed(), Proxies, self)
                });
            }

            // Otherwise proceed to other behaviours, including the original ZoneHoldingBehavior
            return proceed();
        }

        public class ZonesProxyBehavior : ClayBehavior {
            private readonly Func<dynamic> _zonesActivator;
            private readonly IDictionary<string, Func<dynamic>> _proxies;
            private object _parent;

            public ZonesProxyBehavior(Func<dynamic> zonesActivator, IDictionary<string, Func<dynamic>> proxies, object self) {
                _zonesActivator = zonesActivator;
                _proxies = proxies;
                _parent = self;
            }

            public override object GetIndex(Func<object> proceed, object self, IEnumerable<object> keys) {
                var keyList = keys.ToList();
                var count = keyList.Count();
                if (count == 1) {

                    // Here's the new bit
                    var key = System.Convert.ToString(keyList.Single());

                    // Check for the proxy symbol
                    if (key.Contains("@")) {
                        // Find the proxy!
                        var split = key.Split('@');
                        // Access the proxy shape
                        return _proxies[split[0]]()
                            // Find the right zone on it
                            .Zones[split[1]];
                    }
                    // Otherwise, defer to the ZonesBehavior activator, which we made available
                    // This will always return a ZoneOnDemandBehavior for the local shape
                    return _zonesActivator()[key];
                }
                return proceed();
            }

            public override object GetMember(Func<object> proceed, object self, string name) {
                // This is rarely called (shape.Zones.ZoneName - normally you'd just use shape.ZoneName)
                // But we can handle it easily also by deference to the ZonesBehavior activator
                return _zonesActivator()[name];
            }
        }
    }
}

还有:

ZoneShapes.cs:
==============


using System;
using System.Collections.Generic;
using Orchard.DisplayManagement.Descriptors;
using Orchard;
using Orchard.Environment.Extensions;

namespace Downplay.Origami.ZoneProxy.Shapes {
    [OrchardFeature("Downplay.Origami.ZoneProxy")]
    public class ZoneShapes : IShapeTableProvider {
        private readonly IWorkContextAccessor _workContextAccessor;
        public ZoneShapes(IWorkContextAccessor workContextAccessor) {
            _workContextAccessor = workContextAccessor;
        }

        public void Discover(ShapeTableBuilder builder) {

            builder.Describe("Content")
                .OnCreating(creating => creating.Behaviors.Add(
                    new ZoneProxyBehavior(
                        new Dictionary<string, Func<dynamic>> { { "Layout", () => _workContextAccessor.GetContext().Layout } })));
        }
    }

}

这样,您将能够在要寻址的区域名称前使用 Layout@ 来寻址*布局区域,例如 Layout@BeforeContent:1代码>.

With this, you will be able to address top-level layout zones using Layout@ in front of the zone name you want to address, for example Layout@BeforeContent:1.