Globalizing orchard layout elements and then testing them

So, I created a hubspot blog post layout element in orchard for a recent project (which I intend to write a post about later). I was then asked to make it personalised by country, so users would see different blog posts based on which country they were in. This is how I did it…

The finished article

fe-hubspot-blog-posts

Not much to look at really, but the basic idea is that a back-office user of the CMS can drag and drop hubspot blog posts on to a page canvas, and then configure them. So, they can set the ID of the blog post, how long to cache it for, and what theme the post will have (detailed or summary).

The solution

I wanted to keep things simple, not too time-consuming, so I opted for just providing a text area in the back-office, so that editors could put a country code and post id on each new line. When the orchard driver retrieved that info, it would process it, try to match one of the entries against the current country and display that post. If there were no matches, or something went wrong, it would just display a default post, which would be chosen by the editor. This is what the back-office form looks like…

fe-hubspot-blog-post-back-office

So, as you can see, its quite simple, but does allow editors to add any amount of flexibility in that they want.

Processing the data

I created a bespoke hubspot service in orchard, that is used to actually connect with hubspot and retrieve/cache blog posts. So I decided that to actually determine which post to look up, I’d put that functionality into the driver. I think that’s a fairly logical separation of concerns. So, here’s some code stuff…

protected override void OnDisplaying(HubspotBlogPostElement element, ElementDisplayContext context)
{
  var postId = getPostId(element); // 1
  try
  {
    context.ElementShape.BlogPost = _hubspotService.GetPostById(_orchardServices.WorkContext.CurrentSite.As<HubspotSettingsPart>(), postId, element.CacheMinutes); // 2
  }
  catch (Exception ex)
  {
    context.ElementShape.ErrorMessage = ex.Message;
  }
}
  1. try to get the post id by passing the element (which includes all the globalization info and defaults)
  2. get the post using the hubspot service, and populate the BlogPost property of the ElementShape using that data

Here’s how to actually get the correct post id based on country. One point here, I did look at the Localisation module in orchard, but the docs on applying this to a layout element were fairly brief. It was mainly talking about alternate translations of content items.

string getPostId(HubspotBlogPostElement element)
{
  if (element.PostAlternativesByLocale == null) // 1
  {
    return element.PostId;
  }
  string[] lines = element.PostAlternativesByLocale.Split(new string[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);  // 2
  Dictionary<string, string> postIdsByLocale = new Dictionary<string, string>();
  try  // 3
  {
    postIdsByLocale = lines.ToDictionary(l => {
      if (l.Split(',').Length == 2)
      {
        return l.Split(',')[0].Trim();
      }
      return string.Empty;                    
    }, l => {
      if (l.Split(',').Length == 2)
      {
        return l.Split(',')[1].Trim();
      }
      return string.Empty;
    });
  }
  catch (Exception ex)  // 4
  {
    return element.PostId;
  }

  CultureInfo culture = CultureInfo.CurrentCulture;  // 5
  if (postIdsByLocale.ContainsKey(culture.Name))
  {
    return postIdsByLocale[culture.Name];
  }
  return element.PostId;
}
  1. if there aren’t any alternatives, just return the default post id
  2. split the string up by new line (its a text area on the form)
  3. try to create a Dictionary by splitting each line of the string by ‘,’
  4. if that fails, return the default post id
  5. check the current culture and try to look up that culture in the dictionary
  6. if it exists, return the relevant post id, if not, return the default.

Testing the alternatives

A nice little way of testing out alternatives without mucking around in code…

<!-- web.config -->
<system.web>
  <!-- ... -->
  <globalization uiCulture="en" culture="en-AU" />
</system.web>

Whatever culture is specified here will be used by the application. The country codes are all well documented (I used this list).

That’s it

A fairly simple way to add personalisation to orchard layout elements. Any comments welcome.

Leave a Reply