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.