Skip to main content

Since Umbraco v7 was released, a number of great packages have been released by the community. Some of them are so well built and useful that you end up using them on every Umbraco project you start. Nested Content is one of those packages (for me at least).

While Nested Content is most commonly used to create repeatable content on a page, it can be used as any other data type in Umbraco. Recently I had a scenario where it turned out to be quite useful to store properties for website members as well.

So the website in question has a section that is only accessible to logged-in users. There users can view event information and leave a message for the event organiser (who will be an editor with access to the CMS).
The section was setup using the normal Umbraco membership functionality where the pages in that section are restricted using public access rules.

It's a relatively small website with about 30-40 members and each member would only post one message, or maybe a few messages at most.
When someone posts a new message, an email notification will be sent out to the event organiser, but I also wanted to make those messages visible in the CMS. And since the number of messages is so low I opted not to store them in a custom database table, but use a custom property on the member type.
Note that I wouldn't necessarily recommend the approach described in this article if you were dealing with a lot of members or a lot of messages, since that might bring up performance issues.

To create the Nested Content data type, I first created a simple document type called Guest Message. It contains the following properties:

  • Date - a label field
  • Message - a text area field

Then the Nested Content data type uses this document type to create the items stored in the list.
Once the data type had been created I added it as a new property to the relevant member type:

Added custom Nested Content property to the member type
Added custom Nested Content property to the member type

With the member type and section all setup, it's time to add the code to save a new message. This is done using a simple SurfaceController with an action that gets called when the logged-in member submits a new message:

using Newtonsoft.Json;
using Umbraco.Web.Mvc;

[ValidateAntiForgeryToken]
public ActionResult SubmitMessage(MessageViewModel model)
{
    if (ModelState.IsValid)
    {
        var profile = Members.GetCurrentMemberProfileModel();

        // get member property
        var messageProperty = profile.MemberProperties.FirstOrDefault(x => x.Alias == "messages");

        // deserialise JSON into list
        List<GuestMessage> messages = 
            JsonConvert.DeserializeObject<List<GuestMessage>>(messageProperty.Value);

        if (messages == null)
        {
            // member hasn't got any messages yet, create an empty list
            messages = new List<GuestMessage>();
        }

        // create new message
        var message = new GuestMessage();
        message.Date = DateTime.Now.ToString("dd/MM/yyyy HH:mm:ss");
        message.Message = model.Message;

        // append it to the list
        messages.Add(message);

        // serialise the list back to a JSON string
        messageProperty.Value = JsonConvert.SerializeObject(messages);

        var result = Members.UpdateMemberProfile(profile);

        if (result.Success)
        {
            // send out email notification

            return RedirectToCurrentUmbracoPage();
        }
        else
        {
            // failed to update member, log the error
        }
    }

    return CurrentUmbracoPage();
}

As you can see it gets the profile model from the current member, it then reads the current value of the custom Messages property, adds the newly submitted message to the back of the list, updates the property value and saves the updated member profile.

The value of a Nested Content property gets stored as a JSON array using a specific format:

[{
    "name" : "Some item name",
    "ncContentTypeAlias" : "yourDocTypeAlias",
    "propertyAlias1" : "some value 1",
    "propertyAlias2" : "some value 2"
},
{
    "name" : "Some item name",
    "ncContentTypeAlias" : "yourDocTypeAlias",
    "propertyAlias1" : "some value 1",
    "propertyAlias2" : "some value 2"
}]

You could hand-code the JSON as a string, but as you might have seen in the above snippet, I chose to create a custom class called GuestMessage and use it with Json.NET to deserialise and serialise the property value into a strongly-typed list for easier updating:

using Newtonsoft.Json;

public class GuestMessage
{
    [JsonProperty(PropertyName = "name")]
    public string Name
    {
        get { return string.Empty; }
    }

    [JsonProperty(PropertyName = "ncContentTypeAlias")]
    public string NcContentTypeAlias
    {
        get { return "GuestMessage"; }
    }

    [JsonProperty(PropertyName = "date")]
    public string Date { get; set; }

    [JsonProperty(PropertyName = "message")]
    public string Message { get; set; }
}

Since we're only interested in the date and message text, it's only those two properties which have setters. The other two properties required by Nested Content (name and ncContentTypeAlias) can be the same for each item, so a simple getter will do just fine.

And that's all you need to get Nested Content working with your members. The above example has been working great for me so far, and is also quite user-friendly to use for CMS editors:

A member with example messages in the CMS
A member with example messages in the CMS

When creating a text count package I explored the concept of wrapping data type controls to enhance their CMS appearance and functionality for an improved editor experience.

Read more

I noticed that a website hosted on Azure Web Apps was generating multiple Umbraco trace log files for the same day. I went to investigate what caused it, and also came up with a suggested change to resolve this.

Read more