diff --git a/src/OrchardCore.Modules/OrchardCore.Alias/Services/AliasShapeTableProvider.cs b/src/OrchardCore.Modules/OrchardCore.Alias/Services/ContentAliasShapeTableProvider.cs similarity index 94% rename from src/OrchardCore.Modules/OrchardCore.Alias/Services/AliasShapeTableProvider.cs rename to src/OrchardCore.Modules/OrchardCore.Alias/Services/ContentAliasShapeTableProvider.cs index 718d38b954a..cc883a8a9d2 100644 --- a/src/OrchardCore.Modules/OrchardCore.Alias/Services/AliasShapeTableProvider.cs +++ b/src/OrchardCore.Modules/OrchardCore.Alias/Services/ContentAliasShapeTableProvider.cs @@ -6,7 +6,7 @@ namespace OrchardCore.Alias.Services; -public class AliasShapeTableProvider : ShapeTableProvider +public sealed class ContentAliasShapeTableProvider : ShapeTableProvider { public override ValueTask DiscoverAsync(ShapeTableBuilder builder) { diff --git a/src/OrchardCore.Modules/OrchardCore.Alias/Services/WidgetAliasShapeTableProvider.cs b/src/OrchardCore.Modules/OrchardCore.Alias/Services/WidgetAliasShapeTableProvider.cs new file mode 100644 index 00000000000..85d8a984550 --- /dev/null +++ b/src/OrchardCore.Modules/OrchardCore.Alias/Services/WidgetAliasShapeTableProvider.cs @@ -0,0 +1,35 @@ +using OrchardCore.Alias.Models; +using OrchardCore.ContentManagement; +using OrchardCore.DisplayManagement; +using OrchardCore.DisplayManagement.Descriptors; +using OrchardCore.DisplayManagement.Utilities; + +namespace OrchardCore.Alias.Services; + +public sealed class WidgetAliasShapeTableProvider : ShapeTableProvider +{ + public override ValueTask DiscoverAsync(ShapeTableBuilder builder) + { + builder.Describe("Widget") + .OnDisplaying(displaying => + { + var shape = displaying.Shape; + var contentItem = shape.GetProperty("ContentItem"); + + var aliasPart = contentItem?.As(); + + if (aliasPart != null) + { + var encodedAlias = aliasPart.Alias.EncodeAlternateElement(); + + // Widget__Alias__[Alias] e.g. Widget-Alias-example, Widget-Alias-my-page + displaying.Shape.Metadata.Alternates.Add("Widget__Alias__" + encodedAlias); + + // Widget_[DisplayType]__Alias__[Alias] e.g. Widget-Alias-example.Summary, Widget-Alias-my-page.Summary + displaying.Shape.Metadata.Alternates.Add("Widget_" + displaying.Shape.Metadata.DisplayType + "__Alias__" + encodedAlias); + } + }); + + return ValueTask.CompletedTask; + } +} diff --git a/src/OrchardCore.Modules/OrchardCore.Alias/Startup.cs b/src/OrchardCore.Modules/OrchardCore.Alias/Startup.cs index 45ddc742c99..c08f6df7e85 100644 --- a/src/OrchardCore.Modules/OrchardCore.Alias/Startup.cs +++ b/src/OrchardCore.Modules/OrchardCore.Alias/Startup.cs @@ -15,6 +15,7 @@ using OrchardCore.ContentTypes.Editors; using OrchardCore.Data; using OrchardCore.Data.Migration; +using OrchardCore.DisplayManagement; using OrchardCore.DisplayManagement.Descriptors; using OrchardCore.Indexing; using OrchardCore.Liquid; @@ -71,7 +72,23 @@ public override void ConfigureServices(IServiceCollection services) services.AddScoped(); services.AddScoped(); + } +} - services.AddScoped(); +[RequireFeatures("OrchardCore.Contents")] +public sealed class ContentAliasStartup : StartupBase +{ + public override void ConfigureServices(IServiceCollection services) + { + services.AddShapeTableProvider(); + } +} + +[RequireFeatures("OrchardCore.Widgets")] +public sealed class WidgetAliasStartup : StartupBase +{ + public override void ConfigureServices(IServiceCollection services) + { + services.AddShapeTableProvider(); } } diff --git a/src/OrchardCore.Modules/OrchardCore.Autoroute/Services/AutorouteShapeTableProvider.cs b/src/OrchardCore.Modules/OrchardCore.Autoroute/Services/ContentAutorouteShapeTableProvider.cs similarity index 94% rename from src/OrchardCore.Modules/OrchardCore.Autoroute/Services/AutorouteShapeTableProvider.cs rename to src/OrchardCore.Modules/OrchardCore.Autoroute/Services/ContentAutorouteShapeTableProvider.cs index aec9625e803..6b1c1576843 100644 --- a/src/OrchardCore.Modules/OrchardCore.Autoroute/Services/AutorouteShapeTableProvider.cs +++ b/src/OrchardCore.Modules/OrchardCore.Autoroute/Services/ContentAutorouteShapeTableProvider.cs @@ -6,7 +6,7 @@ namespace OrchardCore.Autoroute.Services; -public class AutorouteShapeTableProvider : ShapeTableProvider +public sealed class ContentAutorouteShapeTableProvider : ShapeTableProvider { public override ValueTask DiscoverAsync(ShapeTableBuilder builder) { diff --git a/src/OrchardCore.Modules/OrchardCore.Autoroute/Services/WidgetAutorouteShapeTableProvider.cs b/src/OrchardCore.Modules/OrchardCore.Autoroute/Services/WidgetAutorouteShapeTableProvider.cs new file mode 100644 index 00000000000..be4247f0fcb --- /dev/null +++ b/src/OrchardCore.Modules/OrchardCore.Autoroute/Services/WidgetAutorouteShapeTableProvider.cs @@ -0,0 +1,35 @@ +using OrchardCore.Autoroute.Models; +using OrchardCore.ContentManagement; +using OrchardCore.DisplayManagement; +using OrchardCore.DisplayManagement.Descriptors; +using OrchardCore.DisplayManagement.Utilities; + +namespace OrchardCore.Autoroute.Services; + +public sealed class WidgetAutorouteShapeTableProvider : ShapeTableProvider +{ + public override ValueTask DiscoverAsync(ShapeTableBuilder builder) + { + builder.Describe("Widget") + .OnDisplaying(displaying => + { + var shape = displaying.Shape; + var contentItem = shape.GetProperty("ContentItem"); + + var autoroutePart = contentItem?.As(); + + if (autoroutePart != null) + { + var encodedSlug = autoroutePart.Path.EncodeAlternateElement().Replace("/", "__"); + + // Widget__Slug__[Slug] e.g. Widget-Slug-example, Widget-Slug-blog-my-post + displaying.Shape.Metadata.Alternates.Add("Widget__Slug__" + encodedSlug); + + // Widget_[DisplayType]__Slug__[Slug] e.g. Widget-Slug-example.Summary, Widget-Slug-blog-my-post.Summary + displaying.Shape.Metadata.Alternates.Add("Widget_" + displaying.Shape.Metadata.DisplayType + "__Slug__" + encodedSlug); + } + }); + + return ValueTask.CompletedTask; + } +} diff --git a/src/OrchardCore.Modules/OrchardCore.Autoroute/Startup.cs b/src/OrchardCore.Modules/OrchardCore.Autoroute/Startup.cs index 129f5044de8..c500a1ca040 100644 --- a/src/OrchardCore.Modules/OrchardCore.Autoroute/Startup.cs +++ b/src/OrchardCore.Modules/OrchardCore.Autoroute/Startup.cs @@ -22,6 +22,7 @@ using OrchardCore.ContentTypes.Editors; using OrchardCore.Data; using OrchardCore.Data.Migration; +using OrchardCore.DisplayManagement; using OrchardCore.DisplayManagement.Descriptors; using OrchardCore.Indexing; using OrchardCore.Liquid; @@ -54,7 +55,7 @@ public override void ConfigureServices(IServiceCollection services) if (!slug.StartsWith('/')) { - slug = "/" + slug; + slug = '/' + slug; } (var found, var entry) = await autorouteEntries.TryGetEntryByPathAsync(slug); @@ -98,8 +99,6 @@ public override void ConfigureServices(IServiceCollection services) services.AddSingleton(); services.AddSingleton(); - - services.AddScoped(); } public override void Configure(IApplicationBuilder app, IEndpointRouteBuilder routes, IServiceProvider serviceProvider) @@ -117,3 +116,21 @@ public override void ConfigureServices(IServiceCollection services) services.AddScoped(); } } + +[RequireFeatures("OrchardCore.Contents")] +public sealed class ContentAutourouteStartup : StartupBase +{ + public override void ConfigureServices(IServiceCollection services) + { + services.AddShapeTableProvider(); + } +} + +[RequireFeatures("OrchardCore.Widgets")] +public sealed class WidgetAutourouteStartup : StartupBase +{ + public override void ConfigureServices(IServiceCollection services) + { + services.AddShapeTableProvider(); + } +} diff --git a/src/docs/reference/modules/Templates/README.md b/src/docs/reference/modules/Templates/README.md index 8ab53b1204d..f980475e35f 100644 --- a/src/docs/reference/modules/Templates/README.md +++ b/src/docs/reference/modules/Templates/README.md @@ -109,6 +109,42 @@ This template is called when a widget is rendered on a page. | `Model.ContentItem.Content` | A JSON object containing all the data of the content item. | | `Model.Classes` | An array of all the classes attached to the widget. | +### `Widget__Alias__[Alias]` + +This template is called when displaying a widget content item with a specific alias. It needs to have the `AliasPart` attached to it. + +#### Widget with Alias Examples + +| Template | Filename | +|----------------------------|--------------------------------| +| `Widget__Alias__example` | `Widget-Alias-example.cshtml` | +| `Widget__Alias__my__page` | `Widget-Alias-my-page.cshtml` | + +#### Widget with Alias and Display Type Examples + +| Template | Filename | +|------------------------------------|----------------------------------------| +| `Widget_Summary__Alias__example` | `Widget-Alias-example.Summary.cshtml` | +| `Widget_Summary__Alias__my__page` | `Widget-Alias-my-page.Summary.cshtml` | + +### `Widget__Slug__[Slug]` + +This template is called when displaying a widget content item with a specific slug (i.e., a path is assigned to the item). It needs to have the `AutoroutePart` attached to it. + +#### Widget with Slug Examples + +| Template | Filename | +|---------------------------------|------------------------------------| +| `Widget__Slug__example` | `Widget-Slug-example.cshtml` | +| `Widget__Slug__blog__my__post` | `Widget-Slug-blog-my-post.cshtml` | + +#### Widget with Slug and Display Type Examples + +| Template | Filename | +|-----------------------------------|----------------------------------------| +| `Widget_Summary__Slug__example` | `Widget-Slug-example.Summary.cshtml` | +| `Widget_Summary__Slug__blog__my__post` | `Widget-Slug-blog-my-post.Summary.cshtml` | + ## Content Part templates Each driver is free to return a shape type of its choosing, but the usage is diff --git a/src/docs/releases/2.1.0.md b/src/docs/releases/2.1.0.md index b02da7e6467..d852ea1f802 100644 --- a/src/docs/releases/2.1.0.md +++ b/src/docs/releases/2.1.0.md @@ -145,9 +145,9 @@ Additionally, the configuration provider key for the default provider has change ### Autoroute Feature -#### Content Item Shape Alternates Based on Alias and Slug +#### Content Item Shape Alternates Based on Alias and Slug (Content and Widget shapes) -Content item shapes can be overridden by their alias if `AliasPart` is attached or by their slug if `AutoroutePart` is attached. For examples, refer to the [docs](../reference/modules/Templates/README.md). +Content item shapes (Content and Widget local zones) can be overridden by their alias if `AliasPart` is attached or by their slug if `AutoroutePart` is attached. For examples, refer to the [docs](../reference/modules/Templates/README.md). ### Recipes Feature