diff --git a/src/Orchard.Web/Modules/Orchard.DesignerTools/Module.txt b/src/Orchard.Web/Modules/Orchard.DesignerTools/Module.txt
index 80761c299..9fa065e27 100644
--- a/src/Orchard.Web/Modules/Orchard.DesignerTools/Module.txt
+++ b/src/Orchard.Web/Modules/Orchard.DesignerTools/Module.txt
@@ -2,8 +2,8 @@ Name: Designer Tools
AntiForgery: enabled
Author: The Orchard Team
Website: http://orchardproject.net
-Version: 1.0
-OrchardVersion: 1.0
+Version: 1.0.20
+OrchardVersion: 1.0.20
Description: Contains designer tools to ease the Themes development process
FeatureName: Shape Tracing
Category: Designer
@@ -14,3 +14,8 @@ Features:
Name: Url Alternates
Category: Designer
Description: Adds shape alternates for specific urls
+ WidgetAlternates:
+ Name: Widget Alternates
+ Category: Designer
+ Description: Adds shape alternates for content types stereotyped as widgets, allowing to customize shapes by widget and zone
+ Dependencies: Orchard.Widgets
diff --git a/src/Orchard.Web/Modules/Orchard.DesignerTools/Orchard.DesignerTools.csproj b/src/Orchard.Web/Modules/Orchard.DesignerTools/Orchard.DesignerTools.csproj
index b448d7a46..52f2ac387 100644
--- a/src/Orchard.Web/Modules/Orchard.DesignerTools/Orchard.DesignerTools.csproj
+++ b/src/Orchard.Web/Modules/Orchard.DesignerTools/Orchard.DesignerTools.csproj
@@ -99,6 +99,10 @@
{9916839C-39FC-4CEB-A5AF-89CA7E87119F}
Orchard.Core
+
+ {194D3CCC-1153-474D-8176-FDE8D7D0D0BD}
+ Orchard.Widgets
+
@@ -106,6 +110,7 @@
+
diff --git a/src/Orchard.Web/Modules/Orchard.DesignerTools/Services/WidgetAlternatesFactory.cs b/src/Orchard.Web/Modules/Orchard.DesignerTools/Services/WidgetAlternatesFactory.cs
new file mode 100644
index 000000000..03c8f3afd
--- /dev/null
+++ b/src/Orchard.Web/Modules/Orchard.DesignerTools/Services/WidgetAlternatesFactory.cs
@@ -0,0 +1,34 @@
+using Orchard.DisplayManagement.Implementation;
+using Orchard.Environment.Extensions;
+using Orchard.ContentManagement;
+using Orchard.Widgets.Models;
+
+namespace Orchard.DesignerTools.Services {
+ [OrchardFeature("WidgetAlternates")]
+ 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") {
+ ContentItem contentItem = displayedContext.Shape.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();
+ 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")
+ // [ContentTypeName]-[ZoneName].cshtml: (e.g. "RecentBlogPosts-myZoneName.cshtml")
+ displayedContext.ShapeMetadata.Alternates.Add(contentTypeName + "__" + zoneName);
+ displayedContext.ShapeMetadata.Alternates.Add(shapeName + "__" + zoneName);
+ }
+ }
+ }
+ });
+
+ }
+ }
+}
\ No newline at end of file