SharePoint 2010 Search Results Customisation

Requirement

I was given the task of creating a simple Staff Directory for the company I work for after trialing some other products that used custom webparts. All of the products we tested did not meet our requirements or were too slow.

After some research, I found a way to customise the people search results webpart to look like a Staff Directory.

Here are the steps.

Solution

Create your search results page and add a People search results webpart.

Modify the People search results webpart

  • Edit Webpart -> Location Properties -> Display Properties
  • Use Local Visualization: Unticked
  • Results per page: 50 (up to you)
  • Click on XSL editor
  • Delete the code and paste the following code in:

<?xml version=”1.0″ encoding=”utf-8″?>

<xsl:stylesheet version=”1.0″

xmlns:xsl=”http://www.w3.org/1999/XSL/Transform”

xmlns:ddwrt=”http://schemas.microsoft.com/WebParts/v2/DataView/runtime”

xmlns:asp=”http://schemas.microsoft.com/ASPNET/20″

xmlns:SEARCHWC=”http://schemas.microsoft.com/searchserver/”>

<xsl:output method=”xml” indent=”no”/>

<xsl:param name=”SortBy” />

<xsl:param name=”DropDownOption” />

<xsl:param name=”RelevanceSortUrl” />

<xsl:param name=”RelevanceSortLabel” />

<xsl:param name=”SocialDistanceSortUrl” />

<xsl:param name=”SocialDistanceSortLabel” />

<xsl:param name=”NameSortUrl” />

<xsl:param name=”NameSortLabel” />

<xsl:param name=”IsNoKeyword” />

<xsl:param name=”IsFixedQuery” />

<xsl:param name=”ShowMoreLink” />

<xsl:param name=”MoreLinkLabel” />

<xsl:param name=”MoreLink” />

<xsl:param name=”AlertMeLink” />

<xsl:param name=”AlertMeText” />

<xsl:param name=”SrchRSSText” />

<xsl:param name=”SrchRSSLink” />

<xsl:param name=”ShowMessage” />

<xsl:param name=”ShowActionLinks” />

<xsl:param name=”SearchProviderText” />

<xsl:param name=”SearchProviderLink” />

<xsl:param name=”IsPeopleCoreResultsWebPart” />

<xsl:param name=”NoFixedQuery” />

<xsl:param name=”NoKeyword” />

<xsl:param name=”NoPeopleResults” />

<xsl:param name=”NoPeopleResults1″ />

<xsl:param name=”NoPeopleResults2″ />

<xsl:param name=”NoPeopleResults3″ />

<xsl:param name=”NoPeopleResults4″ />

<xsl:param name=”ParentOrgsLabel” />

<xsl:param name=”ViewHiearchyLabel” />

<xsl:param name=”RecentContentLabel” />

<xsl:param name=”ResponsibilitiesLabel” />

<xsl:param name=”SkillsLabel” />

<xsl:param name=”InterestsLabel” />

<xsl:param name=”PastProjectsLabel” />

<xsl:param name=”SchoolLabel” />

<xsl:param name=”MembershipLabel” />

<xsl:param name=”AboutMeLabel” />

<xsl:param name=”BaseOfficeLabel” />

<xsl:param name=”SummaryLabel” />

<xsl:param name=”ProfileViewLabel” />

<xsl:param name=”UpdateProfileLabel” />

<xsl:param name=”QueriesFoundYouLabel” />

<xsl:param name=”UpdateProfileKeywordLabel” />

<xsl:param name=”SelfSearchLabel” />

<xsl:param name=”NoKeywordLabel” />

<xsl:param name=”AddToMyColleaguesText” />

<xsl:param name=”PopupFetcingResultLabel” />

<xsl:param name=”IdPrefix” />

<xsl:param name=”LangPickerHeading” />

<xsl:param name=”LangPickerNodeSet” />

<xsl:param name=”FilterNodeSet” />

<xsl:param name=”ShowPeopleSortDropdown” />

<xsl:param name=”RecentUpdateTabLabel” />

<!– Custom fields –>

<xsl:param name=”IPPhoneLabel” />

<xsl:param name=”MobileLabel” />

<!– When there is no keywory to issue the search –>

<xsl:template name=”dvt_1.noKeyword”>

<span class=”ms-sbplain”>

<xsl:choose>

<xsl:when test=”$IsFixedQuery”>

<xsl:value-of select=”$NoFixedQuery” />

</xsl:when>

<xsl:otherwise>

<xsl:value-of select=”$NoKeyword” />

</xsl:otherwise>

</xsl:choose>

</span>

</xsl:template>

<!– When empty result set is returned from search –>

<xsl:template name=”dvt_1.empty”>

<div class=”psrch-results”>

<xsl:if test=”$ShowActionLinks”>

<xsl:call-template name=”ActionBarTemplate” />

</xsl:if>

</div>

<span class=”srch-description” id=”CSR_NO_RESULTS”>

<xsl:value-of select=”$NoPeopleResults”/>

<ol>

<li>

<xsl:value-of select=”$NoPeopleResults1″/>

</li>

<li>

<xsl:value-of select=”$NoPeopleResults2″/>

</li>

<li>

<xsl:value-of select=”$NoPeopleResults3″/>

</li>

<li>

<xsl:value-of select=”$NoPeopleResults4″/>

</li>

</ol>

</span>

</xsl:template>

<!– Main body template–>

<xsl:template name=”dvt_1.body”>

<div class=”psrch-results”>

<xsl:if test=”$ShowActionLinks”>

<div class=”srch-sort-right2″>

<xsl:if test=”$LangPickerNodeSet and count($LangPickerNodeSet) &gt; 0″>

<label for=”langpickerdd” id=”langpickerddlabel”>

<xsl:value-of select=”$LangPickerHeading”/>

</label>

<select title=”{$LangPickerHeading}” class=”srch-dropdown” onchange=”window.location.href=this.value” id=”langpickerdd”>

<xsl:for-each select=”$LangPickerNodeSet”>

<xsl:element name=”option”>

<xsl:attribute name=”value”>

<xsl:value-of select=”@url”/>

</xsl:attribute>

<xsl:if test=”@selected = ‘true'”>

<xsl:attribute name=”selected”>selected</xsl:attribute>

</xsl:if>

<xsl:value-of select=”@title”/>

</xsl:element>

</xsl:for-each>

</select>

<xsl:text disable-output-escaping=”yes”>&#8195;</xsl:text>

</xsl:if>

<xsl:if test=”$ShowPeopleSortDropdown”>

<label for=”sortbydd” id=”sortbyddlabel”>

<xsl:value-of select=”$SortBy” />

</label>

<select title=”{$SortBy}” name=”dropdown” onchange=”window.location.href=this.value” class=”srch-dropdown” id=”sortbydd”>

<xsl:element name=”option”>

<xsl:attribute name=”value”>

<xsl:value-of select=”string($RelevanceSortUrl)”/>

</xsl:attribute>

<xsl:if test=”$DropDownOption = ‘0’”>

<xsl:attribute name=”selected”>selected</xsl:attribute>

</xsl:if>

<xsl:value-of select=”$RelevanceSortLabel”/>

</xsl:element>

<xsl:if test=”string-length($SocialDistanceSortUrl) &gt; 0 and string-length($SocialDistanceSortLabel) &gt; 0″>

<xsl:element name=”option”>

<xsl:attribute name=”value”>

<xsl:value-of select=”string($SocialDistanceSortUrl)”/>

</xsl:attribute>

<xsl:if test=”$DropDownOption = ‘1’”>

<xsl:attribute name=”selected”>selected</xsl:attribute>

</xsl:if>

<xsl:value-of select=”$SocialDistanceSortLabel”/>

</xsl:element>

</xsl:if>

<xsl:element name=”option”>

<xsl:attribute name=”value”>

<xsl:value-of select=”string($NameSortUrl)”/>

</xsl:attribute>

<xsl:if test=”$DropDownOption = ‘2’”>

<xsl:attribute name=”selected”>selected</xsl:attribute>

</xsl:if>

<xsl:value-of select=”$NameSortLabel”/>

</xsl:element>

</select>

<xsl:text disable-output-escaping=”yes”>&#8195;</xsl:text>

</xsl:if>

<xsl:call-template name=”ActionBarTemplate” />

</div>

</xsl:if>

<table width=”100%” class=”ms-listviewtable”>

<thead>

<tr class=”ms-viewheadertr ms-vhltr”>

<td class=”ms-vh2″>Name</td>

<td class=”ms-vh2″>Phone</td>

<td class=”ms-vh2″>Email</td>

<td class=”ms-vh2″>Job title</td>

<td class=”ms-vh2″>Department</td>

<td class=”ms-vh2″>Office</td>

<!– Custom fields –>

<td class=”ms-vh2″>IPPhone</td>

<td class=”ms-vh2″>Mobile</td>

</tr>

</thead>

<xsl:for-each select=”All_Results/Result”>

<xsl:call-template name=”SingleResult”/>

</xsl:for-each>

</table>

<xsl:call-template name=”MoreLinkTemplate” />

</div>

</xsl:template>

<!– This template is called for each result –>

<xsl:template name=”SingleResult”>

<xsl:call-template name=”SingleResultInternal” />

</xsl:template>

<xsl:template name=”SingleResultInternal”>

<xsl:variable name=”id” select=”id”/>

<xsl:variable name=”currentId” select=”concat($IdPrefix,$id)”/>

<xsl:variable name=”url” select=”url”/>

<xsl:variable name=”email” select=”workemail”/>

<xsl:variable name=”sip” select=”sipaddress”/>

<xsl:variable name=”prefix”>IMNRC(‘</xsl:variable>

<xsl:variable name=”suffix”>’)</xsl:variable>

<xsl:variable name=”hassip” select=”string-length($sip) &gt; 0″/>

<xsl:variable name=”hasemail” select=”string-length($email) &gt; 0″/>

<xsl:variable name=”haspn” select=”string-length(preferredname) &gt; 0″/>

<xsl:variable name=”hasydn” select=”string-length(yomidisplayname) &gt; 0″/>

<xsl:variable name=”hasjt” select=”string-length(jobtitle) &gt; 0″/>

<xsl:variable name=”hasdp” select=”string-length(department) &gt; 0″/>

<xsl:variable name=”hasorg” select=”string-length(orgnames) &gt; 0″/>

<xsl:variable name=”haswph” select=”string-length(workphone) &gt; 0″/>

<xsl:variable name=”hasonum” select=”string-length(officenumber) &gt; 0″/>

<xsl:variable name=”hascol” select=”string-length(colleaguecategory) &gt; 0″/>

<xsl:variable name=”hasacu” select=”string-length(addtomycolleaguesurl) &gt; 0″/>

<xsl:variable name=”hashier” select=”string-length(hierarchyurl) &gt; 0″/>

<xsl:variable name=”hasabme” select=”string-length(aboutme) &gt; 0″/>

<xsl:variable name=”hasresp” select=”string-length(responsibility) &gt; 0″/>

<xsl:variable name=”hassk” select=”($FilterNodeSet and $FilterNodeSet/@title=’SPShSkills’) or hithighlightedproperties/skills/@hashh &gt; 0″/>

<xsl:variable name=”hasint” select=”($FilterNodeSet and $FilterNodeSet/@title=’SPShInterests’) or hithighlightedproperties/interests/@hashh &gt; 0″/>

<xsl:variable name=”hasorgparent” select=”($FilterNodeSet and $FilterNodeSet/@title=’OrgParentNames’) or hithighlightedproperties/orgparentnames/@hashh &gt; 0″/>

<xsl:variable name=”hasmem” select=”($FilterNodeSet and $FilterNodeSet/@title=’Memberships’) or hithighlightedproperties/memberships/@hashh &gt; 0″/>

<xsl:variable name=”haspp” select=”($FilterNodeSet and $FilterNodeSet/@title=’SPShPastProjects’) or hithighlightedproperties/pastprojects/@hashh &gt; 0″/>

<xsl:variable name=”hasbol” select=”($FilterNodeSet and $FilterNodeSet/@title=’SPShLocation’) or hithighlightedproperties/baseofficelocation/@hashh &gt; 0″/>

<xsl:variable name=”hassch” select=”($FilterNodeSet and $FilterNodeSet/@title=’SPShSchool’) or hithighlightedproperties/schools/@hashh &gt; 0″/>

<xsl:variable name=”hassum” select=”count(hithighlightedsummary/c0) &gt; 0″/>

<xsl:variable name=”hasvlm” select=”string-length(profileviewlastmonth) &gt; 0″/>

<xsl:variable name=”hasvlw” select=”string-length(profileviewlastweek) &gt; 0″/>

<xsl:variable name=”hasquery” select=”string-length(queriesfoundyou) &gt; 0″/>

<!– Custom fields –>

<xsl:variable name=”hasipphone” select=”string-length(ipphone) &gt; 0″/>

<xsl:variable name=”hasmobile” select=”string-length(mobile) &gt; 0″/>

<tr>

<td class=”ms-vb2″>

<xsl:if test=”$haspn”>

<a href=”{string($url)}” id=”{concat($currentId, ‘_CSR’)}”>

<xsl:apply-templates select=”hithighlightedproperties/preferredname” />

</a>

</xsl:if>

</td>

<td class=”ms-vb2″>

<xsl:apply-templates select=”hithighlightedproperties/workphone” />

</td>

<td class=”ms-vb2″>

<xsl:choose>

<xsl:when test=”$hassip”>

<a id=”{concat($currentId, ‘_EmailLink’)}” href=”{concat(‘mailto:’, $sip)}”>

<xsl:apply-templates select=”hithighlightedproperties/sipaddress” />

</a>

</xsl:when>

<xsl:otherwise>

<a id=”{concat($currentId, ‘_EmailLink’)}” href=”{concat(‘mailto:’, $email)}”>

<xsl:apply-templates select=”hithighlightedproperties/workemail” />

</a>

</xsl:otherwise>

</xsl:choose>

</td>

<td class=”ms-vb2″>

<xsl:apply-templates select=”hithighlightedproperties/jobtitle” />

</td>

<td class=”ms-vb2″>

<xsl:apply-templates select=”hithighlightedproperties/department” />

</td>

<td class=”ms-vb2″>

<xsl:apply-templates select=”hithighlightedproperties/officenumber” />

</td>

<!– Custom fields –>

<td class=”ms-vb2″>

<xsl:apply-templates select=”hithighlightedproperties/ipphone” />

</td>

<td class=”ms-vb2″>

<xsl:apply-templates select=”hithighlightedproperties/mobile” />

</td>

</tr>

</xsl:template>

<!– XSL transformation starts here –>

<xsl:template match=”/”>

<xsl:if test=”$AlertMeLink and $ShowActionLinks”>

<input type=”hidden” name=”P_Query” />

<input type=”hidden” name=”P_LastNotificationTime” />

</xsl:if>

<div class=”psrch-Main”>

<xsl:choose>

<xsl:when test=”$IsNoKeyword = ‘True'” >

<xsl:call-template name=”dvt_1.noKeyword” />

</xsl:when>

<xsl:when test=”$ShowMessage = ‘True'”>

<xsl:call-template name=”dvt_1.empty” />

</xsl:when>

<xsl:otherwise>

<xsl:call-template name=”dvt_1.body”/>

</xsl:otherwise>

</xsl:choose>

<xsl:if test=”$IsPeopleCoreResultsWebPart and (count(All_Results/Result) &gt; 0 or count(All_Results/FakeResult) &gt; 0)”>

<asp:Panel ID=”PopupPanelPeopleCore” runat=”server” CssClass=”psrch-PopupPanel”>

<div id=”PopupContainer” class=”psrch-PopupContainer”>

<asp:UpdatePanel runat=”server” ID=”UpdatePanelPeopleCore” UpdateMode=”Conditional” ChildrenAsTriggers=”true”>

<ContentTemplate>

<SEARCHWC:PeopleCoreResultPopupControl

id=”PopupControl51A944753DF0430C8FE1EBAA70F3E945″

runat=”server”/>

<div id=”PopupFooter”>

<asp:UpdateProgress ID=”UpdateProgress” DisplayAfter=”0″ AssociatedUpdatePanelID=”UpdatePanelPeopleCore” runat=”server”>

<ProgressTemplate>

<span id=”Progress”>

<img class=”psrch-UpdateGraphics” src=”/_layouts/images/hig_progcircle_loading24.gif”/>

<xsl:value-of select=”$PopupFetcingResultLabel” />

</span>

</ProgressTemplate>

</asp:UpdateProgress>

</div>

</ContentTemplate>

</asp:UpdatePanel>

</div>

</asp:Panel>

</xsl:if>

</div>

</xsl:template>

<xsl:template name=”ActionBarTemplate”>

<xsl:if test=”string-length($AlertMeLink) &gt; 0″>

<a href=”{$AlertMeLink}” id=”CSR_AM” title=”{$AlertMeText}”>

<img src=”/_layouts/images/bell.gif” alt=”{$AlertMeText}” border=”0″/>

</a>

<xsl:text disable-output-escaping=”yes”>&#8195;</xsl:text>

</xsl:if>

<xsl:if test=”string-length($SrchRSSLink) &gt; 0″>

<a type=”application/rss+xml” href=”{string($SrchRSSLink)}” title=”{$SrchRSSText}” id=”SRCHRSSL”>

<img border=”0″ src=”/_layouts/images/rss.gif” alt=”{$SrchRSSText}”/>

</a>

<xsl:text disable-output-escaping=”yes”>&#8195;</xsl:text>

</xsl:if>

<xsl:if test=”string-length($SearchProviderLink) &gt; 0″>

<a href=”{string($SearchProviderLink)}” title=”{$SearchProviderText}” >

<img border=”0″ src=”/_layouts/images/searchfolder.png” alt=”{$SearchProviderText}”/>

</a>

<xsl:text disable-output-escaping=”yes”>&#8195;</xsl:text>

</xsl:if>

</xsl:template>

<xsl:template name=”GetPicUrl”>

<xsl:param name=”PicUrl”/>

<xsl:param name=”PlaceHolderUrl”/>

<xsl:choose>

<xsl:when test=”string-length($PicUrl) &lt; 1 or starts-with($PicUrl, ‘file:’) or starts-with($PicUrl, ‘\\’) or starts-with($PicUrl, ‘//’)”>

<xsl:value-of select=”$PlaceHolderUrl”/>

</xsl:when>

<xsl:otherwise>

<xsl:value-of select=”$PicUrl”/>

</xsl:otherwise>

</xsl:choose>

</xsl:template>

<xsl:template name=”MoreLinkTemplate”>

<xsl:if test=”$ShowMoreLink = true() and string-length($MoreLink) &gt; 0″>

<div id=”MoreLink”>

<a href=”{string($MoreLink)}”>

<xsl:value-of select=”$MoreLinkLabel”/>

</a>

</div>

</xsl:if>

</xsl:template>

<xsl:template name=”RenderNameUrlMultivalue”>

<xsl:param name=”names”/>

<xsl:param name=”urls”/>

<xsl:param name=”currentId”/>

<xsl:for-each select=”$names”>

<xsl:variable name=”p” select=”position()”/>

<xsl:if test=”string-length(.) &gt; 0″>

<xsl:if test=”$p &gt; 1″>

<span class=”psrch-TextSeparator”> :: </span>

</xsl:if>

<xsl:choose>

<xsl:when test=”string-length($urls[$p]) &gt; 0″>

<a id=”{concat($currentId, ‘_MultivalueUrl’)}” href=”{string($urls[$p])}”>

<xsl:apply-templates select=”.” />

</a>

</xsl:when>

<xsl:otherwise>

<xsl:apply-templates select=”.” />

</xsl:otherwise>

</xsl:choose>

</xsl:if>

</xsl:for-each>

</xsl:template>

<xsl:template name=”RenderSimpleMultivalue”>

<xsl:param name=”multivalue”/>

<xsl:param name=”cutoff”/>

<xsl:for-each select=”$multivalue”>

<xsl:sort data-type=”number” order=”descending” select=”@hashh”/>

<xsl:variable name=”p” select=”position()”/>

<xsl:if test=”string-length(.) &gt; 0″>

<xsl:choose>

<xsl:when test=”$p = 1″>

<span id=”Multivalue”>

<xsl:apply-templates select=”.” />

</span>

</xsl:when>

<xsl:when test=”$p &gt; 1 and $p &lt;= $cutoff”>

<span class=”psrch-TextSeparator”> :: </span>

<span id=”Multivalue”>

<xsl:apply-templates select=”.” />

</span>

</xsl:when>

<xsl:when test=”$p = $cutoff + 1″>

&#8230;

</xsl:when>

</xsl:choose>

</xsl:if>

</xsl:for-each>

</xsl:template>

<xsl:template name=”HitHighlighting”>

<xsl:param name=”hh” />

<xsl:apply-templates select=”$hh”/>

</xsl:template>

<xsl:template match=”ddd”>

&#8230;

</xsl:template>

<xsl:template match=”c0″>

<b>

<xsl:value-of select=”.”/>

</b>

</xsl:template>

<xsl:template match=”c1″>

<b>

<xsl:value-of select=”.”/>

</b>

</xsl:template>

<xsl:template match=”c2″>

<b>

<xsl:value-of select=”.”/>

</b>

</xsl:template>

<xsl:template match=”c3″>

<b>

<xsl:value-of select=”.”/>

</b>

</xsl:template>

<xsl:template match=”c4″>

<b>

<xsl:value-of select=”.”/>

</b>

</xsl:template>

<xsl:template match=”c5″>

<b>

<xsl:value-of select=”.”/>

</b>

</xsl:template>

<xsl:template match=”c6″>

<b>

<xsl:value-of select=”.”/>

</b>

</xsl:template>

<xsl:template match=”c7″>

<b>

<xsl:value-of select=”.”/>

</b>

</xsl:template>

<xsl:template match=”c8″>

<b>

<xsl:value-of select=”.”/>

</b>

</xsl:template>

<xsl:template match=”c9″>

<b>

<xsl:value-of select=”.”/>

</b>

</xsl:template>

</xsl:stylesheet>

  •  Save your changes.
  • Go to Location Properties -> Results Query Options
  • Fixed Keyword Query: ContentClass:SPSPeople
  • Save webpart changes
  • Save your page and refresh

The people search results webpart should now look something like this:

Note that we added two custom fields: IP Phone and Mobile. You can remove this or add your own custom fields by modifying the sections with <!– Custom fields –> in the above XSLT.

Other things you might want to do is change the default sorting of results to Name.

You can do this easily by modifying the Search Action Links webpart properties:

You can extend this solution further with filtering if you write a custom solution but that is outside the scope of this article.

Tags: , ,

4 Responses to “SharePoint 2010 Search Results Customisation”

  1. Gustavo January 19, 2012 at 11:29 am #

    There is a way that it looks for people ordering displayed for search in general?

    • Andrew Toh January 20, 2012 at 8:50 am #

      If you are using Enterprise Search you get the option of sorting by Name, Social Distance, or Default. You can sort on custom properties if you have Fast search.

      • Gustavo January 20, 2012 at 9:33 am #

        I have no search by running fast, estubo research and the only way is to create a paging webpart even though I can not show all the data sorting and paging together not by each of the pages. Sabras any way which I can sort out all the search with everything and the results per page?.

        Greetings and thank you very much and
        Congratulations on your blog

  2. Karen May 15, 2013 at 2:16 am #

    I’ve created a people directory search, but the name results are sorted by first name, last name by default. Is there a way to change the search results to sort by last name, first name?

Leave a Reply

%d bloggers like this: