Working With Taxonomies

Taxonomies are the workhorse feature for organizing the content on your site and finding the items you want to display in any situation.

There's a lot of options in what you can do with taxonomies, which are the direct result of all the different needs we've encountered in helping designers build many diverse sites. This makes writing WebvantaScript code to work with taxonomies one of the more complex parts of building sites with Webvanta. But don't despair, we're here to help! If you find your head swimming as you read this (and we don't blame you, especially until you've worked with these features for a while), just submit a helpdesk ticket. Let us know what you're trying to accomplish, and we'll point you in the right direction.

Taxonomy Terminology

Each member of a taxonomy is called a term. Taxonomies can be either flat — a single-level collection of terms, or hierarchical. In a hierarchical taxonomy, you can nest terms to any depth, like categories and subcategories.

The name of a term should be unique within a taxonomy; it can cause problems if you have two different parent terms, each of which has a child term (i.e., a subcategory) of the same name. Each taxonomy creates an entirely independent namespace, however, so you there's no problem with using the same term name in different taxonomies.

Note: If you've been using Webvanta for some time, you may be accustomed to Categories, Tags, and Taxonomies having three separate interfaces. They've now been merged into one system. It's the Grand Unification Theory of WebvantaScript. Categories are just a hierarchical taxonomy named "categories", and tags are simply a flat taxonomy named "tags". The legacy syntax, such as category="Cats", is still available, but you'll have more flexibility using the taxonomy syntax, which in this case would be taxonomy="Categories:Cats".

Setting the Context

When finding items with WebvantaScript, you first set the context that determines what items you want to work with. Then you can easily access the items.

If you're looking for all the items that have been assigned to a given taxonomy term, this is how you'd set the context:

<w:taxonomy name="taxonomy_name:term_name">...</w:taxonomy>

Then you can find all the items with that taxonomy term by using taxonomy = "current" as an attribute in the item iterator. For example, suppose you have a taxonomy named "Animals" and one of the terms is "Cats". The following code will list all the cats:

<w:taxonomy name="Animals:Cats">
<h1><w:name /></h1>      <!-- the name of the taxonomy term -->
   <w:kb:items:each taxonomy="current">
      <p><w:name /></p>  <!-- the name of an item  -->
   <w:kb:items:each>
</w:taxonomy>

Note: you can also identify terms by their ID, anywhere you can provide a name. This makes the code less readable, but it is more robust because the code will keep working even if the name of the taxonomy term is edited. The ID is not currently displayed directly in the admin interface, but you can see it in the URL if you edit a taxonomy term.

In addition to the name of the taxonomy term, you can access other information about it. Here's all the values that are available:

nameName of the taxonomy term
descriptionDescription of the taxonomy term
idThe ID number of the term
countThe number of items that have been assigned to the term
root_nameName of the highest-level parent term
root_idID number of the highest-level parent term
pathURL for a page with the term ID as a parameter
positionPosition of this term within the terms for a given parent
parent_nameName of the term that is the immediate parent of the current term
parent_idID of the term that is the immediate parent of the current term
permalinkID plus first five words of the term's name

If you don't need to access the taxonomy term name or other attributes of the term itself, you can use this more compact form:

<w:kb:items:each taxonomy="Animals:Cats">
  <p><w:name /></p>
<w:kb:items:each>

Testing for Multiple Taxonomies

You can also test for more than one taxonomy term. Suppose you have a taxonomy "Age" that has terms like "Baby", "Youth", and "Adult". You can find all the baby cats as follows:

<w:kb:items:each taxonomy="(Animals:Cats&&Age:Baby)">
  <p><w:name /></p>
<w:kb:items:each>

Note that the separator to "AND" together taxonomy terms is &&. You can also "OR" terms together using a double pipe (||), and you must group using parenthesis. So the following example will find all the baby cats and baby dogs:

<w:kb:items:each taxonomy="((Animals:Cats||Animals:Dogs)&&(Age:Baby))">
  <p><w:name /></p>
<w:kb:items:each>

You can use the keyword "current" in place of one of the taxonomy terms. For example, the following code lists all the baby animals of whatever kind is set by the context (as described in the following section):

<w:kb:items:each taxonomy="(current&&Age:Baby)">
  <p><w:name /></p>
<w:kb:items:each>

Note that compound taxonomy conditions should always be surrounded by parentheses.

Getting the Taxonomy from the Context

The context can be set in two ways:

  • On a page of type "Category" or "List", the context can come from the URL.
  • The context can come from an outer loop that is iterating through all the taxonomies, or some subset of them.

Once the taxonomy has been set by the context, you can use the keyword "current" to set the taxonomy name from the context:

<w:taxonomy name="current">...</w:taxonomy>

You can also pass a taxonomy term to a page of any type by setting it as a URL parameter, as follows:

www.example.com/mypage?wtx=taxonomy_name:term_name

The key here is to use the parameter name "wtx", and then you can access the taxonomy using the keyword "auto":

<w:taxonomy name="auto">

Looping Through Taxonomy Items

You can repeat a block of code for every top-level term in a taxonomy using the basic taxonomy iterator:

<w:taxonomy:each name='taxonomy_name'>
  ... 
</w:taxonomy:each>

For example, this code lists all the major type of animals (the top level terms in the Animals taxonomy):

<w:taxonomy:each name="Animals">
  <p><w:name /></p>
</w:taxonomy:each>

If you don't specify a "relative" attribute for the taxonomy:each iterator, it defaults to "roots", which means that it will loop through all the top-level terms in the taxonomy.

There are many other options for the "relative" attribute, as shown below:

<w:taxonomy:each name='taxonomy_name' relative="roots|parents|reversed-parents|children|siblings|item|related-items"

Here's the rundown on what each of these "relative" options do:

parentsStarts from the current term, and provides each of the parent terms (moving up the tree)
reversed-parentsStarts at the most distant ancestor (top level parent term) and provides each of the child terms down to the current term's immediate parent. Just what you need when you're creating breadcrumbs.
childrenIterate over all of the immediate children of the current term. (This is the same as subcategories.)
siblingsIterate over all the siblings (other terms at the same level, with the same parent) as the current term.
itemProvides access to a list of terms in the current taxonomy that have been assigned to a particular database item. Must use in an item context and a taxonomy context.
in.itemAs above, but for a related item (as set up by for_each)
related-itemsReturns terms for all related items of the current item (must be used in an item context).

You can limit the number of taxonomy terms the iterator will go through:

<w:taxonomy:each name='taxonomy_name' limit='n'>

And you can exclude certain terms:

<w:taxonomy:each name='taxonomy_name' exclude='comma separated list of names'>

Displaying the Taxonomy Tree

The iterators described above show only a single level of terms at a time. You can show nested terms by using iterators within iterators.

You can also show a complete tree of all the terms in a taxonomy:

<w:taxonomy:tree name='taxonomy_name' type='html'/>

You can also get the tree in JSON format, which is useful for feeding JavaScript tree widgets:

<w:taxonomy:tree name='taxonomy_name' type='json' />

Conditionals

Note: As with all conditions in WebvantaScript, there is an "unless" version available for every "if" statement. There is no "else", so to achieve if-then-else structures, use an if statement followed by an unless statement with the same condition.

<w:taxonomy:if_root>

Test if current term is a root term or child term

<w:taxonomy:if_term>

Tests if there is any taxonomy term context set.

<w:taxonomy:if_term name="term_name">

Tests if the current taxonomy term context matches the specified term name. Note: you can also provide the term ID instead of the name.

<w:taxonomy:if_current name='term_name'>

Tests if the current term matches the specified name.

<w:taxonomy:if_items type="type_name">

Test if the current term has any items assigned to it of the specified type. If the type is not specified, checks for any type.

<w:taxonomy:if_items type="type_name, type_name, type_name">

Test if the current term has any items assigned to it with any of the specified types.

<w:taxonomy:if_items type="-type_name, -type_name">

Test if the current term has any items assigned to it that are not of any of the specified types.

<w:taxonomy:if_items type="type_name" count=n>

Test if the current term has more than n items assigned to it of the specified type.

<w:taxonomy:if_subterms>

Test to see if current term has any children terms associated with it.

<w:taxonomy:if_subterms count=n>

Test to see if current term has more than n children terms associated with it.

<w:taxonomy:each:if_first> 

Test if the current term for taxonomy context is the first one in the iteration.

<w:taxonomy:each:if_last> 

Test if the current term for taxonomy context is the last one in the iteration.

If you are testing for items that have more than one taxonomy term, use the item-centric "if_items" instead:

<w:kb:item:if_items taxonomy="Animals:Cats&&Age:Baby">