Favorite Pages for Members

So, you have your Umbraco site all wired up for members, they can log in, adjust their profiles, etc. but wouldn't it be great if they could save a list of page favorites with their profile and easily navigate your site when they are logged in?

Front end display
Front end display

There was a recent Umbraco blog post about doing something similar with Umbraco relations - check it out here - which involves using the API and some .Net coding.

Wouldn't it be even more fun if you did not have to launch Visual Studio to make this all work?

Below is a brief description of how I achieved just that with the help of some great packages and little bit of razor script and jquery.

The tools I used...

If you are not familiar with Macro Service, you should check it out!

Setting up the member...

In my membership configuration, I created a dataType for myFavorites of type Multi-Node Tree Picker and added it to the memberType with an alias of myFavs. 

The razor macros... Get to it already!

 addFavorite.cshtml

@using umbraco.cms.businesslogic.member;
@using umbraco.NodeFactory;

@{
  var member = Member.GetCurrentMember();
  String myValue = @Model.Id.ToString();
  List<string> ListPages = null;

    if (member != null)
        {
            if (member.getProperty("myFavs")!= null && member.getProperty("myFavs").Value != null)
                {   
                   string value = member.getProperty("myFavs").Value.ToString();
                 if(String.IsNullOrEmpty(value)){                 
                           member.getProperty("myFavs").Value = myValue;
                                  } else {
                                        ListPages = value.Split(',').ToList(); 
                                                 if (!ListPages.Contains(myValue))  
                                                    {
                                                     ListPages.Add(myValue);
                                                     member.getProperty("myFavs").Value = String.Join(",", ListPages.ToArray());
                                                     }
                                           }                 
                  member.Save();
                  value = member.getProperty("myFavs").Value.ToString();        
                  ListPages = value.Split(',').ToList();
                }
            }        
  
}

<ul class="unstyled">

@foreach (var id in ListPages) {
                         var name = umbraco.library.GetItem(Int32.Parse(id),"nodeName");      
                         <li><a href="#" rel="@id" class="btn btn-mini btn-danger delete">&times;</a>&nbsp;&nbsp;<a href="@umbraco.library.NiceUrl(Int32.Parse(id))">@name</a></li>       
                                }
</ul>

Add Favorite

removeFavorite.cshtml

@using umbraco.cms.businesslogic.member;
@{
  
        var member = Member.GetCurrentMember();
        String myValue = @Model.Id.ToString();
        List<string> ListPages = null;

            if (member != null)
            {
                if (member.getProperty("myFavs")!= null && member.getProperty("myFavs").Value != null)
                {
                   
                    string value = member.getProperty("myFavs").Value.ToString();
                    ListPages = value.Split(',').ToList();
                 
                    if (ListPages.Contains(myValue))
                    {                  
                        ListPages.Remove(myValue);
                        member.getProperty("myFavs").Value = String.Join(",", ListPages.ToArray());
                        member.Save();                      
                    }
                }
            }
}
<ul class="unstyled">
@foreach (var id in ListPages) {
                         var name = umbraco.library.GetItem(Int32.Parse(id),"nodeName");                               
                         <li><a href="#" rel="@id" class="btn btn-mini btn-danger delete">&times;</a>&nbsp;&nbsp;<a href="@umbraco.library.NiceUrl(Int32.Parse(id))">@name</a></li>       
                                }
</ul>

Remove Favorite

Setting up macro service...

So, now that you have the razor macros created, you need to set up the macro service(s). When you install the Macro Service package, it adds a tab to your macros. Simply select the macro you want to turn into a service and set up as you see below. For more info about macro service, please consult the package page on our.umbraco.org.

Configure Macro Service
Configure Macro Service

and...

Parameters Tab
Parameters Tab

Add the button to the page...

We use the rel attribute on the link to tell our macro what page to add to the member's favorites.

<a class="btn btn-small btn-success" href="#" id="addFav" rel="<umbraco:Item field="pageID" runat="server" />" ><i class="icon-thumbs-up"></i> Add To Favorites</a>

The add link

Some jQuery to tie it all together...

Use this jQuery snippet to add pages to the favorites box -

$('a#addFav').live("click", function(){
      var theNode = $(this).attr('rel');
      $('#favList').load('/feeds/addFav?nodeId='+ theNode);
      })

jQuery snippet

and remove a favorite with this little bit -

$('a.delete').live("click", function(){
      var theNode = $(this).attr('rel');
      $('#favList').load('/feeds/RemoveFav?nodeId='+ theNode);
      })

jQuery snippet

Oh, and I guess we need a little macro to list the favs too... well, for this, I decided to go back to my old school XSLT roots ;)

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE xsl:stylesheet [
  <!ENTITY nbsp "&#x00A0;">
  <!ENTITY times "&#215;">
]>
<xsl:stylesheet
  version="1.0" 
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
  xmlns:msxml="urn:schemas-microsoft-com:xslt"
  xmlns:umbraco.library="urn:umbraco.library" xmlns:Exslt.ExsltCommon="urn:Exslt.ExsltCommon" xmlns:Exslt.ExsltDatesAndTimes="urn:Exslt.ExsltDatesAndTimes" xmlns:Exslt.ExsltMath="urn:Exslt.ExsltMath" xmlns:Exslt.ExsltRegularExpressions="urn:Exslt.ExsltRegularExpressions" xmlns:Exslt.ExsltStrings="urn:Exslt.ExsltStrings" xmlns:Exslt.ExsltSets="urn:Exslt.ExsltSets" xmlns:ucomponents.cms="urn:ucomponents.cms" xmlns:ucomponents.dates="urn:ucomponents.dates" xmlns:ucomponents.email="urn:ucomponents.email" xmlns:ucomponents.io="urn:ucomponents.io" xmlns:ucomponents.media="urn:ucomponents.media" xmlns:ucomponents.members="urn:ucomponents.members" xmlns:ucomponents.nodes="urn:ucomponents.nodes" xmlns:ucomponents.random="urn:ucomponents.random" xmlns:ucomponents.request="urn:ucomponents.request" xmlns:ucomponents.search="urn:ucomponents.search" xmlns:ucomponents.strings="urn:ucomponents.strings" xmlns:ucomponents.urls="urn:ucomponents.urls" xmlns:ucomponents.xml="urn:ucomponents.xml" 
  exclude-result-prefixes="msxml umbraco.library Exslt.ExsltCommon Exslt.ExsltDatesAndTimes Exslt.ExsltMath Exslt.ExsltRegularExpressions Exslt.ExsltStrings Exslt.ExsltSets ucomponents.cms ucomponents.dates ucomponents.email ucomponents.io ucomponents.media ucomponents.members ucomponents.nodes ucomponents.random ucomponents.request ucomponents.search ucomponents.strings ucomponents.urls ucomponents.xml ">

  <xsl:output method="xml" omit-xml-declaration="yes"/>

  <xsl:param name="currentPage"/>

  <xsl:template match="/">
    <xsl:variable name="theMember" select="umbraco.library:GetCurrentMember()" />
    <xsl:if test="$theMember">
      <div class="well well-small">
        <h4>My Favorites</h4>
        <div id="favList">
          <xsl:if test="$theMember/myFavs != ''"> 
            <ul class="unstyled">
              <xsl:for-each select="umbraco.library:Split($theMember/myFavs, ',')/value">
                <xsl:if test=". != ''">
                  <xsl:variable name="link" select="umbraco.library:NiceUrl(.)" />
                    <li>
                      <a href="#" rel="{.}" class="btn btn-mini btn-danger delete">&times;</a>&nbsp;&nbsp;
                      <a href="{$link}"><xsl:value-of select="umbraco.library:GetXmlNodeById(.)/@nodeName" /></a>
                    </li>
                </xsl:if>
              </xsl:for-each>
            </ul>
          </xsl:if>
        </div>
      </div>
    </xsl:if>
  </xsl:template>

</xsl:stylesheet>

listMyFavs.xslt

With that we are just about done! There are many modifications and enhancements that I know all of you can make to this, so have fun and enjoy your holiday season!

Bob Baty-Barr

Bob is on Twitter as