19

Resolved

Autoroute token is always empty: {Content.Fields.Article.MyTaxonomySection}

description

Repro steps:

1) Create a new content type with title/body/autoroute and MyTaxonomySection as a field
2) Set autoruote to {Content.Fields.Article.MyTaxonomySection}/{Content.Slug}
3) Create a new content item of this type and select a taxonomy field.
4) {Content.Fields.Article.MyTaxonomySection} token in the URL will always be empty.

comments

nxtjv wrote Jun 25, 2012 at 6:27 AM

Same issue when trying to use Taxonomy tokens in projector layouts :(

sebastienros wrote Jun 25, 2012 at 5:37 PM

Taxonomy needs more code to be handled with tokens. If you need it now you could try to copy/paste the code from Orchard.Fields regarding tokens, and do the same in taxonomy. Or just wait for me to do it.

nxtjv wrote Jun 25, 2012 at 8:56 PM

i really have no idea what I'm doing, but I created a class called TaxonomyTokens.cs and the following is not working (I didn't think it would, but maybe someone can explain what's missing if it's not too far off)

<code>
using System;
using Orchard.ContentManagement;
using Orchard.Events;
using Contrib.Taxonomies.Fields;
using Orchard.Localization;

namespace Contrib.Taxonomies.Tokens
{
public interface ITokenProvider : IEventHandler
{
    void Describe(dynamic context);
    void Evaluate(dynamic context);
}

public class TaxonomyTokens : ITokenProvider
{
    private readonly IContentManager _contentManager;

    public TaxonomyTokens(IContentManager contentManager)
    {
        _contentManager = contentManager;
    }

    public Localizer T { get; set; }

    public void Describe(dynamic context)
    {
        context.For("TaxonomyField", T("Taxonomy Field"), T("Tokens for Taxonomy Fields"))
           .Token("Terms", T("Terms"), T("The text of the Terms."))
           ;
    }
    public void Evaluate(dynamic context)
    {
        context.For<TaxonomyField>("TaxonomyField")

           .Token("Terms", (Func<TaxonomyField, object>)(field => field.Terms))
           .Chain("Terms", "Terms", (Func<TaxonomyField, object>)(field => field.Terms))
           ;
    }
}
}
</code>

Jetski5822 wrote Dec 6, 2012 at 6:02 PM

Hey Seb did you ever do the work on this?

mrtn_t wrote Jan 18, 2013 at 11:17 AM

Best regards!

I tried to create Taxonomy token by my self, but I got stucked at some point.

I did as follows:
  1. I installed the latest Taxonomies module, ver 1.4
  2. I created new taxonomy named "Skupina" (means "group")
  3. Added new field to Page content type, also named "Skupina"
  4. Created new token. Code follows:
using System;
using System.Linq;
using Orchard;
using Orchard.ContentManagement;
using Orchard.Environment.Extensions;
using Orchard.Localization;

using Orchard.Tokens;

namespace Contrib.Taxonomies.Providers
{
    /// <summary>
    /// Adds tokens:
    /// {Content.Taxonomies.*}
    /// 
    /// tried with route: {Content.Taxonomies.Skupina}/{Content.Slug} this hit the code
    /// 
    /// </summary>
    [OrchardFeature("Contrib.Taxonomies")]
    public class TaxonomyToken : ITokenProvider
    {
        public TaxonomyToken(IWorkContextAccessor workContextAccessor)
        {
            T = NullLocalizer.Instance;
        }

        public Localizer T { get; set; }

        public void Describe(DescribeContext context)
        {
            context.For("Content", T("Content"), T("Content"))
                   .Token("Taxonomies.*", T("Taxonomies.<name>"), T("Name of taxonomy"));

        }

        public void Evaluate(EvaluateContext context)
        {
            context.For<IContent>("Content")
                   .Token(
                       token => token.StartsWith("Taxonomies.", StringComparison.OrdinalIgnoreCase)
                                    ? token.Substring("Taxonomies.".Length)
                                    : null,
                       tryGetToken);
        }

        private string tryGetToken(string token, IContent content)
        {
            // this line is hit whenever token {Content.Taxonomies.*} is present
            try
            {
                var term = content.As<Models.TermsPart>();
                if (term == null) return string.Empty;
                var t = term.Terms.FirstOrDefault(x => x.Field == token);
                if (t == null) return string.Empty;

                // here I get 
                //?t
                //{Contrib.Taxonomies.Models.TermContentItem}
                //    Field: "Skupina"
                //    Id: 0
                //    TermRecord: {Contrib.Taxonomies.Models.TermPartRecord}
                //    TermsPartRecord: {Contrib.Taxonomies.Models.TermsPartRecord}
                //?t.TermRecord
                //{Contrib.Taxonomies.Models.TermPartRecord}
                //    base {Orchard.ContentManagement.Records.ContentPartRecord}: {Contrib.Taxonomies.Models.TermPartRecord}
                //    Count: 2
                //    Path: "/"
                //    Selectable: true
                //    TaxonomyId: 77
                //    Weight: 0

                return "abc";
            }
            catch (Exception e)
            {
                return string.Empty;
            }
        }

    }
}
  1. I added new Autoroute with "{Content.Taxonomies.Skupina}/{Content.Slug}" as pattern
Point is that I get "Contrib.Taxonomies.Models.TermContentItem" in method tryGetToken, but i can't find a way to get right "Contrib.Taxonomies.Models.TermPart" to extract any of it's properties.

I left here quite a few hours ans I'm stucked.

PLEASE help me if you can. If my code is of any use, I promise I'll give it back to comunity :)

Best regards, martin

Timbioz wrote Feb 19, 2013 at 5:31 AM

Please!!! We need working Tokens in this awesome module...

mrtn_t wrote Feb 19, 2013 at 8:33 AM

I managed to solve this, but in very stupid way. During storing of content, model is not nessesary populated with values. But one can extract values directly from http request

Try this:

Step 1:
Create new class "TaxonomyToken" in "Contrib.Taxonomies.Providers"
using System;
using Contrib.Taxonomies.Services;
using Orchard;
using Orchard.ContentManagement;
using Orchard.Environment.Extensions;
using Orchard.Localization;

using Orchard.Tokens;

namespace Contrib.Taxonomies.Providers
{
    /// <summary>
    /// Adds tokens:
    /// {Content.Taxonomies.*}
    /// 
    /// tried with route: {Content.Taxonomies.Skupina}/{Content.Slug} this hit the code
    /// 
    /// </summary>
    [OrchardFeature("Contrib.Taxonomies")]
    public class TaxonomyToken : ITokenProvider
    {
        private readonly IWorkContextAccessor _workContextAccessor;
        private readonly ITaxonomyService _taxonomyService;

        public TaxonomyToken(
            IWorkContextAccessor workContextAccessor,
            ITaxonomyService taxonomyService)
        {
            _workContextAccessor = workContextAccessor;
            ; _taxonomyService = taxonomyService;
            T = NullLocalizer.Instance;
        }

        public Localizer T { get; set; }

        public void Describe(DescribeContext context)
        {
            context.For("Content", T("Content"), T("Content"))
                   .Token("Taxonomies.*", T("Taxonomies.<name>"), T("Name of taxonomy"));

        }

        public void Evaluate(EvaluateContext context)
        {
            context.For<IContent>("Content")
                   .Token(
                       token => token.StartsWith("Taxonomies.", StringComparison.OrdinalIgnoreCase)
                                    ? token.Substring("Taxonomies.".Length)
                                    : null,
                       TryGetToken);
        }

        private string TryGetToken(string token, IContent content)
        {
            // this line is hit whenever token {Content.Taxonomies.*} is present
            try
            {
                /*
                 * this will not work, because content is not stored yet
                 * We read values directly from content of request
                 */
                var fieldName = String.Format("Page.{0}.SingleTermId", token);
                var request = _workContextAccessor.GetContext().HttpContext.Request;
                var param = request[fieldName];
                var id = 0;
                if (!int.TryParse(param, out id)) return string.Empty;
                var term = _taxonomyService.GetTerm(id);
                if (term == null) return string.Empty;
                var taxonomy = _taxonomyService.GetTaxonomy(term.TaxonomyId);
                if (taxonomy == null) return string.Empty;
                var slug = term.Slug;
                if (!String.IsNullOrEmpty(taxonomy.Slug) && slug.Contains(taxonomy.Slug))
                    slug = slug.Replace(taxonomy.Slug + "/", "");
                return slug;

            }
            catch (Exception e)
            {
                return string.Empty;
            }
        }
    }
}
Step 2:
Prepare your taxonomy. Name it properly (in my case "Skupina", wich means group in slovenan language, but you can use any name). Enter some terms.
Add that taxonomy field to your content type. It is very important that you mark it as Single Term (check "Allow only one term to be selected")

Step 3:
Fix your autoroute pattern.
Mine is "{Content.Taxonomies.__Skupina__}/{Content.Slug}"
Please notice that Skupina should actualy be name of your taxonomy

This should work.
It's dirty workaround, it's against many concepts ("Thou Shalt Not change the code from foreign modules").
But it works for me.

Feel free to contact me in case of any troubles.

Best regards, Martin

mrtn_t wrote Feb 19, 2013 at 8:38 AM

Small fix:
In step 3 I wrote:
"{Content.Taxonomies.__Skupina__}/{Content.Slug}"

It is ofcourse "{Content.Taxonomies.Skupina}/{Content.Slug}", without underscores. I put underscores because I tought it will mean BOLD. Obviously that does not work inside quotes :)

sebastienros wrote Feb 19, 2013 at 8:00 PM

Fixed in changeset 2bd61b0ec84a

gbas wrote Mar 20, 2013 at 12:25 PM

I have downloaded the latest source code but still I have the same issue. {Content.Fields.Article.MyTaxonomySection} still returns nothing.I have also implemented the TaxonomyToken class as mrtn_t wrote but still no luck.
I ve tried to debugg and maybe the error is at this line as it returns null

var param = request[fieldName];

arbitrix wrote Apr 8, 2013 at 9:19 PM

Taxonomy tokens still do not work in 6895 (155b3eceb6be).

Field {Content.Fields.BlogPost.Category} shows up in the autoroute pattern dropdown but is always underlined red.

The resulting autoroute show an empty string being inserted instead of the token.

BrentCarter wrote Apr 30, 2013 at 5:24 AM

First of all, thanks so much to Martin for posting the solution. I've been struggling with this for a long time. I had my taxonomy field defined on a custom content type and to get it to work, I had to replace:

var fieldName = String.Format("Page.{0}.SingleTermId", token);

with

var fieldName = String.Format("{0}.{1}.SingleTermId", content.ContentItem.ContentType, token);

I'm guessing you'd put the taxonomy on the Page content type... Also, I was a little confused when you said "Please notice that Skupina should actualy be name of your taxonomy" and was putting in the name of the taxonomy but really had to put the field name of the taxonomy field as it was added on the current content type (this was just my lack of understanding of tokens but maybe will help someone else). Anyway, thanks again!

julianusflavius wrote Jun 18, 2013 at 8:50 AM

In order to work for me i had to add Params after request.

var param = request.Params["fieldName"];

sheltonial wrote Jul 9, 2013 at 2:36 AM

This has not been resolved in changeset 2bd61b0ec84a.

Issue has also not been resolved within:
  • Orchard Taxonomies Module commit e688a1b34b01 Mar 10, 2012 (1.x branch)
  • Orchard Taxonomies Module commit 2bedcd7ba4f3 Feb 20, 2013 (default branch)
  • Orchard commit 71d81e849620 Jul 9, 2013 (1.x branch)
  • Orchard commit f65d032a9b0c Apr 30, 2013 (default branch)
My tests were conducted with the following steps:
  • Create taxonomy named "test"
  • Attached taxonomy field "test" to content type "Page" using field name "testfield"
  • Under "testfield" checked "Allow only one term to be selected"
  • Under Autoroute (within "Page" content type) checked "automatically generate when editing content"
  • tried all of the below tokens within the autoroute pattern in between publishing a page with a taxonomy selected:
    • {Content.Fields.Page.testfield}/{Content.Slug}
    • {Content.Fields.Page.testfield.Terms}/{Content.Slug}
    • {Content.Fields.Page.testfield.Terms:0}/{Content.Slug}
    • {Content.Fields.Page.test}/{Content.Slug}
    • {Content.Fields.Page.test.Terms}/{Content.Slug}
    • {Content.Fields.Page.test.Terms:0}/{Content.Slug}
I manged to get taxonomy tokens working in the current unreleased version of 1.7 (I assume it would work with 1.6 too) by utilising the following posts within this thread:
  • mrtn_t wrote Feb 19 at 7:33 AM
  • BrentCarter wrote Apr 30 at 4:24 AM
Just to clarify, when you add the taxonomy token make sure you use the field name of the taxonomy, not the taxonomy name itself (unless the taxonomy name and field name are named the same, then you're ok).

Taxonomies is such a powerful feature within Orchard, not having access to it's values through tokens is a huge disadvantage, and for me (i'm sure many others also) renders this module useless.

I propose for this issue to be reopened, and if not why? Perhaps the Orchard team has something planned for the future making this issue redundant? Would be useful to know if this was the case.

Cheers,

Andrew