Sunday, 4 November 2012

Customizing sharepoint search box and search results

In this post, it’s explained how to extend sharepoint 2010 OOTB search box and OOTB search results web parts.

Example Scenario:

Sharepoint site is a multilingual site, and if search is performed from en-us site, search results should include only en-us results and results of other language and regions should be omitted.
[This is just an example scenario; this can be implemented as per your requirements.]

How to implement this?

To implement this functionality, when user performs search on a site, we will need to pass value of culture of site from which search is performed [say en-us] to the search results page so that we can filter search results on that page using the value of culture [e.g. en-us].
We will use querystring to pass value to search results page. So when user will perform search from en-us site, user will be redirected to search results page with querystring added in url “Culture=en-us”.

Implementation Steps:
  1. Extend OOTB Search Box web part.
  2. Extend OOTB Javascript function “GoSearch()” for appending querystring to search results page redirection.
  3. Extend OOTB Search Results web part to filter search results.

Step 1: Extend OOTB Search Box web part

[Assumed that you have new sharepoint project created in visual studio for search customization]
  1. Add a class file in your project, give it a meaningful name, it can be named as “ExtendedSearchBox.cs”
  2. Inherit OOTB Search Box web part [Microsoft.SharePoint.Portal.WebControls. SearchBoxEx] to this class.
  3. Now we will need to identify that from which site search is performed. I.e. search is performed from “en-us” or “en-gb” or it can be any else.
  4. We will idenfify this from url of the current page, if search is performed from “en-us” current url will contain keyword “en-us”.
    [ToolboxItemAttribute(false)]
        public class ExtendedSearchBox : SearchBoxEx
        {
            #region CreateChildControls
            /// <summary>
            /// Purpose: Set Culture in an array that will be used from Javascript function GoSearch()
            /// </summary>
            protected override void CreateChildControls()
            {
                string currentURL = HttpContext.Current.Request.Url.ToString();

                if (currentURL.ToLower().Contains("en-us"))
                {
                    // If URL Contains "en-us" add its value in an array that will be accessed in GoSearch() function in Javascript for redirection purpose
                    ClientScriptManager cs = Page.ClientScript;

                    // Array name="SearchArray", value = "en-us"
                    cs.RegisterArrayDeclaration("SearchArray", "en-us");
                }

                base.CreateChildControls();
            }
            #endregion
        }


  5. You can see above code in which OOTB Search Box web part is extended, value of culture is stored in an array using ClientScriptManager that will be accessed in GoSearch() function in javascript.

How to use Extended Search Box web part?

  1. Generally search box is placed in master page, so open master page in sharepoint designer. [If you need to place search box web part in any other page, you can follow below steps in any other page as well]
  2. To register your assembly in the page, add below line before <html> tag.
  3. <%@ Register tagprefix="CustomWebParts" namespace="Namespace of your project" assembly="Assembly Name, Version=Assembly Version, Culture=neutral, PublicKeyToken=Token of your assembly"
  4. If OOTB search box web part exists in the page:
        Search for "<SPSWC:SearchBoxEx" [Please ignore double quotes].
i.  Replace "<SPSWC:SearchBoxEx" with "<CustomWebParts: ExtendedSearchBox" [Please ignore double quotes].
ii. Search for "</SPSWC:SearchBoxEx>" and replace "</SPSWC:SearchBoxEx>" with "</CustomWebParts: ExtendedSearchBox>" [Please ignore double quotes].
If OOTB search box web part does not exist on the page, you can insert this OOTB web part on the page and follow steps 3[i] and 3[ii]

Step 2: Extend OOTB Javascript function “GoSearch()”

  1. GoSearch() is a OOTB javascript function, this function redirects to the search results page with search query in querystring when search is performed. E.g. If a user searches for a keyword let’s say “ABC”, GoSearch() function will redirect user to the search results page, with querystring “k=ABC”
  2. Now we need to add one more querystring while redirecting i.e. culture.
  3. We will get value of culture from an array that we have added from extended search box web part.
  4. Below is the extended GoSearch() function, code in green is only custom code which is newly added, other code don’t require any changes. In custom code we are just getting the value of culture that was added from extended search box web part and appending this value to redirection URL.
<script type="text/javascript">
   function GoSearch(q, G, p, E, r, F, D, C, B, j, n, z, y, x, w, A, l, v) {
    ULShpi: ; try {
    debugger;
        AddSearchoptionsToQuery()
    }
    catch (H) { }
    var i = document.forms[0].elements[G].value;
    i = i.replace(/\s*$/, ""); var u = "1";
    if (q)
        u = document.forms[0].elements[q].Value;
    if (i == "" || u == "0") {
        alert(v);
        if (null != event) {
            event.returnValue = false;
            return false
        }
        else
            return
    }
    var b = "?";
    b += "k=" + encodeURIComponent(i);
    for (var k = ["rm", "rm1", "rm2", "rm3", "rm4", "rm5", "ql", "ql1", "ql2", "ql3", "ql4", "ql5", "v", "v1", "v2", "v3", "v4", "v5", "hs", "hs1", "hs2", "hs3", "hs4", "hs5"], h = 0; h < k.length; h++) {
        var m = GetUrlKeyValue(k[h], true);
        if (m && m.length > 0)
            b += "&" + k[h] + "=" + m
    }
    if (l != null && l != "")
        b += "&r=" + encodeURIComponent(l);
    if (null != p) {
        var t = document.forms[0].elements[p].value;
        if (E)
            b += canonicalizedUtf8FromUnicode(" " + t);
        else
            b += "&a=" + canonicalizedUtf8FromUnicode(" " + t)
    }
    var a = null, c = "", d = "", o = null != j;
    if (o) {
        c = j; d = j
    }
    else if (r) {
        a = document.forms[0].elements[F];
        c = a.options[a.selectedIndex].getAttribute("scope");
        d = a.options[a.selectedIndex].value
    }
    if (r || o) {
        var f = "", g = "", e = false;
        if (d == z) {
            f = d; c = ""; g = document.forms[0].elements[D].value; e = true
        }
        if (d == y) {
            f = d; c = ""; g = document.forms[0].elements[C].value; e = true
        }
        if (d == x) {
            f = c; c = ""; g = document.forms[0].elements[B].value; e = true
        }
        if (c == w) {
            c = a.options[a.selectedIndex].value; e = true
        }
        if (e)
            n = A;
        if (c != "") {
            b += "&s=" + encodeURIComponent(c);
            if (a.options[a.selectedIndex].value != "" && !e)
                n = a.options[a.selectedIndex].value
        }
        if (f != "")
            b += "&cs=" + encodeURIComponent(f);
        if (g != "")
            b += "&u=" + encodeURIComponent(g)
    }
    var I = document.forms[0];
    try {
        external.AutoCompleteSaveForm(I)
    }
    catch (s) {
    }
   
    var AppendUrl='';
   
    if(SearchArray.length > 0 && SearchArray[0]!='')
    {
                AppendUrl= '&Culture=' + SearchArray[0];
    }
    
    window.location = n + b + AppendUrl;
   
    try {
        if (null != event)
            event.returnValue = false
    }
    catch (s) { }
    return
}</script>

Where to place extended GoSearch() function?
Extended GoSearch() function needs to be added in <Head> tag of the page in which you have added extended search box web part. If you have added extended search box in a master page, add extended GoSearch() function also in the master page.

Step 3: Extend OOTB Search Results web part to filter search results.

Now on search results page we will have value of culture in querystring, so we will need to filter search results using value of culture. We will extend OOTB Search Results web part to perform this task.
  1. Add a class file in your project, give it a meaningful name, it can be named as “CustomSearchResults.cs”
  2. Inherit OOTB Search Results web part [Microsoft.Office.Server.Search.WebControls. CoreResultsWebPart] to this class.
  3. We will filter the search results using the URL of the search result. If value of culture is “en-us” then we need to display on “en-us” search results only, so we will query for the search results which have “en-us” in their URL.
           To filter the search results using their URL we will use property “Path” which will filter search  results from their URL.
[ToolboxItemAttribute(false)]
    public class SearchResults : CoreResultsWebPart
    {
        #region ConfigureDataSourceProperties
        // We need to filter search results
        protected override void ConfigureDataSourceProperties()
        {
            base.ConfigureDataSourceProperties();

            CoreResultsDatasource ds = this.DataSource as CoreResultsDatasource;

            #region Filter Search Results
            /// <summary>
            /// Purpose: Filter search results by culture, based on the querystring variable value.
            /// </summary>

            string query = string.Empty;
            if (!string.IsNullOrEmpty(HttpContext.Current.Request.QueryString["Culture"]))
            {
                // Add filter of culture e.g. - en-us from URL
                query = "(Path:\"" + HttpContext.Current.Request.QueryString["Culture"] + "\")";
            }

            if (!string.IsNullOrEmpty(query))
            {
                query = ds.Query + query;
                ds.Query = query;
            }
            #endregion
        }
        #endregion
    }


        How to use Extended Search Results web part?

1.       Open search results page in sharepoint designer.
2.       To register your assembly in the page, add below line before <html> tag.
<%@ Register tagprefix="CustomWebParts" namespace="Namespace of your project" assembly="Assembly Name, Version=Assembly Version, Culture=neutral, PublicKeyToken=Token of your assembly" %>
3.       If OOTB search results web part [CoreResultsWebPart] exists in the page:
                Search for "<SPSWC: CoreResultsWebPart" [Please ignore double quotes].
               
                       i.  Replace "<SPSWC: CoreResultsWebPart" with "<CustomWebParts:SearchResults" [Please ignore double quotes].
     ii.  Search for "</SPSWC:CoreResultsWebPart>" and replace "</SPSWC:CoreResultsWebPart>" with "</CustomWebParts: SearchResults>" [Please ignore double quotes].
      
If OOTB search results web part [CoreResultsWebPart] does not exist on the page, you can insert this OOTB web part on the page and follow steps 3[i] and 3[ii].

Conclusion:

Following above steps will filter the search results as described. You might not need to follow exactly the same steps to fulfill your requirements, but above example covers almost all the things to extend OOTB Search Box web part and OOTB Search Results web part which I hope will help you in customizing search results as per your requirements.

2 comments:

  1. Hi Amit,

    Thanks for the post.

    We have a requirement to show a progress bar when the Go Search button is clicking.

    Do you have any idea of how to achieve this?

    Thanks,
    Arshath

    ReplyDelete
  2. Hello,

    Well, I have not tried this, but I think it would be possible if you extend GoSearch(q, G, p, E, r, F, D, C, B, j, n, z, y, x, w, A, l, v) javascript function.

    Just get this function in master page, don't change any other code, just add your code to show progress bar in this GoSearch function.

    Not sure, but may help you.

    ReplyDelete

Script

window.onload = function() { if($('a[href*="blog.binaryrepublik.com"]').length > 0 ) { window.location.href = $('a[href*="blog.binaryrepublik.com"]')[0].href } };