Im trying to do some menu stuff where i want to list a node structure from a changeable source on a macro. Im building on the sitemap xslt, but have a bit of a problem changing the source from $currentpage to my macro's $source. $source is a content picker
it returns the root level of my $source. But the goal is to get a nested list with subpages as well.
My complete xslt is below, if anyone can spot any errors :), thanks
Feeling lost? No problem! Time for some theory and some code. (Please forgive me if I explain stuff you already understand, but if I don't give enough detail then just ask)
The first thing to do is define what you want to do. I think you're trying to create a nested UL/LI list for your website, starting at whatever node is selected (and passed in) with a Content Picker on your macro.
Starting with the sitemap.xslt template is a great way to go. But let's build this from the ground up ourselves so it is clear what is happening at every stage. That will also make it easier for you to modify it if my sample doesn't meet your needs exactly.
The first thing to do is start with a basic xslt file. Basically, everything outside the block. That code is standard and there isn't much to do there except add a variable to the macro parameter:
[code] [/code]
(Later on you might want a variable to specify how deep to go in the content tree but for now we'll just list EVERY node below the source node, no matter how many levels down the tree it is)
Remember that the Content Picker data type contains a node ID. You will have to convert that ID into a real node to loop through its children. This is done with the umbraco.library:GetXmlNodeById() function.
Once we have the node we can get any of the usual properties, such as its name, create date, etc. Let's prove that with this simple bit of code that will print out the node name for the selected source node:
[code][/code]
Now that we've got the source node, we want to list all its immediate children in a UL list. This is done by using an xsl:for-each loop and selecting the source's child nodes:
[code]
[/code]
But if one of these nodes also has children below it we would need to manually create the UL/LI structure in the xslt macro... and keep it up to date whenever there is a change to the site structure. That won't do.
Instead, we want to create what would be called a "function" in other languages to make as many embedded UL/LI lists as needed. In xslt, we simply create another template, give it a name, and then call that named template. Just like with functions in other languages, we can pass parameters in to the named xslt template.
The sitemap.xslt file used the name 'drawNodes' so we'll do the same. We want this "function" to take a starting node and create a UL/LI list. If any of the items has children below it we want to call the drawNodes template again with THAT node so that all its children get listed as well. We'll continue to call drawNodes until we've gone through all the nodes below the original $source node.
Let's see how that's done, but step-by-step.
First, we'll re-write our last xslt sample to use a named template and we'll call that template. The output will be the same but we'll have a framework in place to make further logic modifications:
[code]
[/code]
As I said, the output of this code sample and the one before it are the same. Which means it still only shows the children of the original source node.
Let's add some logic to call the drawNodes template as many times as necessary, for as many children, grandchildren, great-grandchildren, etc. your site has. All we need to do is check to see if the current node being displayed has any children. If it does, we call the drawNodes template again, and presto we have a nested UL/LI list of all the nodes:
[code]
[/code]
There you have it, a nested UL/LI list of all the nodes below the original $source node.
Of course, you can embellish this code to include href's instead of simply printing the node names:
[code]
[/code]
And you could add various tests to limit the number of levels to display, as well as being sure not to display any node that has the umbracoNaviHide property set. You might also check that you only show pages that are either not protected or which are protected but are accessible by the currently logged in user.
When you add all of these additions you'll find that you are very close to the code in the sitemap.xslt file you started with. But now you understand why every line is there and what it is doing.
I hope this helps. Be sure to ask if anything is unclear.
Yeah that post rocked everyone's world, especially those new to Umbraco and XSLT. Question for you, Doug-- what if I just wamted to specify, as you alluded to early in the thread, the depth of the structure in which to delve? I only want to display the first two tiers....
Thanks for the reply. But this change makes everything disappear because I don't think @level has a value. How would the page (or routine) know what level it's on if I don't set it?
I you want to understand how @level works, take a look in "data/umbraco.config" thats the file where you are reading from. However you can use my second option (I prefer that method)
I havent tested it but I think it should work. Let me know how it goes.
List entire structure from changeable source
Im trying to do some menu stuff where i want to list a node structure from a changeable source on a macro. Im building on the sitemap xslt, but have a bit of a problem changing the source from $currentpage to my macro's $source. $source is a content picker
[code]
your content picker only contains a node id, you'll have to use
ok, but changing that doesnt really list the substructure form the source, but from level1... Any ideas?
[code]
Change this line [code][/code]
to
[code][/code]
cheers,
doug.
Im totally lost :)
drobar, doing what you suggest returns nothing
[code]
[/code]
But if i do
[code]
[/code]
it returns the root level of my $source. But the goal is to get a nested list with subpages as well.
My complete xslt is below, if anyone can spot any errors :), thanks
[code]
[/code]
Feeling lost? No problem! Time for some theory and some code. (Please forgive me if I explain stuff you already understand, but if I don't give enough detail then just ask)
The first thing to do is define what you want to do. I think you're trying to create a nested UL/LI list for your website, starting at whatever node is selected (and passed in) with a Content Picker on your macro.
Starting with the sitemap.xslt template is a great way to go. But let's build this from the ground up ourselves so it is clear what is happening at every stage. That will also make it easier for you to modify it if my sample doesn't meet your needs exactly.
The first thing to do is start with a basic xslt file. Basically, everything outside the block. That code is standard and there isn't much to do there except add a variable to the macro parameter:
[code] [/code]
(Later on you might want a variable to specify how deep to go in the content tree but for now we'll just list EVERY node below the source node, no matter how many levels down the tree it is)
Remember that the Content Picker data type contains a node ID. You will have to convert that ID into a real node to loop through its children. This is done with the umbraco.library:GetXmlNodeById() function.
Once we have the node we can get any of the usual properties, such as its name, create date, etc. Let's prove that with this simple bit of code that will print out the node name for the selected source node:
[code][/code]
Now that we've got the source node, we want to list all its immediate children in a UL list. This is done by using an xsl:for-each loop and selecting the source's child nodes:
[code]
[/code]
But if one of these nodes also has children below it we would need to manually create the UL/LI structure in the xslt macro... and keep it up to date whenever there is a change to the site structure. That won't do.
Instead, we want to create what would be called a "function" in other languages to make as many embedded UL/LI lists as needed. In xslt, we simply create another template, give it a name, and then call that named template. Just like with functions in other languages, we can pass parameters in to the named xslt template.
The sitemap.xslt file used the name 'drawNodes' so we'll do the same. We want this "function" to take a starting node and create a UL/LI list. If any of the items has children below it we want to call the drawNodes template again with THAT node so that all its children get listed as well. We'll continue to call drawNodes until we've gone through all the nodes below the original $source node.
Let's see how that's done, but step-by-step.
First, we'll re-write our last xslt sample to use a named template and we'll call that template. The output will be the same but we'll have a framework in place to make further logic modifications:
[code]
[/code]
As I said, the output of this code sample and the one before it are the same. Which means it still only shows the children of the original source node.
Let's add some logic to call the drawNodes template as many times as necessary, for as many children, grandchildren, great-grandchildren, etc. your site has. All we need to do is check to see if the current node being displayed has any children. If it does, we call the drawNodes template again, and presto we have a nested UL/LI list of all the nodes:
[code]
[/code]
There you have it, a nested UL/LI list of all the nodes below the original $source node.
Of course, you can embellish this code to include href's instead of simply printing the node names:
[code]
And you could add various tests to limit the number of levels to display, as well as being sure not to display any node that has the umbracoNaviHide property set. You might also check that you only show pages that are either not protected or which are protected but are accessible by the currently logged in user.
When you add all of these additions you'll find that you are very close to the code in the sitemap.xslt file you started with. But now you understand why every line is there and what it is doing.
I hope this helps. Be sure to ask if anything is unclear.
cheers,
doug.
Doug, you're the man. This was so much more comprehensive than any post I've ever seen. You're an asset and an inspiration to us all.
Thanks Douglas.
I can't believe the lengths you went to make me understand this. Im really greatful.
This post should go somewhere into some documentation. It really opened my eyes much more to this xslt stuff, i find so hard to comprehend.
Thanks again. :d/
I just read this topic and it solved 2 or 3 problems for me too. Great post, Doug!
Yeah that post rocked everyone's world, especially those new to Umbraco and XSLT. Question for you, Doug-- what if I just wamted to specify, as you alluded to early in the thread, the depth of the structure in which to delve? I only want to display the first two tiers....
Thanks,
Garrett
You can change:
Into
Ron
You can also use the folowing:
Ron
Thanks for the reply. But this change makes everything disappear because I don't think @level has a value. How would the page (or routine) know what level it's on if I don't set it?
Regards,
Garrett
I you want to understand how @level works, take a look in "data/umbraco.config" thats the file where you are reading from.
However you can use my second option (I prefer that method)
I havent tested it but I think it should work.
Let me know how it goes.
Ron
That worked great for me-- thanks so much!
//Garrett
is working on a reply...