diff --git a/Packages.props b/Packages.props
index 087ac209..540b179e 100644
--- a/Packages.props
+++ b/Packages.props
@@ -38,5 +38,6 @@
+
diff --git a/src/Feature/Sitemap/Sitemap.module.json b/src/Feature/Sitemap/Sitemap.module.json
new file mode 100644
index 00000000..0c776196
--- /dev/null
+++ b/src/Feature/Sitemap/Sitemap.module.json
@@ -0,0 +1,13 @@
+{
+ "namespace": "Feature.Sitemap",
+ "items": {
+ "includes": [
+ {
+ "name": "templates",
+ "path": "/sitecore/templates/Feature/Sitemap",
+ "allowedPushOperations": "createUpdateAndDelete",
+ "scope": "itemAndDescendants"
+ }
+ ]
+ }
+}
\ No newline at end of file
diff --git a/src/Feature/Sitemap/items/templates/Sitemap.yml b/src/Feature/Sitemap/items/templates/Sitemap.yml
new file mode 100644
index 00000000..b7f8e682
--- /dev/null
+++ b/src/Feature/Sitemap/items/templates/Sitemap.yml
@@ -0,0 +1,31 @@
+---
+ID: "51273b02-674d-4a04-947f-d249f2871bcd"
+Parent: "8f343079-3cc5-4ef7-bc27-32addb46f45e"
+Template: "0437fee2-44c9-46a6-abe9-28858d9fee8c"
+Path: /sitecore/templates/Feature/Sitemap
+Languages:
+- Language: en
+ Versions:
+ - Version: 1
+ Fields:
+ - ID: "25bed78c-4957-4165-998a-ca1b52f67497"
+ Hint: __Created
+ Value: 20231212T005121Z
+ - ID: "52807595-0f8f-4b20-8d2a-cb71d28c6103"
+ Hint: __Owner
+ Value: |
+ sitecore\qDWz4GMo2o
+ - ID: "5dd74568-4d4b-44c1-b513-0af5f4cda34f"
+ Hint: __Created by
+ Value: |
+ sitecore\qDWz4GMo2o
+ - ID: "8cdc337e-a112-42fb-bbb4-4143751e123f"
+ Hint: __Revision
+ Value: "61b184a4-32b9-46ae-a09a-b765d21b4b7a"
+ - ID: "badd9cf9-53e0-4d0c-bcc0-2d784c282f6a"
+ Hint: __Updated by
+ Value: |
+ sitecore\qDWz4GMo2o
+ - ID: "d9cf14b1-fa16-4ba6-9288-e8a174d4d522"
+ Hint: __Updated
+ Value: 20231212T005449Z
diff --git a/src/Feature/Sitemap/items/templates/Sitemap/_SitemapData.yml b/src/Feature/Sitemap/items/templates/Sitemap/_SitemapData.yml
new file mode 100644
index 00000000..87d14d10
--- /dev/null
+++ b/src/Feature/Sitemap/items/templates/Sitemap/_SitemapData.yml
@@ -0,0 +1,37 @@
+---
+ID: "00f7955a-eb3d-4659-94f9-9202865e39de"
+Parent: "51273b02-674d-4a04-947f-d249f2871bcd"
+Template: "ab86861a-6030-46c5-b394-e8f99e8b87db"
+Path: /sitecore/templates/Feature/Sitemap/_SitemapData
+SharedFields:
+- ID: "12c33f3f-86c5-43a5-aeb4-5598cec45116"
+ Hint: __Base template
+ Value: |
+ {1930BBEB-7805-471A-A3BE-4858AC7CF696}
+ {4414A1F9-826A-4647-8DF4-ED6A95E64C43}
+Languages:
+- Language: en
+ Versions:
+ - Version: 1
+ Fields:
+ - ID: "25bed78c-4957-4165-998a-ca1b52f67497"
+ Hint: __Created
+ Value: 20231212T000336Z
+ - ID: "52807595-0f8f-4b20-8d2a-cb71d28c6103"
+ Hint: __Owner
+ Value: |
+ sitecore\qDWz4GMo2o
+ - ID: "5dd74568-4d4b-44c1-b513-0af5f4cda34f"
+ Hint: __Created by
+ Value: |
+ sitecore\qDWz4GMo2o
+ - ID: "8cdc337e-a112-42fb-bbb4-4143751e123f"
+ Hint: __Revision
+ Value: "d85a32fd-cf94-4e5f-92f1-440bb8062c4b"
+ - ID: "badd9cf9-53e0-4d0c-bcc0-2d784c282f6a"
+ Hint: __Updated by
+ Value: |
+ sitecore\qDWz4GMo2o
+ - ID: "d9cf14b1-fa16-4ba6-9288-e8a174d4d522"
+ Hint: __Updated
+ Value: 20231212T005128Z
diff --git a/src/Feature/Sitemap/items/templates/Sitemap/_SitemapData/Sitemap Settings.yml b/src/Feature/Sitemap/items/templates/Sitemap/_SitemapData/Sitemap Settings.yml
new file mode 100644
index 00000000..595722fb
--- /dev/null
+++ b/src/Feature/Sitemap/items/templates/Sitemap/_SitemapData/Sitemap Settings.yml
@@ -0,0 +1,31 @@
+---
+ID: "f1cda39f-65de-4cde-a59b-bcd97968f090"
+Parent: "00f7955a-eb3d-4659-94f9-9202865e39de"
+Template: "e269fbb5-3750-427a-9149-7aa950b49301"
+Path: /sitecore/templates/Feature/Sitemap/_SitemapData/Sitemap Settings
+Languages:
+- Language: en
+ Versions:
+ - Version: 1
+ Fields:
+ - ID: "25bed78c-4957-4165-998a-ca1b52f67497"
+ Hint: __Created
+ Value: 20231212T000540Z
+ - ID: "52807595-0f8f-4b20-8d2a-cb71d28c6103"
+ Hint: __Owner
+ Value: |
+ sitecore\qDWz4GMo2o
+ - ID: "5dd74568-4d4b-44c1-b513-0af5f4cda34f"
+ Hint: __Created by
+ Value: |
+ sitecore\qDWz4GMo2o
+ - ID: "8cdc337e-a112-42fb-bbb4-4143751e123f"
+ Hint: __Revision
+ Value: "ae77877a-f036-42ac-ae2a-09cb0f49f373"
+ - ID: "badd9cf9-53e0-4d0c-bcc0-2d784c282f6a"
+ Hint: __Updated by
+ Value: |
+ sitecore\qDWz4GMo2o
+ - ID: "d9cf14b1-fa16-4ba6-9288-e8a174d4d522"
+ Hint: __Updated
+ Value: 20231212T000718Z
diff --git a/src/Feature/Sitemap/items/templates/Sitemap/_SitemapData/Sitemap Settings/IncludeinSitemap.yml b/src/Feature/Sitemap/items/templates/Sitemap/_SitemapData/Sitemap Settings/IncludeinSitemap.yml
new file mode 100644
index 00000000..242bff92
--- /dev/null
+++ b/src/Feature/Sitemap/items/templates/Sitemap/_SitemapData/Sitemap Settings/IncludeinSitemap.yml
@@ -0,0 +1,48 @@
+---
+ID: "e319ae64-c32a-4e79-b102-256f8c869dae"
+Parent: "f1cda39f-65de-4cde-a59b-bcd97968f090"
+Template: "455a3e98-a627-4b40-8035-e683a0331ac7"
+Path: /sitecore/templates/Feature/Sitemap/_SitemapData/Sitemap Settings/IncludeinSitemap
+SharedFields:
+- ID: "ab162cc0-dc80-4abf-8871-998ee5d7ba32"
+ Hint: Type
+ Value: Checkbox
+- ID: "ba3f86a2-4a1c-4d78-b63d-91c2779c1b5e"
+ Hint: __Sortorder
+ Value: 100
+- ID: "be351a73-fcb0-4213-93fa-c302d8ab4f51"
+ Hint: Shared
+ Value: 1
+Languages:
+- Language: en
+ Fields:
+ - ID: "19a69332-a23e-4e70-8d16-b2640cb24cc8"
+ Hint: Title
+ Value: Include in Sitemap
+ - ID: "b5e02ad9-d56f-4c41-a065-a133db87bdeb"
+ Hint: __Display name
+ Value: Include in Sitemap
+ Versions:
+ - Version: 1
+ Fields:
+ - ID: "25bed78c-4957-4165-998a-ca1b52f67497"
+ Hint: __Created
+ Value: 20231212T000541Z
+ - ID: "52807595-0f8f-4b20-8d2a-cb71d28c6103"
+ Hint: __Owner
+ Value: |
+ sitecore\qDWz4GMo2o
+ - ID: "5dd74568-4d4b-44c1-b513-0af5f4cda34f"
+ Hint: __Created by
+ Value: |
+ sitecore\qDWz4GMo2o
+ - ID: "8cdc337e-a112-42fb-bbb4-4143751e123f"
+ Hint: __Revision
+ Value: "b83eade9-b538-40ac-943f-5e5bbdc0051a"
+ - ID: "badd9cf9-53e0-4d0c-bcc0-2d784c282f6a"
+ Hint: __Updated by
+ Value: |
+ sitecore\qDWz4GMo2o
+ - ID: "d9cf14b1-fa16-4ba6-9288-e8a174d4d522"
+ Hint: __Updated
+ Value: 20231212T001324Z
diff --git a/src/Foundation/Configuration/rendering/AppSettings/MvpSiteSettings.cs b/src/Foundation/Configuration/rendering/AppSettings/MvpSiteSettings.cs
index 6913a395..20c6592c 100644
--- a/src/Foundation/Configuration/rendering/AppSettings/MvpSiteSettings.cs
+++ b/src/Foundation/Configuration/rendering/AppSettings/MvpSiteSettings.cs
@@ -10,8 +10,14 @@ public class MvpSiteSettings
public string? DefaultSiteName { get; set; }
+ public string? RootItemId { get; set; }
+
public string? NotFoundPage { get; set; }
+ public string? DefaultAcceptLanguageHeader { get; set; }
+
+ public string? DefaultLanguage { get; set; }
+
public Uri? RenderingHostUri { get; set; }
public bool EnableExperienceEditor { get; set; }
diff --git a/src/Foundation/DataFetching/rendering/GraphQL/GraphQLRequestBuilder.cs b/src/Foundation/DataFetching/rendering/GraphQL/GraphQLRequestBuilder.cs
index ed6232ff..16dccee9 100644
--- a/src/Foundation/DataFetching/rendering/GraphQL/GraphQLRequestBuilder.cs
+++ b/src/Foundation/DataFetching/rendering/GraphQL/GraphQLRequestBuilder.cs
@@ -1,6 +1,5 @@
using Microsoft.Extensions.Configuration;
using Mvp.Foundation.Configuration.Rendering.AppSettings;
-using Mvp.Foundation.DataFetching.GraphQL;
using System.Collections.Generic;
namespace Mvp.Foundation.DataFetching.GraphQL
diff --git a/src/Project/MvpSite/items/content/MvpSite/Home.yml b/src/Project/MvpSite/items/content/MvpSite/Home.yml
index d19a285b..cfa31483 100644
--- a/src/Project/MvpSite/items/content/MvpSite/Home.yml
+++ b/src/Project/MvpSite/items/content/MvpSite/Home.yml
@@ -7,6 +7,9 @@ SharedFields:
- ID: "ba3f86a2-4a1c-4d78-b63d-91c2779c1b5e"
Hint: __Sortorder
Value: 100
+- ID: "e319ae64-c32a-4e79-b102-256f8c869dae"
+ Hint: IncludeinSitemap
+ Value: 1
- ID: "f1a1fe9e-a60c-4ddb-a3a0-bb5b29fe732e"
Hint: __Renderings
Value: |
@@ -143,7 +146,7 @@ Languages:
Value: MVP, Most Valuable Professional
- ID: "8cdc337e-a112-42fb-bbb4-4143751e123f"
Hint: __Revision
- Value: "198fd8d5-7f00-4749-9c29-b7e4bd29ff1f"
+ Value: "7bfb35cf-92df-47a0-b476-3021107d291e"
- ID: "986ff3ab-18cd-47d7-b294-9a091f0e8cea"
Hint: OgType
Value: article
@@ -160,13 +163,16 @@ Languages:
- ID: "badd9cf9-53e0-4d0c-bcc0-2d784c282f6a"
Hint: __Updated by
Value: |
- sitecore\sebw@sitecore.net
+ sitecore\qDWz4GMo2o
- ID: "d9cf14b1-fa16-4ba6-9288-e8a174d4d522"
Hint: __Updated
- Value: 20221004T072522Z
+ Value: 20231212T000936Z
- ID: "e08359cc-7bf5-4866-81a6-1e1d07226667"
Hint: MetaDescription
Value: MVP Home Description
- ID: "eeb29922-a760-44a8-a5ab-f28efbdc641c"
Hint: OgDescription
Value: MVP Home Description
+ - ID: "efc0a3c7-6993-47d2-ba85-10b44961916e"
+ Hint: IncludeInMenu
+ Value: 1
diff --git a/src/Project/MvpSite/items/content/MvpSite/Home/About.yml b/src/Project/MvpSite/items/content/MvpSite/Home/About.yml
index 097db65e..d038cf42 100644
--- a/src/Project/MvpSite/items/content/MvpSite/Home/About.yml
+++ b/src/Project/MvpSite/items/content/MvpSite/Home/About.yml
@@ -7,6 +7,9 @@ SharedFields:
- ID: "ba3f86a2-4a1c-4d78-b63d-91c2779c1b5e"
Hint: __Sortorder
Value: 100
+- ID: "e319ae64-c32a-4e79-b102-256f8c869dae"
+ Hint: IncludeinSitemap
+ Value: 1
- ID: "f1a1fe9e-a60c-4ddb-a3a0-bb5b29fe732e"
Hint: __Renderings
Value: |
@@ -77,14 +80,14 @@ Languages:
Value: 20200604T042230Z
- ID: "8cdc337e-a112-42fb-bbb4-4143751e123f"
Hint: __Revision
- Value: "94e9fd25-7606-41b5-9ea0-012b3f9065ba"
+ Value: "a2655e6a-c3ac-48d7-8446-4422faad31a0"
- ID: "b1ece12f-b2c9-44e6-92a3-c5dfd6514b59"
Hint: MenuTitle
Value: About
- ID: "badd9cf9-53e0-4d0c-bcc0-2d784c282f6a"
Hint: __Updated by
Value: |
- sitecore\iva@sitecore.net
+ sitecore\qDWz4GMo2o
- ID: "d9cf14b1-fa16-4ba6-9288-e8a174d4d522"
Hint: __Updated
- Value: 20220928T162952Z
+ Value: 20231212T000919Z
diff --git a/src/Project/MvpSite/items/content/MvpSite/Home/Application.yml b/src/Project/MvpSite/items/content/MvpSite/Home/Application.yml
index 2e043425..05276979 100644
--- a/src/Project/MvpSite/items/content/MvpSite/Home/Application.yml
+++ b/src/Project/MvpSite/items/content/MvpSite/Home/Application.yml
@@ -8,6 +8,12 @@ SharedFields:
- ID: "06d5295c-ed2f-4a54-9bf2-26228d113318"
Hint: __Icon
Value: office/32x32/desktop.png
+- ID: "508c54c0-cd02-4266-8b68-d71f88de1aa9"
+ Hint: ChangeFrequency
+ Value:
+- ID: "76fb6ffd-4487-4028-a1cf-705fbe360cba"
+ Hint: Priority
+ Value:
- ID: "ba3f86a2-4a1c-4d78-b63d-91c2779c1b5e"
Hint: __Sortorder
Value: 200
@@ -23,7 +29,7 @@ SharedFields:
p:before="*"
s:ds="{5C0D2E63-B9A6-49BF-81B1-E25DF54CB76E}"
s:id="{13175655-0158-41FA-B796-AC2663CFED2A}"
- s:par="CSSStyles"
+ s:par=""
s:ph="/main/column-container-{413EB6EB-522B-4E53-825B-21992D7DD3F3}-0"
s:ccb="Clear on publish" />
_logger;
+ private readonly SitemapBuilder _sitemap;
- public DefaultController(ILogger logger)
+ public DefaultController(ILogger logger, SitemapBuilder sitemap)
{
_logger = logger;
+ _sitemap = sitemap;
}
// Inject Sitecore rendering middleware for this controller action
@@ -78,5 +81,12 @@ public IActionResult Healthz()
// TODO: Do we want to add logic here to confirm connectivity with SC etc?
return Ok("Healthy");
}
+
+ [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
+ public IResult SiteMap()
+ {
+ var xml = _sitemap.GenerateAsync();
+ return Results.Stream(xml.Result, "text/xml");
+ }
}
}
\ No newline at end of file
diff --git a/src/Project/MvpSite/rendering/Middleware/CustomGraphQlLayoutServiceHandler.cs b/src/Project/MvpSite/rendering/Middleware/CustomGraphQlLayoutServiceHandler.cs
new file mode 100644
index 00000000..5516a2f7
--- /dev/null
+++ b/src/Project/MvpSite/rendering/Middleware/CustomGraphQlLayoutServiceHandler.cs
@@ -0,0 +1,41 @@
+using Microsoft.Extensions.Configuration;
+using Mvp.Foundation.Configuration.Rendering.AppSettings;
+using Mvp.Foundation.DataFetching.GraphQL;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+
+namespace Mvp.Project.MvpSite.Middleware
+{
+ public class CustomGraphQlLayoutServiceHandler
+ {
+ private readonly IGraphQLRequestBuilder _graphQLRequestBuilder;
+ private readonly IGraphQLClientFactory _graphQLClientFactory;
+ private readonly MvpSiteSettings _configuration;
+
+ public CustomGraphQlLayoutServiceHandler(IConfiguration configuration, IGraphQLRequestBuilder graphQLRequestBuilder, IGraphQLClientFactory graphQLClientFactory)
+ {
+ _graphQLRequestBuilder = graphQLRequestBuilder;
+ _graphQLClientFactory = graphQLClientFactory;
+ _configuration = configuration.GetSection(MvpSiteSettings.Key).Get();
+ }
+
+ public async Task> GetSitemap()
+ {
+ var client = _graphQLClientFactory.CreateGraphQlClient();
+ var query = Constants.GraphQlQueries.GetSitemapQuery;
+ var variables = (object)new
+ {
+ rootItemId = _configuration.RootItemId,
+ language = _configuration.DefaultLanguage
+ };
+
+ var request = _graphQLRequestBuilder.BuildRequest(query, variables);
+ var graphQlResponse = await client.SendQueryAsync(request);
+
+ return graphQlResponse.Data.Search.Results;
+ }
+ }
+}
+
+
+
diff --git a/src/Project/MvpSite/rendering/Models/SitemapModel.cs b/src/Project/MvpSite/rendering/Models/SitemapModel.cs
new file mode 100644
index 00000000..d1594686
--- /dev/null
+++ b/src/Project/MvpSite/rendering/Models/SitemapModel.cs
@@ -0,0 +1,60 @@
+// Root myDeserializedClass = JsonConvert.DeserializeObject(myJsonResponse);
+using System.Collections.Generic;
+
+public class ChangeFrequency
+{
+ public TargetItem TargetItem { get; set; }
+}
+
+public class SitemapData
+{
+ public SearchData Search { get; set; }
+}
+
+public class PageInfo
+{
+ public string endCursor { get; set; }
+ public bool hasNext { get; set; }
+}
+
+public class Priority
+{
+ public TargetItem TargetItem { get; set; }
+}
+
+public class Result
+{
+ public Updateddatetime UpdatedDatetime { get; set; }
+ public Url Url { get; set; }
+ public string Name { get; set; }
+ public Priority Priority { get; set; }
+ public ChangeFrequency ChangeFrequency { get; set; }
+}
+
+public class Root
+{
+ public SitemapData Data { get; set; }
+}
+
+public class SearchData
+{
+ public int total { get; set; }
+ public PageInfo pageInfo { get; set; }
+ public List Results { get; set; }
+}
+
+public class TargetItem
+{
+ public string DisplayName { get; set; }
+}
+
+public class Updateddatetime
+{
+ public string Value { get; set; }
+}
+
+public class Url
+{
+ public string Path { get; set; }
+}
+
diff --git a/src/Project/MvpSite/rendering/Mvp.Project.MvpSite.Rendering.csproj b/src/Project/MvpSite/rendering/Mvp.Project.MvpSite.Rendering.csproj
index 1b76d1ce..1eccff47 100644
--- a/src/Project/MvpSite/rendering/Mvp.Project.MvpSite.Rendering.csproj
+++ b/src/Project/MvpSite/rendering/Mvp.Project.MvpSite.Rendering.csproj
@@ -35,6 +35,7 @@
+
diff --git a/src/Project/MvpSite/rendering/Sitemap/Providers/ISitemapUrlProvider.cs b/src/Project/MvpSite/rendering/Sitemap/Providers/ISitemapUrlProvider.cs
new file mode 100644
index 00000000..689bf1f6
--- /dev/null
+++ b/src/Project/MvpSite/rendering/Sitemap/Providers/ISitemapUrlProvider.cs
@@ -0,0 +1,10 @@
+using DotnetSitemapGenerator;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+
+namespace Mvp.Project.MvpSite.Rendering;
+
+public interface ISitemapUrlProvider
+{
+ Task> GetNodes();
+}
\ No newline at end of file
diff --git a/src/Project/MvpSite/rendering/Sitemap/Providers/MvpSitemapUrlProvider.cs b/src/Project/MvpSite/rendering/Sitemap/Providers/MvpSitemapUrlProvider.cs
new file mode 100644
index 00000000..423880a8
--- /dev/null
+++ b/src/Project/MvpSite/rendering/Sitemap/Providers/MvpSitemapUrlProvider.cs
@@ -0,0 +1,100 @@
+using DotnetSitemapGenerator;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Routing;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.Logging;
+using Mvp.Foundation.DataFetching.GraphQL;
+using Mvp.Project.MvpSite.Middleware;
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Threading.Tasks;
+
+namespace Mvp.Project.MvpSite.Rendering;
+
+public class Mvp
+{
+ public int Id { get; set; }
+ public string Name { get; set; }
+ public string Path { get; set; }
+}
+
+public class MvpSitemapUrlProvider : ISitemapUrlProvider
+{
+ private readonly LinkGenerator _linkGenerator;
+ private readonly IHttpContextAccessor _httpContextAccessor;
+ private readonly ILogger _logger;
+ private readonly IGraphQLClientFactory _graphQLClientFactory;
+ private readonly IGraphQLRequestBuilder _graphQLRequestBuilder;
+ private readonly IConfiguration _configuration;
+
+ public MvpSitemapUrlProvider(
+ LinkGenerator linkGenerator,
+ IHttpContextAccessor httpContextAccessor,
+ ILogger logger,
+ IGraphQLClientFactory graphQLClientFactory,
+ IGraphQLRequestBuilder graphQLRequestBuilder,
+ IConfiguration configuration)
+ {
+ _linkGenerator = linkGenerator;
+ _httpContextAccessor = httpContextAccessor;
+ _logger = logger;
+ _graphQLClientFactory = graphQLClientFactory;
+ _graphQLRequestBuilder = graphQLRequestBuilder;
+ _configuration = configuration;
+ }
+
+ private static DotnetSitemapGenerator.ChangeFrequency GetChangeFrequency(string changefreq)
+ {
+ if (string.IsNullOrWhiteSpace(changefreq)) { return DotnetSitemapGenerator.ChangeFrequency.Never; }
+
+ switch (changefreq.ToLowerInvariant())
+ {
+ case "always":
+ return DotnetSitemapGenerator.ChangeFrequency.Always;
+ case "daily":
+ return DotnetSitemapGenerator.ChangeFrequency.Daily;
+ case "weekly":
+ return DotnetSitemapGenerator.ChangeFrequency.Weekly;
+ case "yearly":
+ return DotnetSitemapGenerator.ChangeFrequency.Yearly;
+ case "hourly":
+ return DotnetSitemapGenerator.ChangeFrequency.Hourly;
+ case "never":
+ return DotnetSitemapGenerator.ChangeFrequency.Never;
+ }
+
+ return DotnetSitemapGenerator.ChangeFrequency.Never;
+ }
+
+ public Task> GetNodes()
+ {
+ var nodes = new List();
+ var results = GetSiteMap();
+
+ foreach (var result in results)
+ {
+ var url = _httpContextAccessor.HttpContext.Request.Scheme + "://" + _httpContextAccessor.HttpContext.Request.Host.Value + result.Url.Path;
+
+ _logger.LogInformation("Adding product: {URL}", url);
+
+ SitemapNode node = new(url)
+ {
+ LastModificationDate = DateTime.ParseExact(result.UpdatedDatetime?.Value,
+ "yyyyMMdd'T'HHmmss'Z'",
+ CultureInfo.InvariantCulture),
+ Priority = Convert.ToDecimal(result.Priority?.TargetItem?.DisplayName),
+ ChangeFrequency = GetChangeFrequency(result.ChangeFrequency?.TargetItem?.DisplayName)
+ };
+ nodes.Add(node);
+ }
+
+ return Task.FromResult>(nodes);
+ }
+
+ private List GetSiteMap()
+ {
+ CustomGraphQlLayoutServiceHandler customGraphQlLayoutServiceHandler = new(_configuration, _graphQLRequestBuilder, _graphQLClientFactory);
+ return customGraphQlLayoutServiceHandler.GetSitemap().Result;
+ }
+}
\ No newline at end of file
diff --git a/src/Project/MvpSite/rendering/Sitemap/SitemapBuilder.cs b/src/Project/MvpSite/rendering/Sitemap/SitemapBuilder.cs
new file mode 100644
index 00000000..61bdda09
--- /dev/null
+++ b/src/Project/MvpSite/rendering/Sitemap/SitemapBuilder.cs
@@ -0,0 +1,33 @@
+using DotnetSitemapGenerator;
+using DotnetSitemapGenerator.Serialization;
+using System.Collections.Generic;
+using System.IO;
+using System.Threading.Tasks;
+
+namespace Mvp.Project.MvpSite.Rendering;
+
+public class SitemapBuilder
+{
+ private readonly IEnumerable _providers;
+
+ public SitemapBuilder(IEnumerable providers)
+ {
+ _providers = providers;
+ }
+
+ public async Task GenerateAsync()
+ {
+ var nodes = new List();
+ foreach (var provider in _providers)
+ {
+ nodes.AddRange(await provider.GetNodes());
+ }
+
+ IXmlSerializer sitemapProvider = new XmlSerializer();
+ var memory = new MemoryStream();
+ sitemapProvider.SerializeToStream(new SitemapModel(nodes), memory);
+ // reset the stream to the start
+ memory.Position = 0;
+ return memory;
+ }
+}
\ No newline at end of file
diff --git a/src/Project/MvpSite/rendering/Sitemap/SitemapExtensions.cs b/src/Project/MvpSite/rendering/Sitemap/SitemapExtensions.cs
new file mode 100644
index 00000000..5780e7bd
--- /dev/null
+++ b/src/Project/MvpSite/rendering/Sitemap/SitemapExtensions.cs
@@ -0,0 +1,13 @@
+using Microsoft.Extensions.DependencyInjection;
+
+namespace Mvp.Project.MvpSite.Rendering;
+
+public static class SitemapExtensions
+{
+ public static void AddSitemap(this IServiceCollection services)
+ {
+ // add sitemap services
+ services.AddScoped();
+ services.AddScoped();
+ }
+}
\ No newline at end of file
diff --git a/src/Project/MvpSite/rendering/Sitemap/SitemapResponse.cs b/src/Project/MvpSite/rendering/Sitemap/SitemapResponse.cs
new file mode 100644
index 00000000..898cb7d4
--- /dev/null
+++ b/src/Project/MvpSite/rendering/Sitemap/SitemapResponse.cs
@@ -0,0 +1,20 @@
+using System.Text.Json;
+
+namespace Mvp.Project.MvpSite.Sitemap
+{
+ public class SitemapQueryResponse
+ {
+ //
+ // Summary:
+ // Gets or sets Layout Service GraphQL Response.
+ public SitemapModel SiteMap { get; set; }
+ }
+
+ public class SitemapModel
+ {
+ //
+ // Summary:
+ // Gets or sets Layout Service GraphQL Response.
+ public JsonElement? Sitemap { get; set; }
+ }
+}
diff --git a/src/Project/MvpSite/rendering/Startup.cs b/src/Project/MvpSite/rendering/Startup.cs
index 13a0c61f..5bcda33a 100644
--- a/src/Project/MvpSite/rendering/Startup.cs
+++ b/src/Project/MvpSite/rendering/Startup.cs
@@ -58,6 +58,8 @@ public void ConfigureServices(IServiceCollection services)
.AddGraphQlHandler("default", Configuration.DefaultSiteName!, Configuration.ExperienceEdgeToken!, Configuration.LayoutServiceUri!)
.AsDefaultHandler();
+ services.AddHttpContextAccessor();
+ services.AddSitemap();
services.AddFeatureUser(DotNetConfiguration);
// Register the Sitecore Rendering Engine services.
@@ -141,8 +143,7 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
// Enable Authentication & Authorization
app.UseAuthentication();
- app.UseAuthorization();
-
+ app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
@@ -155,6 +156,12 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
"healthz",
"healthz",
new { controller = "Default", action = "Healthz" }
+ );
+
+ endpoints.MapControllerRoute(
+ "Sitemap",
+ "sitemap.xml",
+ new { controller = "Default", action = "SiteMap" }
);
endpoints.MapOktaSigninRoute();
diff --git a/src/Project/MvpSite/rendering/appsettings.Development.json b/src/Project/MvpSite/rendering/appsettings.Development.json
index 3dae2617..a26661b8 100644
--- a/src/Project/MvpSite/rendering/appsettings.Development.json
+++ b/src/Project/MvpSite/rendering/appsettings.Development.json
@@ -3,7 +3,6 @@
"InstanceUri": "https://xmcloudcm.localhost/",
"LayoutServicePath": "/sitecore/api/graph/edge",
"DefaultSiteName": "mvp-site",
- "NotFoundPage": "/404",
"ExperienceEdgeToken": "{E2F3D43E-B1FD-495E-B4B1-84579892422A}",
"MvpDirectoryGraphQLQueryPageSize": 1000,
"MvpDirectoryGraphQLQueryCacheTimeout": 1
@@ -16,7 +15,7 @@
}
},
"AllowedHosts": "*",
- "Okta" : {
+ "Okta": {
"OktaDomain": "<>",
"ClientId": "<>",
"ClientSecret": "<>",
diff --git a/src/Project/MvpSite/rendering/appsettings.json b/src/Project/MvpSite/rendering/appsettings.json
index 56ebfc56..d672c768 100644
--- a/src/Project/MvpSite/rendering/appsettings.json
+++ b/src/Project/MvpSite/rendering/appsettings.json
@@ -4,6 +4,8 @@
"LayoutServicePath": "/api/graphql/v1",
"DefaultSiteName": "mvp-site",
"NotFoundPage": "/404",
+ "RootItemId": "A43C669260F44743A1BE6424DE611DFA",
+ "DefaultLanguage": "en",
"ExperienceEdgeToken": "<>",
"MvpDirectoryGraphQLQueryPageSize": 1000,
"MvpDirectoryGraphQLQueryCacheTimeout": 60,