Take the community feedback survey now.
Take the community feedback survey now.
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