Sitecore Custom User Properties

September 05, 2013

In a recent Sitecore build I had to store the pages that a user saved as a "Favorite" throughout the site. The site was an intranet so everyone had a user within Sitecore, which helped. The next question was where to store the information. I wanted it to be stored along with local user data but wasn't sure if I was going to need to extend the user object and create extra fields or if I could leverage the existing structure. I ended up looking through a lot of the user properties and scouring the cookbooks and eventually I found what I was looking for in the security api cookbook: Custom Properties.

You can access and set custom properties on a Sitecore user. It stores these custom properties in a NameValueCollection so you can get and set the values with a key. With that settled, I knew I'd only need to be storing the item ID's for each page. I ended up creating a wrapper class to manage the key for the favorites and to help manage the string value as a comma-delimited list.

Here's the code I used:

using System;using System.Collections.Generic;using System.Linq;using System.Text;using Sitecore.Data;using Sitecore.Data.Items;using Sitecore.Security.Accounts;namespace MyLibrary {	public static class UserExtensions {		public static readonly string custPropKey = "user-favorites";		public static readonly string custPropDelim = ",";		#region Add Favorite		public static void AddFavorite(this User u, ID pageID) {			AddFavorite(u, pageID.ToString());		}		public static void AddFavorite(this User u, Item page) {			AddFavorite(u, page.ID);		}		public static void AddFavorite(this User u, string pageID) {			IEnumerable<string> f = GetFavorites(u);			List<string> l = f.ToList();			//skip if already added			if (l.Contains(pageID))				return; 			l.Add(pageID);			SetFavorites(u, l);		}		#endregion Add Favorite		#region Remove Favorite		public static void RemoveFavorite(this User u, ID pageID) {			RemoveFavorite(u, pageID.ToString());		}		public static void RemoveFavorite(this User u, Item page) {			RemoveFavorite(u, page.ID);		}		public static void RemoveFavorite(this User u, string pageID) {			IEnumerable<string> f = GetFavorites(u);			List<string> l = f.ToList();			if (!l.Contains(pageID))				return; 			l.Remove(pageID);			SetFavorites(u, l);		}		#endregion Remove Favorite		#region Set Favorites		public static void SetFavorites(this User u, List<string> pageIDs) {			StringBuilder sb = new StringBuilder();			foreach (string s in pageIDs) {				if (sb.Length > 0)					sb.Append(custPropDelim);				sb.Append(s);			}			u.Profile.SetCustomProperty(custPropKey, sb.ToString());			u.Profile.Save();		}		#endregion Set Favorites		#region Get Favorites		public static IEnumerable<string> GetFavorites(this User u) {			string s = u.Profile.GetCustomProperty(custPropKey);			IEnumerable<string> split = s.Split(new string[] { custPropDelim }, StringSplitOptions.RemoveEmptyEntries).ToList();			return split;		}		public static IEnumerable<ID> GetFavoriteIDs(this User u) {			IEnumerable<string> s = GetFavorites(u);			return (s.Any()) ?				from string id in s				where ID.IsID(id)				select ID.Parse(id) 				: Enumerable.Empty<ID>();		}		public static IEnumerable<Item> GetFavoriteItems(this User u) {			IEnumerable<ID> s = GetFavoriteIDs(u);			List<Item> returnList = new List<Item>();			if (s.Any()) {				var items = from ID i in s							select Sitecore.Context.Database.Items[i];				foreach(Item i in items){					if(i != null)						returnList.Add(i);				}			}			return returnList;		}		#endregion Get Favorites		#region Is Favorite		public static bool IsFavorite(this User u, string pageID) {			IEnumerable<string> s = GetFavorites(u);			List<string> l = s.ToList();			return l.Contains(pageID);		}		public static bool IsFavorite(this User u, ID pageID) {			return IsFavorite(u, pageID.ToString());		}		public static bool IsFavorite(this User u, Item page) {			return IsFavorite(u, page.ID);		}		#endregion Is Favorite	}}

Now knowing this and looking back, there's a lot of other useful things you can store for a user to help manage users who access different sites but end up in the same extranet security domain. There's also a lot of registration information that can be stored without having to modify anything. Here's to forward thinking in design.