Slug for Taxonomy Term Token


The ability to slugify a taxonomy term token for use primarily within an autoroute pattern. I have implemented the following solution in my code: http://sheltonial.blogspot.com.au/2013/10/orchard-cms-taxonomy-term-autoroute.html


Codinlab wrote Nov 7, 2013 at 1:27 PM

Thank for your solution which was helpfull for me.

You don't need to call "Slugify" function, because TermPart already has a "Slug" property.

Did push a patch for future releases ?

sheltonial wrote Nov 10, 2013 at 11:08 PM

Hi Codinlab, thanks for the tip, I have not pushed a patch as the solution requires chaining and not 100%.

Since writing this I have discovered a better method which allows a full taxonomy term hierarchy path to be returning into a token in slug format. The code is provided here: http://sheltonial.blogspot.com.au/2013/11/orchard-cms-taxonomy-term-autoroute.html

Brentdc3 wrote Feb 5, 2014 at 8:55 PM

Hi Sheltonial - I extended your solution a bit so that it doesn't modify the core Orchard source.

I added the following class to my own custom module:
using System;
using System.Linq;
using Orchard.Taxonomies.Fields;
using Orchard.Localization;
using Orchard.Tokens;

namespace MyModule.Tokens
    public class TaxonomyTokens : ITokenProvider

        public TaxonomyTokens()
            T = NullLocalizer.Instance;

        public Localizer T { get; set; }

        public void Describe(DescribeContext context)
            // Usage:
            // Content.Fields.Article.Categories.Terms -> 'Science, Sports, Arts'
            // Content.Fields.Article.Categories.Terms:0 -> 'Science'

            // When used with an indexer, it can be chained with Content tokens
            // Content.Fields.Article.Categories.Terms:0.DisplayUrl -> http://...

                        T("Taxonomy Field"), 
                        T("Tokens for Taxonomy Fields"))
                        T("The first term. Can be chained with Content tokens."))

        public void Evaluate(EvaluateContext context)
                   .Chain("FirstTerm", "Content", t => t.Terms.ElementAt(0))
It supports chaining so you can write your Autoroute pattern as: {Content.Fields.MyArticle.MyTerm.FirstTerm.Path}/{Content.Slug} and get a route of /taxonomy/term/subterm/slug as expected.

Looking at the (Orchard Source, the Token call with the StartsWith("Terms:") might be the source of the problem.

The pattern {Content.Fields.MyArticle.MyTerm:0.Path} doesn't work because the StartsWith("Terms:") condition succeeds and ensure that the Chain("Terms:0"...) call is never called.

I'm guessing that the StartsWith("Terms:") condition needs an additional check that nothing is chained after it?

PS this is on Orchard 1.7.2.

Codinlab wrote Feb 7, 2014 at 4:05 PM

Based on Brentdc3 comment, I pushed a fix

By replacing :
   token => token.StartsWith("Terms:", StringComparison.OrdinalIgnoreCase) ? token.Substring("Terms:".Length) : null,
   (token, t) => {
       var index = Convert.ToInt32(token);
       return index + 1 > t.Terms.Count() ? null : t.Terms.ElementAt(index).Name;
with :
   token => {
       var match = Regex.Match(token, "^Terms:(?<index>[0-9]+)$", RegexOptions.IgnoreCase);
       return match.Success ? match.Groups["index"].Value: null;
   (token, t) =>
       var index = Convert.ToInt32(token);
       return index + 1 > t.Terms.Count() ? null : t.Terms.ElementAt(index).Name;
condition succeeds only when it is not chained.

sebastienros wrote Mar 5, 2014 at 5:16 PM

Fixed in changeset 61fd42fb41273bb39d07656cf3e49bac7e67e4ec