I am trying to create an xml sitemap surface controller, so i will not have to use a view.
But current problem is that in Umbraco 8 i cannot figure out how to get the Home (root) page...
my code:
public class XmlSitemapSurfaceController : SurfaceController
{
// {domain}/umbraco/surface/xmlsitemapsurface/generatexmlsitemap
public FileResult GenerateXmlSiteMap()
{
// Get all registered Domains in Umbraco
var home = CurrentPage.AncestorOrSelf<Home>(); // find the home node.
var children = home.Descendants(); // get needed content from each page.
var sitemapList = new List<SitemapModel>(); //initiate new list.
foreach (var item in children)
{
if (!item.Value<bool>("hideFromSitemap"))
{
var sitemapItem = new SitemapModel()
{
Loc = item.UrlAbsolute(),
LastUpdated = item.UpdateDate,
Priority = "0.5",
ChangeFreq = "weekly"
};
sitemapList.Add(sitemapItem);
}
}
// Generate XML in proper format.
var xml = GenerateXml(sitemapList);
// return as XML.
var stream = new MemoryStream();
var writer = XmlWriter.Create(stream);
xml.WriteTo(writer);
writer.Flush();
stream.Seek(0, SeekOrigin.Begin);
return File(stream, "text/xml", "sitemap.xml"); // returns an XML file with name sitemap.xml
}
public XDocument GenerateXml(IEnumerable<SitemapModel> data)
{
XNamespace ns = "http://www.sitemaps.org/schemas/sitemap/0.9";
XNamespace xsiNs = "http://www.w3.org/2001/XMLSchema-instance";
XDocument doc = new XDocument(
new XDeclaration("1.0", "UTF-8", "no"),
new XElement(ns + "urlset",
new XAttribute(XNamespace.Xmlns + "xsi", xsiNs),
new XAttribute(xsiNs + "schemeLocation",
"http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd"),
GenerateElements(data, ns)
));
return doc;
}
public IEnumerable<XElement> GenerateElements(IEnumerable<SitemapModel> data, XNamespace ns)
{
List<XElement> elements = new List<XElement>();
foreach (var item in data)
{
var element = new XElement(ns + "url",
new XElement(ns + "loc", item.Loc),
new XElement(ns + "lastmod", item.Lastmod),
new XElement(ns + "changefreq", item.ChangeFreq),
new XElement(ns + "priority", item.Priority)
);
elements.Add(element);
}
return elements;
}
}
Anyone know what i can do to get the Home (root) node ?
The idea behind the above is what ever domain i access the surface controller through, it should just get all descendants of that root (home) page.
The problem is the Surface Controller takes the 'context' of it's CurrentPage from the template of the document type it has been added to, but in your suggestion above you are calling the surface controller 'directly' via
and Umbraco does not know which IPublishedContent item in umbraco should be the 'CurrentPage'
If you only have one site, then you could take this approach and query for all the 'root level content' and pick the home node (it would likely be the only one)
var home = Umbraco.ContentAtRoot().Where(f=>f.Name == "Home").FirstOrDefault(); // find the home node.
Then your approach would work.
But if you have multiple sites in Umbraco with different domains, then I'd probably create an XmlSiteMap document type, - and create a 'SiteMap' node in each site's content tree - and use route hijacking to create a RenderMvcController to handle any requests to the XmlSiteMap page - now this page 'would have the context' of the site that it is published in, and then you could find your homepage, via the Umbraco.Web namespace's Site() extension method... and build your sitemap from there.
in my surface controller calling a helper class i created.
var home = this.nodeHelper.GetFrontpage(); // find the home node.
and the helper:
public class NodeHelper
{
private readonly HttpContextBase httpContext;
private readonly UmbracoHelper umbracoHelper;
public NodeHelper(
HttpContextBase httpContext,
UmbracoHelper umbracoHelper)
{
this.httpContext = httpContext;
this.umbracoHelper = umbracoHelper;
}
public Home GetFrontpage()
{
Uri url = this.httpContext.Request.Url;
var registeredDomains = Umbraco.Core.Composing.Current.Services.DomainService.GetAll(false).ToList();
var domains = (from d in registeredDomains
where d.DomainName.StartsWith($"{url.Scheme}://{url.Authority}") ||
d.DomainName.StartsWith($"{url.Scheme}://{url.Host}") ||
d.DomainName.Contains(url.Authority) ||
d.DomainName.Contains(url.Host)
select d).ToList();
var domain = domains.FirstOrDefault();
return this.GetFrontpage(domain);
}
public Home GetFrontpage(IDomain domain)
{
if (domain == null || domain.RootContentId.HasValue == false)
{
return null;
}
else
{
var content = this.umbracoHelper.Content(domain.RootContentId.Value) as Home;
return content;
}
}
}
This should give me the frontpage node based on my URL so i can call the xmlsitemap surfacecontroller no matter what site i am on. Then it will just generate the sitemap for that "site".
Umbraco 8 Surfacecontroller get root
I am trying to create an xml sitemap surface controller, so i will not have to use a view.
But current problem is that in Umbraco 8 i cannot figure out how to get the Home (root) page...
my code:
Anyone know what i can do to get the Home (root) node ? The idea behind the above is what ever domain i access the surface controller through, it should just get all descendants of that root (home) page.
Hi André
The problem is the Surface Controller takes the 'context' of it's CurrentPage from the template of the document type it has been added to, but in your suggestion above you are calling the surface controller 'directly' via
{domain}/umbraco/surface/xmlsitemapsurface/generatexmlsitemap
and Umbraco does not know which IPublishedContent item in umbraco should be the 'CurrentPage'
If you only have one site, then you could take this approach and query for all the 'root level content' and pick the home node (it would likely be the only one)
var home = Umbraco.ContentAtRoot().Where(f=>f.Name == "Home").FirstOrDefault(); // find the home node.
Then your approach would work.
But if you have multiple sites in Umbraco with different domains, then I'd probably create an XmlSiteMap document type, - and create a 'SiteMap' node in each site's content tree - and use route hijacking to create a RenderMvcController to handle any requests to the XmlSiteMap page - now this page 'would have the context' of the site that it is published in, and then you could find your homepage, via the Umbraco.Web namespace's Site() extension method... and build your sitemap from there.
regards
marc
I ended up doing this:
in my surface controller calling a helper class i created.
and the helper:
This should give me the frontpage node based on my URL so i can call the xmlsitemap surfacecontroller no matter what site i am on. Then it will just generate the sitemap for that "site".
is working on a reply...