In the template editor...pick sitemap from the dropdown...gives you this...
<umbraco:Macro runat="server" language="cshtml"> @* SITEMAP ================================= This snippet generates a complete sitemap of all pages that are published and visible (it'll filter out any pages with a property named "umbracoNaviHide" that's set to 'true'). It's also a great example on how to make helper methods in Razor and how to pass values to your '.Where' filters.
How to Customize for re-use (only applies to Macros, not if you insert this snippet directly in a template): - If you add a Macro Parameter with the alias of "MaxLevelForSitemap" which specifies how deep in the hierarchy to traverse
How it works: - The first line (var maxLevelForSitemap) assigns default values if none is specified via Macro Parameters - Next is a helper method 'traverse' which uses recursion to keep making new lists for each level in the sitemap - Inside the the 'traverse' method there's an example of using a 'Dictionary' to pass the 'maxLevelForSitemap' to the .Where filter - Finally the 'traverse' method is called taking the very top node of the website by calling AncesterOrSelf()
NOTE: It is safe to remove this comment (anything between @ * * @), the code that generates the list is only the below! *@
Instead of node.Children, you can type node.textPage (textPage is the alias of the documentType) so you will get the Children which are of that document type only where you need to filter
It won't make that much difference as the script is recursively 'walking the tree'...so each foreach call is only getting the direct children of that single node. If there where 1000's of direct siblings and only a few of the correct type, then it would make a difference.
However, assuming your site isn't massive or extremely 'flat', I doubt if it would make much difference.
I'm trying to use the cshtml script shown above. I've created a new macro and referenced the file, yet I get an error when I add the macro into the editor. Is there something else I need to do to use Razor, this is my first time trying out Razor so be kind!
Razor code for complete navigation
Anyone has Razor code (or could create one quickly for me) that prints all pages, not only the first level?
The end result I want is like this
I am not sure how to do the recursion or get the child pages, I'm still new to Umbraco and Razor.
Thanks in advance.
If you're doing recursive, you'll have to make a function.
I'll try and put together a fast example.
In the template editor...pick sitemap from the dropdown...gives you this...
<umbraco:Macro runat="server" language="cshtml">
@*
SITEMAP
=================================
This snippet generates a complete sitemap of all pages that are published and visible (it'll filter out any
pages with a property named "umbracoNaviHide" that's set to 'true'). It's also a great example on how to make
helper methods in Razor and how to pass values to your '.Where' filters.
How to Customize for re-use (only applies to Macros, not if you insert this snippet directly in a template):
- If you add a Macro Parameter with the alias of "MaxLevelForSitemap" which specifies how deep in the hierarchy to traverse
How it works:
- The first line (var maxLevelForSitemap) assigns default values if none is specified via Macro Parameters
- Next is a helper method 'traverse' which uses recursion to keep making new lists for each level in the sitemap
- Inside the the 'traverse' method there's an example of using a 'Dictionary' to pass the 'maxLevelForSitemap' to
the .Where filter
- Finally the 'traverse' method is called taking the very top node of the website by calling AncesterOrSelf()
NOTE: It is safe to remove this comment (anything between @ * * @), the code that generates the list is only the below!
*@
@inherits umbraco.MacroEngines.DynamicNodeContext
@helper traverse(dynamic node){
var maxLevelForSitemap = String.IsNullOrEmpty(Parameter.MaxLevelForSitemap) ? 4 : int.Parse(Parameter.MaxLevelForSitemap);
var values = new Dictionary<string,object>();
values.Add("maxLevelForSitemap", maxLevelForSitemap) ;
var items = node.Children.Where("Visible").Where("Level <= maxLevelForSitemap", values);
<ul>
@foreach (var item in items) {
<li>
<a href="@item.Url">@item.Name</a>
@traverse(item)
</li>
}
</ul>
}
<div class="sitemap">
@traverse(@Model.AncestorOrSelf())
</div>
</umbraco:Macro>
And there you go! :)
I didn't realise there is SiteMap that does that. Thanks a lot Steen and Trevor!
Guys, would you also know how I filter the document type.
I have news items under the News page and they are showing as well.
I have document types HomePage, NewsPage and TextPage, all of them are inherited from the type Page
How can I do something like this?
var items = node.Children.Where("Visible").Where("documentType is Page");
Can you just change the 'level' that the sitemap goes to?
var maxLevelForSitemap = String.IsNullOrEmpty(Parameter.MaxLevelForSitemap) ? 4 : int.Parse(Parameter.MaxLevelForSitemap);
Note that the default level is 4 if the parameter is null.
Let me know if not and I'll look into it.
Thanks Trevor, but I can't, because under the News page I've got news items, but under other pages, I've got sub-pages (TextPages)
Instead of node.Children, you can type node.textPage (textPage is the alias of the documentType) so you will get the Children which are of that document type only where you need to filter
Thanks,
-Rajeev
I have document types HomePage, NewsPage and TextPage, all of them are inherited from the type Page. (Can you see my screenshot above?)
I want to show all those document types
Can you just add an if statement into the loop?
@foreach (var item in items) {
if (@item.NodeTypeAlias == "doctype1" || @item.NodeTypeAlias == "DC2" etc)
{
<li>
<a href="@item.Url">@item.Name</a>
@traverse(item)
</li>
}
}
ah... yea i can probably do that, thanks!
isn't it more efficient to filter it before that though...? but that should also work thanks Trevor!
It won't make that much difference as the script is recursively 'walking the tree'...so each foreach call is only getting the direct children of that single node. If there where 1000's of direct siblings and only a few of the correct type, then it would make a difference.
However, assuming your site isn't massive or extremely 'flat', I doubt if it would make much difference.
Thanks Trevor.
Actually it doesn't work if you filter it in the loop, because it will then create empty <ul>'s if all the sub pages are filtered out.
Now my cshtml gets very complicated, I'd rather use ascx. But @Model.AncestorOrSelf doesn't exist in .ascx. What do I replace it with? Any idea?
If you are now trying to implement in your own user control, I'd just use the umbraco api.
Node.GetCurrent() will get the current node for the 'page'
Node.GetChildren() for the children etc.
...what are you trying to schieve?
I'm trying to mimic sitemap, but not to print empty ul's. It'd be easier using ascx.
So how do I get ALL the nodes instead of only the current node or its children? I couldn't do Node.GetAncestorOrSelf()
Thanks again!
private string Traverse(Node node) {
var items = node.Children.Where("Visible").Where("hideInNavi==false");
Even the above already gives an error:
'umbraco.NodeFactory.Nodes' does not contain a definition for 'Where' ...
How do you do that line in C# (ascx)?
Sorry I kept getting problems just to get the top navigation working.
I'm trying to use the cshtml script shown above. I've created a new macro and referenced the file, yet I get an error when I add the macro into the editor. Is there something else I need to do to use Razor, this is my first time trying out Razor so be kind!
Problem solved, it works once you save and publish...
is working on a reply...