2

I was trying to display user information inside a Scriban template (SXA variant).

I managed to write a context function that gives me the full name of the user (or any profile property I put in there) - but as I don't want to create a function for every property I might need. I'd rather be able to return the User (or UserProfile) object and choose the properties that I want to display inside my Scriban template. But that didn't work.

To create the extension, I used this information: https://ggullentops.blogspot.com/2019/11/custom-sxa-scriban-extensions.html

The code now is this:

public class GetSubscribers : IGenerateScribanContextProcessor
{
    private delegate IEnumerable<string> Subscribers(Item currentItem);

    public void Process(GenerateScribanContextPipelineArgs args)
    {
        var subscribers = new Subscribers(GetSubscriberList);
        args.GlobalScriptObject.Import("sc_subscribers", subscribers);
    }

    public IEnumerable<string> GetSubscriberList(Item currentItem)
    {
        var users = currentItem.Fields["Subscribers"].Value.Split('|');
        const string domainName = "extranet";
        var userList = new List<User>();
        foreach (var userName in users)
        {
            if (!string.IsNullOrEmpty(userName) && User.Exists(domainName + @"\" + userName))
            {
                userList.Add(User.FromName(domainName + @"\" + userName, false));
            }
        }

        return userList.Select(u => u.Profile.FullName);
    }
}

If I return objects instead of the strings, I get errors...

Is there a way to achieve what I'm trying here?

  • 1
    Yes, it is possible. I will write a longer answer later on:) – Dawid Rutkowski Mar 3 at 15:54
2

First of all, you don't need to have a delegate there. It is useful when your function can accept optional parameters. You won't do it in Func and that is why we are using delegate.

enter image description here

Otherwise, you can do something like that and skip delegate:

args.GlobalScriptObject.Import("sc_link", new Func<Item, string>((item) =>
{
    // something
    return linkProvider.GetItemUrl(item, urlOptions);
}));

Now... If you would like to return an object (instead of string) it would require more work. By default, Scriban doesn't allow to iterate over custom object properties as it might be dangerous. You need to implement your own object accessor.

We have such and that is why you can use an item as an object which is returned by Scriban function. Such object accessor defines what is possible to be accessed inside of that object and what is not. For example, in our item accessor (investigate ItemAccessor for more details) we have a logic which is checking if a property you want to access on an object is a field. So that if you will type {{ i_item.title }} you will get the value of a Title field.

The steps to do that in SXA (that is not easy):

  • you need to create your own TemplateContext which would inherit from SitecoreTemplateContext and override GetMemberAccessorImpl method wherein case of your object type will return your custom accessor
  • override our InitializeScribanContext processor (first one in the GenerateScribanContext pipeline) and instead of SitecoreTemplateContext create your own template context
  • pray that it will work - you would be probably the first one who will do it
| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.