SharePoint Config

Ari Bakker's thoughts on customising and configuring SharePoint

SharePoint 2010 People Directory Part 3 – Sorting

with 18 comments

I’ve had several requests to show how to implement sorting following my previous posts on creating a simple SharePoint 2010 people directory and using a table based layout for a SharePoint 2010 people directory. This post shows how to implement custom sorting for the people directory so you can sort by first name, last name or any other managed property.

sharepoint-people-directory-sort

Step 1: Extend the search core results web part to support sorting

There are two search core results web parts that are capable of displaying list of people:

  • Search Core Results – provides a generic way of displaying search results and supports sorting by relevance and modified date
  • People Search Core Results – provides additional people based information in search results and supports sorting by relevance, social distance and name (a-z only)

As both the web parts only allow a fixed set of sorting options we need to create a new web part if we want to provide sorting options such as by last name or by first name (z-a). The easiest way to do this is to inherit from an existing web part and as the people search core results is sealed we can only do this by inheriting from the search core results web part.

One benefit of using the search core results web part is that we are not limited to displaying lists of people. We can use this web part to display sortable lists of documents, list items, sites or any other information in the search index. This is a very useful technique for aggregating content from across several site collections or across a large number of sites where web parts such as the content query web part run into performance problems (in fact SharePoint 2013 introduces the content by search web part which is based on the same principals we use here).

In the class that extends the search core results web part we can add code that changes the order by clause of the search query. Bart-Jan Hoeijmakers has an excellent post on Creating a sortable CoreResultsWebPart in SharePoint 2010 that shows how to do this. I’ve extended his web part in the example below to changes the sort order based on query string parameters, or properties of the web part if there are no parameters passed in.

using System;
using System.ComponentModel;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using Microsoft.SharePoint;
using Microsoft.SharePoint.WebControls;
using Microsoft.Office.Server.Search.WebControls;
using Query = Microsoft.Office.Server.Search.Query;

namespace Ari.SharePointSearch.WebParts
{
    [ToolboxItemAttribute(false)]
    public class SortableCoreResults : CoreResultsWebPart
    {
        [Personalizable(PersonalizationScope.Shared)]
        [WebBrowsable(true)]
        [WebDisplayName("Default managed property")]
        [WebDescription("Sort by this managed property by default")]
        [Category("Sorting Properties")]
        public string OrderByProperty { get; set; }

        [Personalizable(PersonalizationScope.Shared)]
        [WebBrowsable(true)]
        [WebDisplayName("Default direction")]
        [WebDescription("Default sorting direction")]
        [Category("Sorting Properties")]
        public Microsoft.Office.Server.Search.Query.SortDirection SortDirection { get; set; }

        /// <summary>
        /// Runs the base configuration then adds a custom sort property
        /// </summary>
        protected override void ConfigureDataSourceProperties()
        {
            // only run when we are showing search results (e.g. not the search action links)
            if (this.ShowSearchResults)
            {
                try
                {
                    // run the base code
                    base.ConfigureDataSourceProperties();

                    // get the sorting parameters off the query string
                    string orderByProperty = this.Context.Request.QueryString["v1"];
                    string sortDir = this.Context.Request.QueryString["SortDir"];

                    // if none set use the defaults
                    if (string.IsNullOrEmpty(orderByProperty))
                        orderByProperty = OrderByProperty;

                    Query.SortDirection sortDirection = SortDirection;

                    if (!string.IsNullOrEmpty(sortDir) && sortDir.ToLower() == "desc")
                        sortDirection = Query.SortDirection.Descending;
                    else if (!string.IsNullOrEmpty(sortDir) && sortDir.ToLower() == "asc")
                        sortDirection = Query.SortDirection.Ascending;

                    CoreResultsDatasource dataSource = this.DataSource as CoreResultsDatasource;

                    // if we have an orderByProperty then modify the search query sort order
                    if (!string.IsNullOrEmpty(orderByProperty))
                    {
                        dataSource.SortOrder.Clear();
                        dataSource.SortOrder.Add(orderByProperty, sortDirection);
                    }
                }
                catch (Exception ex)
                {
                    // implement exception handling here
                }
            }
        }

        protected override void ModifyXsltArgumentList(Microsoft.SharePoint.WebPartPages.ArgumentClassWrapper argList)
        {
            base.ModifyXsltArgumentList(argList);

            // add a parameter with the current URL
            argList.AddParameter("CurrentUrl", string.Empty, HttpContext.Current.Request.Url.PathAndQuery);
        }
    }
}

This web part now lets us set a default sort option by passing in parameters on the query string. For example if we load the page the web part is on with parameters such as peopledirectory.aspx?v1=LastName&SortDir=asc the web part will sort the results by last name A-Z.

We can also set the default sorting option by using the sorting properties that are shown when editing the web part. This will be used to sort the results when the query string parameters are not present.

sharepoint-search-results-sorting-properties

Step 2: Extend the search results XSLT to render additional sorting options

sharepoint-people-directory-sort-dropdown The second step is to change the XSLT that renders the sort by drop down to include additional sorting options. When a different sort option is selected the property and the direction (i.e. ascending or descending) will be passed on the query string to the core results web part we created in step 1.

I’ve included an example of how to add first name and last name sorts both ascending (a-z) and descending (z-a) below:

        <xsl:if test="$ShowDropDown = 'true'">
          <xsl:value-of select="$SortBy" />
          <select id="dropdown" title="{$SortOptions}" onchange="PostToUrl(this.value)" class="srch-dropdown">
            <xsl:call-template name="AddSortOption">
              <xsl:with-param name="DisplayName">First name (A-Z)</xsl:with-param>
              <xsl:with-param name="ManagedProperty">FirstName</xsl:with-param>
              <xsl:with-param name="Direction">Asc</xsl:with-param>
            </xsl:call-template>
            <xsl:call-template name="AddSortOption">
              <xsl:with-param name="DisplayName">First name (Z-A)</xsl:with-param>
              <xsl:with-param name="ManagedProperty">FirstName</xsl:with-param>
              <xsl:with-param name="Direction">Desc</xsl:with-param>
            </xsl:call-template>
            <xsl:call-template name="AddSortOption">
              <xsl:with-param name="DisplayName">Last name (A-Z)</xsl:with-param>
              <xsl:with-param name="ManagedProperty">LastName</xsl:with-param>
              <xsl:with-param name="Direction">Asc</xsl:with-param>
            </xsl:call-template>
            <xsl:call-template name="AddSortOption">
              <xsl:with-param name="DisplayName">Last name (Z-A)</xsl:with-param>
              <xsl:with-param name="ManagedProperty">LastName</xsl:with-param>
              <xsl:with-param name="Direction">Desc</xsl:with-param>
            </xsl:call-template>
          </select>
        </xsl:if>

This relies on a couple of helper templates to create the hyperlink containing the relevant query string parameters. These templates are shown below:

  <xsl:template name="AddSortOption">
    <xsl:param name="DisplayName"/>
    <xsl:param name="ManagedProperty"/>
    <xsl:param name="Direction"/>

    <xsl:variable name="UrlWithSortProperty">
      <xsl:call-template name="ReplaceQsParameter">
        <xsl:with-param name="URL" select="$CurrentUrl"/>
        <xsl:with-param name="ParamName">v1=</xsl:with-param>
        <xsl:with-param name="ParamValue" select="$ManagedProperty"/>
      </xsl:call-template>
    </xsl:variable>

    <xsl:variable name="UrlWithSortAndOrderProperties">
      <xsl:call-template name="ReplaceQsParameter">
        <xsl:with-param name="URL" select="$UrlWithSortProperty"/>
        <xsl:with-param name="ParamName">SortDir=</xsl:with-param>
        <xsl:with-param name="ParamValue" select="$Direction"/>
      </xsl:call-template>
    </xsl:variable>

    <option value="{$UrlWithSortAndOrderProperties}">
      <xsl:if test="$UrlWithSortAndOrderProperties = $CurrentUrl">
        <xsl:attribute name="selected">selected</xsl:attribute>
      </xsl:if>
      <xsl:value-of select="$DisplayName"/>
    </option>

  </xsl:template>

  <xsl:template name="ReplaceQsParameter">
    <xsl:param name="URL"/>
    <xsl:param name="ParamName"/>
    <xsl:param name="ParamValue"/>
    <xsl:choose>
      <xsl:when test="contains($URL, $ParamName)">
        <xsl:variable name="Before" select="substring-before($URL, $ParamName)"/>
        <xsl:variable name="After" select="substring-after(substring-after($URL, $ParamName), '&amp;')"/>
        <xsl:choose>
          <xsl:when test="$After = ''">
            <xsl:value-of select="concat($Before, $ParamName, $ParamValue)"/>
          </xsl:when>
          <xsl:otherwise>
            <xsl:value-of select="concat($Before, $ParamName, $ParamValue, '&amp;', $After)"/>
          </xsl:otherwise>
        </xsl:choose>
      </xsl:when>
      <xsl:when test="contains($URL, '?')">
        <xsl:value-of select="concat($URL, '&amp;', $ParamName, $ParamValue)"/>
      </xsl:when>
      <xsl:otherwise>
        <xsl:value-of select="concat($URL, '?', $ParamName, $ParamValue)"/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

I’ve also modified the XSLT to display the results in a table based layout as per my previous post on creating a SharePoint 2010 people directory with a table based layout.

If you want the complete code packaged up you can download the solution package for the search core results web part. Note this is a farm solution as the search core results web part cannot be extended using a sandboxed solution.

Once you have deployed the solution the steps below can be used to add the sortable search results web part to a search results page:

  1. Activate the ‘Sortable Core Results’ site collection feature
  2. Assuming you have an enterprise search center set up the next step is to create a new search results page by selecting Site Actions > New Page from the search site.
  3. On the search results page delete the Search Core Results web part
  4. In the bottom web part zone click ‘Add a Web Part’ and select the ‘Sortable Core Results’ web part from the Search category
  5. Delete the Search Action Links web part
  6. In the middle lower right web part zone click ‘Add a Web Part’ and select the ‘Sortable Core Results’ web part
  7. Modify the sortable core results web part in the middle right zone and under the miscellaneous section deselect ‘show search results’ and select ‘show action links’sharepoint-search-show-action-links-property

You should now have a page that displays a list people with a drop down that allows users to sort by first name or last name A-Z or Z-A.

sharepoint-people-directory-sort

The example solution uses a table based layout but it is also possible to use a layout similar to the people search results by changing the XSLT file used to render the results.

Download the solution package for the search core results web part

Additional resources

Post to Twitter Post to Delicious Post to Digg Post to Reddit Post to StumbleUpon

Written by Ari Bakker

February 5th, 2013 at 1:11 pm

Posted in 2010,Search

18 Responses to 'SharePoint 2010 People Directory Part 3 – Sorting'

Subscribe to comments with RSS or TrackBack to 'SharePoint 2010 People Directory Part 3 – Sorting'.

  1. I downloaded your solution package and deployed it to my farm but was unable to find it under the Search section in order to add it to a web part zone. Am I missing something?

    Naveen Brahmi

    7 Feb 13 at 8:25 pm

  2. @Naveen to ensure the web part is available you need to activate the ‘Sortable Core Results’ site collection level feature. I’ve amended the article so this is clear. Let me know if it still doesn’t show up.

    Ari Bakker

    7 Feb 13 at 10:27 pm

  3. Silly mistake! Deployed and activated the solution on a different web app. Got it added and configured as per your instructions.
    However after replacing Search Core Results web part and Search Action Links web parts with the sortable core results, the web part throws an error with a correlation id. I cant seem to upload a screenshot here, but it displayed something in the lines if “Unable to display web part or content…”. Again I have followed your instructions word to word. Am I missing something in my environment per se?
    Thanks!

    Naveen

    8 Feb 13 at 3:40 am

  4. @Naveen what is the error message that is displayed in the log files for that correlation ID?

    Ari Bakker

    8 Feb 13 at 10:22 am

  5. This is what is displayed once I add and configure the web part “Unable to display this Web Part. To troubleshoot the problem, open this Web page in a Microsoft SharePoint Foundation-compatible HTML editor such as Microsoft SharePoint Designer. If the problem persists, contact your Web server administrator.

    Correlation ID:76518cbc-8821-4319-908b-da22704d4d65″

    I have Created a Search Results page under my IT site collection pages library. I am assuming the location shoudl not matter as long as I have a search service appl running successfully.

    The ULS logs seem to have quite a few entries against the corelation id but here are a couple that looked problematic (in the order of occurence)
    1. Medium Filter category FASTMaxNumberOfFilters in the config is in wrong format.Input string was not in a correct format.

    2. Medium Unknown SPRequest error occurred.

    3. Error while executing web part: System.ArgumentNullException: Value cannot be null. Parameter name: s at System.IO.StringReader..ctor(String s) at Microsoft.SharePoint.WebPartPages.DataFormWebPart.LoadXslCompiledTransform(WSSXmlUrlResolver someXmlResolver) at Microsoft.SharePoint.WebPartPages.DataFormWebPart.GetXslCompiledTransform() at Microsoft.SharePoint.WebPartPages.DataFormWebPart.PrepareAndPerformTransform(Boolean bDeferExecuteTransform)

    Naveen

    8 Feb 13 at 8:15 pm

  6. @Naveen I think you will need to modify the path to the XSLT file if you are not using the root site collection. If you are able to change the XSL Link property under the miscellaneous section to include the path to the site collection e.g. /sites/it/Style Library/SortableCoreResults/SortableSearchResults.xslt that might resolve the problem. When I have time I’ll also update the code to handle this scenario.

    Ari Bakker

    9 Feb 13 at 11:29 pm

  7. @Ari Bakker
    Thanks! Worked beautifully!
    Two questions here though:
    1. Im looking to increase the number of items displyed on a single page. I get about 10 results displayed currently. What parameter am I looking at modifying to make this change?
    2. You have also mentioned that the same effect if possible with the default/OOTB people search results view, by modifying the XSLT. Again, am I looking heavy moficiations to the XSLT or could I possibly just use the XSLT from the default view directly?
    Please advise.

    Naveen

    11 Feb 13 at 3:32 pm

  8. Great article, Ari – everything worked as expected.

    Two quick questions:
    1) I noticed that the table layout does not seem to expand to fit the page, even when you edit the web part appearance to fit the zone. Is this due to the page layout? If yes, is is possible to use a different page layout or otherwise better control the column widths?

    2) I wanted to display the OOTB “Assistant” user profile property in my table. I created a managed property and can display the value, but it is displaying as the person’s account name and not display name. Do you know of any way to get this property to display using the display name in the table?

    Thanks!

    Brian

    Brian

    11 Feb 13 at 9:25 pm

  9. Hi Ari,

    Great post! thanks for the mention.

    Regards,
    Bart-Jan Hoeijmakers

  10. Ari,
    Just a followup – as a workaround for the column width issue I increased the size of my column header text. This works great for me (site collection admin) but when a normal user (read permission only) views the same page, the column widths are again very narrow. I noticed that users must have at least contribute rights to the site to see the page as intended. Do you know why this may be?

    Thanks!

    Brian

    14 Feb 13 at 6:22 pm

  11. Arrgh! Disregard last comment… just hadn’t published the xslt file.

    I Love SharePoint! :-)

    Brian

    14 Feb 13 at 7:00 pm

  12. Very helpful post!
    I am new to XSLT and seem to have the same requirement as Naveen. Any chance you could point me to a helpful resource on implementing the same on the default people search results XSLT?

    John H

    4 Mar 13 at 9:23 pm

  13. Hi Ari,

    Thanks for the post. I’ve followed the steps but nothing got displayed… My thought is that the the core search result doesn’t render the people search properties such as preferredname, etc. I copied the xslt to the People search core results and it displays fine but then I lost the sorting… Any idea? Thanks for your help!

    Xin

    11 Mar 13 at 7:33 pm

  14. I downloaded the .zip file but I do not see a wsp package in there? How do I deploy to my farm without a wsp file? thank you in advance

    Emily

    9 May 13 at 8:47 pm

  15. @Emily the package contains the source code – if you just want the wsp there is one in the bin/debug folder

    Ari Bakker

    13 May 13 at 10:56 pm

  16. Thanks for the post. I have download and deployed solution. But i am not able to get any result. I want to use this for metadata properties for local scope

    Gaurav

    21 May 13 at 2:58 pm

  17. Hi Ari,

    Apart from the .wsp file in the bin folder, do I need to copy the .pdb and .ll files for the solution to work?

    Secondly, what do I need to do to show the picture column in this table base style.

    Thank you,

    Bisi

    3 Jul 13 at 9:27 pm

  18. @Bisi you only need the .wsp file. You can find instructions on how to deploy this solution package at http://technet.microsoft.com/en-us/library/cc262995(v=office.14).aspx

    Ari Bakker

    5 Jul 13 at 5:02 pm

Leave a Reply