Adding custom field as option in a slug

Topics: Writing modules
Aug 4, 2013 at 1:37 PM
I'm trying to add a field as an option when creating a slug in a custom module, but I can't seem to get any content to be emitted from it. Seeing other posts in the forum, I've created my own token provider. I can see my token in the list of tokens in the Admin UI, but nothing is being added to the autoroute... not sure what I've done wrong here... ideas?
namespace Contrib.Podcasts.Providers {
  public class PodcastTokens : ITokenProvider{
    public PodcastTokens() {
      T = NullLocalizer.Instance;
    }

    public Localizer T { get; set; }

    public void Describe(DescribeContext context) {
      context.For("PodcastEpisode", T("Podcast Episode Items"), T("Tokens for podcast text strings"))
        .Token("EpisodeNumber",T("Episode Number"),T("Includes the episode number."));
    }

    public void Evaluate(EvaluateContext context) {
      context.For<PodcastEpisodePart>("PodcastEpisode")
        .Token("EpisodeNumber", content => content.EpisodeNumber);
    }
  }
}
Coordinator
Aug 5, 2013 at 1:44 AM
Put a breakpoint in there and find out. The token might be getting evaluated before your part has data.
Developer
Aug 5, 2013 at 6:14 AM
How does your route look like? I may be wrong, but I don't think the Contents token provider automatically chains into custom parts.
You may need to extend your token provider as follows:
    public void Describe(DescribeContext context) {
      context.For("Content", T("Content Items"), T("Content Items"))
         .Token("PodcastEpisode", T("PodcastEpisode"), T("Provides access to the PodcastEpisode part."), "PodcastEpisode");
      context.For("PodcastEpisode", T("Podcast Episode Items"), T("Tokens for podcast text strings"))
        .Token("EpisodeNumber",T("Episode Number"),T("Includes the episode number."));
    }

    public void Evaluate(EvaluateContext context) {
      context.For<IContent>("Content")
        .Token("PodcastEpisode", content => content.As<PodcastEpisode>())
        .Chain("PodcastEpisode", "PodcastEpisode", content => content.As<PodcastEpisode>());
      context.For<PodcastEpisodePart>("PodcastEpisode")
        .Token("EpisodeNumber", content => content.EpisodeNumber);
    }
Aug 5, 2013 at 11:43 AM
Edited Aug 5, 2013 at 12:41 PM
BertrandLeRoy - I did & I can see in the Evaluate method it is passing in a reference, but I can't see where it is extracting the value from my custom part for inclusion in the slug.

sfmskywalker - I tweaked the two methods to look like what you posted... now I see the PodcastEpisode.EpisodeNumber showing up in the autoroute token selector. However it isn't rendering anything. Here's the route: {Content.Container.Path}/Episodes/episode-{PodcastEpisode.EpisodeNumber}-{Content.Slug} ... that was generated from the admin UI for the autoroute part. Everything is rendering except the episode number (all i see is /episode--{title} where title is correctly replaced).

The only difference I did in my code is the two "content.As<PodcastEpisode>" lines you have in the code above wouldn't work because I don't have a class named PodcastEpisode. I have PodcastEpisodeRecord, PodcastEpisodePart & PodcastEpisodeViewModel. Looking at other token files in other modules, I thought it was the part that should be used here so I used that (see below).

Ideas?
public void Describe(DescribeContext context) {
  context.For("Content", T("Content Items"), T("Content Items"))
    .Token("PodcastEpisode", T("PodcastEpisode"), T("Provides access to the PodcastEpisode part."), "PodcastEpisode");
  context.For("PodcastEpisode", T("Podcast Episode Items"), T("Tokens for podcast text strings"))
    .Token("EpisodeNumber", T("Episode Number"), T("Includes the episode number."));
}

public void Evaluate(EvaluateContext context) {
  context.For<IContent>("Content")
    .Token("PodcastEpisode", content => content.As<PodcastEpisodePart>())
    .Chain("PodcastEpisode", "PodcastEpisode", content => content.As<PodcastEpisodePart>());
  context.For<PodcastEpisodePart>("PodcastEpisode")
    .Token("EpisodeNumber", content => content.EpisodeNumber);
}
BTW, the code at the project (https://orchardpodcast.codeplex.com/) is current. The Token class is in the /Providers folder. Note this is still a work in progress. To test: activate the Podcasts module, create a podcast, manually create a new route on the PodcastEpisode content type using the episode number and set that to default, then create a new episode to see the results.