I recently had a request from a customer we have implemented FAST Search for SharePoint 2010 for to include a couple of html meta tags on the search result pages. The reason for this is that they use webtrends in addition to SharePoint statistics to log site visits and queries searched for. A webtrends javascript is added to the end of the page. This script sends relevant information to a logging server somewhere else. We wanted to add two new metatags to the page, one for the current query, and one for the total results for this query.
Since the tags should be present on all search result pages, I investigated the page layout for all search result pages, located in \_layouts\masterpages\SearchResults.aspx. In the PlaceHolderPageTitle Contentplaceholder, the title of the page is set by using
<SEARCHWC:SearchTermFromUrl runat="server"/>
where SEARCHWC is registered in the page directive:
<%@ Register Tagprefix="SEARCHWC" Namespace="Microsoft.Office.Server.Search.WebControls" Assembly="Microsoft.Office.Server.Search, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
Now, displaying this value in a meta-tag is obviously a piece of cake. This can be done in the following way:
<meta name='query' content='<SEARCHWC:SearchTermFromUrl runat="server"/>' />
Getting the number of results for this query was a little harder to do. The first thing I did was investigating the Microsoft.Office.Server.Search.WebControls namespace (The .dll is in the 14-hive/ISAPI folder) by reverse engingeering it with Reflector. I found no similiar method to use to get the number of results.
Lazy as I am, I tweeted the almighty FAST for SharePoint guru Mikael Svenson (check out his blog and twitter), and asked if he had been into something similiar. He suggested to try
<meta name='num_hits' content='<%= SharedQueryManager.GetInstance(this.Page).QueryManager[0].TotalResultsIncludingDuplicates %>' />
where the SharedQueryManager represents the object that executes the query and returns the search results to the SharePoint Enterprise Search results Web Parts. (SharedQuerymanager on MSDN)
I tried this in my page layout, but I got an error which said “Code blocks are not allowed in this file”. I found this blogpost which explains the reason for this error. To fix this, I need to add a line to the PageParserPaths-element in the web.config of my web application. NB: This is generally not best practice!
I added the following line to the PageParserPaths-element:
<PageParserPath VirtualPath="/_catalogs/masterpage/SearchResults.aspx" CompilationMode="Always" AllowServerSideScript="true" />
I previewed the page layout, and eureka, I got a new error: An IndexOutOfBounds exception. Now this is obviously because I’m just previewing the site, not searching for anything (the QueryManager has no queries). I added some basic logic to avoid more errors, and imported the QueryManager in the Page Directive. Oh, and don’t forget that you can only have methods in the script block, because the script is executed at each rquest.
The end result looks like this:
<!-- Default page directives removed for simplicity --> <%@ Import Namespace="Microsoft.Office.Server.Search.Query" %> <script type="text/c#" runat="server"> public int getTotalHits() { QueryManager mgr = SharedQueryManager.GetInstance(this.Page).QueryManager; int numhits = 0; if (mgr!= null) { if (mgr.Count > 0) { numhits = mgr[0].TotalResultsIncludingDuplicates; } } return numhits; } </script> <!-- Default PlaceHolderTitle --> <asp:Content ContentPlaceHolderId="PlaceHolderPageTitle" runat="server"> <asp:literal runat="server" Text="<%$Resources:Microsoft.Office.Server.Search, Search_Results_Page_Title1%>"/> : <SEARCHWC:SearchTermFromUrl runat="server"/> </asp:Content> <asp:Content ContentPlaceHolderID="PlaceHolderAdditionalPageHead" runat="server"> <meta name='num_hits' content='<%= getTotalHits() %>' /><!-- This line is added --> <meta name='query' content='<SEARCHWC:SearchTermFromUrl runat="server"/>' /><!-- This line is added -->
Now, when I view the source code after a search, I can find in the head-seaction of the html-source:
<meta name='query' content='sharepoint' /> <meta name='num_hits' content='3692' />