Join us this Friday for AI in Action at the Virtual Happy Hour! This free virtual event is open to all—enroll now on Academy and don’t miss out.
Join us this Friday for AI in Action at the Virtual Happy Hour! This free virtual event is open to all—enroll now on Academy and don’t miss out.
Something like this?
public class SitemapNode { public string Title { get; set; } public string Url { get; set; } public List<SitemapNode> Nodes { get; set; } }
public class FilterPublicAccess : PageFilterBase { private readonly IPrincipal _principal; public FilterPublicAccess() { _principal = new GenericPrincipal(new GenericIdentity("visitor"), new[] { "Everyone" }); } public override bool ShouldFilter(PageData page) { return !page.ACL.QueryDistinctAccess(_principal, AccessLevel.Read); } public override bool ShouldFilter(IContent content) { var page = content as PageData; if (page == null) { return false; } return ShouldFilter(page); } }
public class SitemapGenerator { private readonly IContentLoader _contentLoader; private readonly UrlResolver _urlResolver; public SitemapGenerator(IContentLoader contentLoader, UrlResolver urlResolver) { _contentLoader = contentLoader; _urlResolver = urlResolver; } public SitemapNode GetNodes(PageReference startPage) { var page = _contentLoader.Get<PageData>(startPage); var node = new SitemapNode { Title = page.Name, Url = GetExternalUrl(page.PageLink) }; GetChildNodes(page, node); return node; } private void GetChildNodes(PageData page, SitemapNode node) { var publicAccessFilter = new FilterPublicAccess(); var publishedFilter = new FilterPublished(); var children = _contentLoader.GetChildren<PageData>(page.ContentLink) .Where(x => // skip container pages x.HasTemplate() && // skip pages that have 'Display in navigation' unchecked x.VisibleInMenu && // skip pages that are not visible to everyone !publicAccessFilter.ShouldFilter(x) && // skip unpublished pages !publishedFilter.ShouldFilter(x)) .ToList(); if (children.Count == 0) return; node.Nodes = new List<SitemapNode>(children.Count); foreach (var child in children) { var sitemapNode = new SitemapNode { Title = child.Name, Url = GetExternalUrl(child.PageLink) }; GetChildNodes(child, sitemapNode); node.Nodes.Add(sitemapNode); } } private string GetExternalUrl(PageReference pageReference) { var internalUrl = _urlResolver.GetUrl(pageReference); var url = new UrlBuilder(internalUrl); EPiServer.Global.UrlRewriteProvider.ConvertToExternal(url, null, Encoding.UTF8); return url.ToString(); } }
In page controller, you can generate sitemap like this:
var siteMapGenerator = ServiceLocator.Current.GetInstance<SitemapGenerator>(); var node = siteMapGenerator.GetNodes(ContentReference.StartPage);
Result from Alloy:
Hope this helps :)
You can create a helper class like this:
public static class SitemapHelper { public static void GenerateSitemap(this HtmlHelper html, SitemapNode sitemap) { html.ViewContext.Writer.WriteLine("<ul>"); WriteNode(html, sitemap); html.ViewContext.Writer.WriteLine("</ul>"); } private static void WriteNode(this HtmlHelper html, SitemapNode node) { html.ViewContext.Writer.WriteLine("<li>"); html.ViewContext.Writer.WriteLine("<a href=\"{0}\">{1}</a>", node.Url, node.Title); if (node.Nodes != null && node.Nodes.Count > 0) { html.ViewContext.Writer.WriteLine("<ul>"); foreach (var childNode in node.Nodes) { WriteNode(html, childNode); } html.ViewContext.Writer.WriteLine("</ul>"); } html.ViewContext.Writer.WriteLine("</li>"); } }
I don't know how your viewmodel looks like, but you could have something like this in controller:
var viewModel = new MyViewModel(currentPage); var siteMapGenerator = ServiceLocator.Current.GetInstance<SitemapGenerator>(); var sitemap = siteMapGenerator.GetNodes(ContentReference.StartPage); viewModel.Sitemap = sitemap; return View(viewModel);
View:
@model MyViewModel @{ Html.GenerateSitemap(Model.Sitemap); }
It should generate the following HTML for Alloy:
<ul> <li> <a href="/">Start</a> <ul> <li> <a href="/alloy-plan/">Alloy Plan</a> <ul> <li> <a href="/alloy-plan/download-alloy-plan/">Download Alloy Plan</a> </li> </ul> </li> <li> <a href="/alloy-track/">Alloy Track</a> <ul> <li> <a href="/alloy-track/download-alloy-track/">Download Alloy Track</a> </li> <li> <a href="/alloy-track/download-whitepaper-alloy-track/">Whitepaper</a> </li> </ul> </li> <li> <a href="/alloy-meet/">Alloy Meet</a> <ul> <li> <a href="/alloy-meet/download-alloy-meet/">Download Alloy Meet</a> </li> </ul> </li> <li> <a href="/about-us/">About us</a> <ul> <li> <a href="/about-us/news-events/">News & Events</a> <ul> <li> <a href="/about-us/news-events/events/">Events</a> <ul> <li> <a href="/about-us/news-events/events/reporting-made-simple/">Reporting Made Simple</a> </li> <li> <a href="/about-us/news-events/events/collaboration-made-simple/">Collaboration Made Simple</a> </li> <li> <a href="/about-us/news-events/events/risk-management-in-complex-projects/">Risk Management</a> </li> </ul> </li> <li> <a href="/about-us/news-events/press-releases/">Press Releases</a> <ul> <li> <a href="/about-us/news-events/press-releases/alloy-pays-it-forward/">Alloy Pays it Forward</a> </li> <li> <a href="/about-us/news-events/press-releases/newworld-wildlife-fund-chooses-alloy/">Alloy Saves Bears</a> </li> <li> <a href="/about-us/news-events/press-releases/alloy-plan-enhances-risk-management/">Enhances Risk Management</a> </li> <li> <a href="/about-us/news-events/press-releases/alloy-meet-acclaimed-for-top-collaboration-technology/">Top Collaboration Technology</a> </li> </ul> </li> </ul> </li> <li> <a href="/about-us/management/">Management</a> </li> <li> <a href="/about-us/contact-us/">Contact us</a> </li> <li> <a href="/about-us/become-a-reseller/">Become a reseller</a> </li> </ul> </li> </ul> </li> </ul>
HI,
Can I ask what your viewmodel looks like please? It's always tricky looking at someone elses code and your thoughts are all blank :).
Hi,
Let's say you have sitemap page type defined like this:
[ContentType(GUID = "d6030985-2cb1-4c03-801e-a282a8122bd0")] public class SitemapPage : PageData { // ... }
If you want to use PageViewModel<T> approach from Alloy:
public class MyViewModel : PageViewModel<StartPage> { public MyViewModel(SitemapPage currentPage) : base(currentPage) { } public SitemapNode Sitemap { get; set; } }
Otherwise you can define your viewmodel like this:
public class MyViewModel { public MyViewModel(SitemapPage currentPage) { CurrentPage = currentPage; } public SitemapPage CurrentPage { get; private set; } public SitemapNode Sitemap { get; set; } }
Page type:
[ContentType(GUID = "d6030985-2cb1-4c03-801e-a282a8122bd0")] public class SitemapPage : PageData { // ... }
View model:
public class SitemapViewModel { public SitemapViewModel(SitemapPage currentPage) { CurrentPage = currentPage; } public SitemapPage CurrentPage { get; private set; } public SitemapNode Sitemap { get; set; } }
Controller:
public class SitemapPageController : PageController<SitemapPage> { public ActionResult Index(SitemapPage currentPage) { var viewModel = new SitemapViewModel(currentPage); var siteMapGenerator = ServiceLocator.Current.GetInstance<SitemapGenerator>(); var sitemap = siteMapGenerator.GetNodes(ContentReference.StartPage); viewModel.Sitemap = sitemap; return View(viewModel); } }
View (you may need to change the namespace):
@model SitemapDemo.Controllers.SitemapViewModel @{ Html.GenerateSitemap(Model.Sitemap); }
Hi, Many thanks for your patience - this is exactly what I needed and works like a charm - thansk for all your help,
:)
Jon
Hi,
Is it possible to generate a normal Sitemap for a site - not an XML site map but a navigation type site map that shows all the published pages on a site.
I can do it as a webform but for this project we are using MVC.
Thanks
Jon