Hierarchical titles vs. paged overviews
Every page should have a unique title. Unique titles can help you not only optimize your content for search engines but also improve the user experience. Hierarchical titles can help you make your page titles more usable but there is more to it if you’re using paged overviews. Find out how to generate unique titles for pages that use paged overviews in SharePoint 2010.
Hierarchical page title is a good title
Not that long ago I wrote about generating hierarchical titles in SharePoint 2010. I showed you how you can improve the user experience without too much content management hassle. By using hierarchical titles you can create more meaningful titles that not only provide search engines with more information about your content but also make it easier for your visitors to place the page in the context of your site.
Hierarchical title consists in most cases of the title of the page, followed by the title of the subsite followed by the title of the website, for example:
Super Bike 123 – Mountain Bikes – Adventure Work Bikes
Whenever your visitor opens a page with such title it’s instantly clear for him what the page content is about and how the page fits in the site. Hierarchical titles are quite clever and since they are generated automatically they don’t introduce any additional content management effort. There is however an exception.
What’s wrong with hierarchical titles?
Let’s take a look at a paged overview such as the overview of blog posts on our new website.
If you look at the title of the page, you won’t see anything odd: it’s a proper hierarchical title.
When you however go to the second page of the overview, you will see, that although the URL of the page and its contents have changed, the title is the same!
Because paging is being done on the same page, the standard hierarchical title uses the same title for every page. Ideally you would want the page title to include the page number such as Blog page 2 – Mavention.
Extending hierarchical page title with support for paging
Before we start extending the hierarchical page title with support for paging information, let’s have a quick look at the control responsible for generating hierarchical titles.
Setting up the baseline
public class SimpleHierarchicalPageTitle : Control
{
public string Separator { get; set; }
public bool Reversed { get; set; }
protected List<string> TitleParts = new List<string>(3);
protected override void CreateChildControls()
{
base.CreateChildControls();
bool isHomePage = false;
using (new SPMonitoredScope("Retrieving title parts (SimpleHierarchicalPageTitle)"))
{
using (new SPMonitoredScope("Root Web title"))
{
TitleParts.Add(SPContext.Current.Site.RootWeb.Title);
}
using (new SPMonitoredScope("Site title"))
{
if (!SPContext.Current.Web.IsRootWeb)
{
TitleParts.Add(SPContext.Current.Web.Title);
}
}
using (new SPMonitoredScope("Page Title"))
{
isHomePage = Path.GetFileName(SPContext.Current.File.Url).Equals("default.aspx", StringComparison.InvariantCultureIgnoreCase);
if (!isHomePage)
{
TitleParts.Add(SPContext.Current.ListItem[SPBuiltInFieldId.Title] as string);
}
}
}
}
protected override void Render(HtmlTextWriter writer)
{
if (TitleParts.Count > 0)
{
if (Reversed)
{
TitleParts.Reverse();
}
writer.Write(HttpUtility.HtmlEncode(String.Join(Separator, TitleParts.ToArray())));
}
}
}
This is the control we will use as a starting point for adding support for paging.
Paging here paging there…
Depending on the structure and functionality of your site you might have one or more paged overviews. Ideally they would use the same paging parameter, but since we don’t live in an ideal world, it’s better to take into account that multiple paging parameters can be used throughout the site. So the first thing to do is to extend the control with a property that will allow us to store the list of all the different paging parameters:
public class SimpleHierarchicalPageTitle : Control
{
public const string PagingParametersSeparator = ",";
public string PagingParameters { get; set; }
...
}
Using the PagingParameters property we can store the all the paging parameters that we use on our website. Also note that we configured the parameters separator to , (comma).
Including the page number in the page title
The next thing is to specify some kind of configuration capability for including the information about the current page in the hierarchical title. You can imagine that different customers might have different requirements for this part so you definitely want this to be configurable.
Defining a formatting pattern might give you the most flexibility, so let’s extend our control with one more property that will allow us to define the formatting pattern:
public class SimpleHierarchicalPageTitle : Control
{
...
/// <summary>
/// String for formatting the title of a page with paging, eg. {1} page {0}
/// </summary>
/// <remarks>
/// {0} - page number<br/>
/// {1} - page title
/// </remarks>
public string PagingString { get; set; }
...
}
As you can read in the description of the PagingString property, the formatting pattern should contain two placeholders: one for the page number and one for the page title. Such formatting pattern gives you the possibility of having virtually any page title format that your customer might ask for.
Having the base properties in place, we can proceed with retrieving the paging information from the query string and including it in the page title.
Retrieving the page number from the query string
In most scenarios paged overviews are based on a query string parameter. This allows your visitors to send the link to other people to point them to specific content. Knowing that we can use the following method to retrieve the page number from the query string and make it available to our control:
protected virtual int GetCurrentPage()
{
int currentPage = 0;
using (new SPMonitoredScope("Simple paging"))
{
if (!String.IsNullOrEmpty(PagingParameters))
{
string[] pagingParameters = PagingParameters.Split(new string[] { PagingParametersSeparator }, StringSplitOptions.RemoveEmptyEntries);
foreach (string pagingParameter in pagingParameters)
{
string pageNumber = Page.Request.QueryString[pagingParameter];
if (!String.IsNullOrEmpty(pageNumber) && Int32.TryParse(pageNumber, out currentPage) && currentPage > 1)
{
break;
}
}
}
}
return currentPage;
}
Given that we allow using different paging parameters, we first have to get a list of all the different query string parameters that we support. We do this by splitting the value of the PagingParameters property. Then we step through all those parameters and check if they are set and if so, if the value is a valid number greater than 1.
You might have noticed that I marked the GetCurrentPage method as virtual. I did this on purpose which I will explain later on. As for now it’s sufficient to say that the GetCurrentPage method will search query string parameters for known paging parameters and if it finds one, it will try to retrieve the current page information from it.
Adding paging information to the title
The last thing left to be done is to include the paging information in the title of the page. We can do this as follows:
protected override void Render(HtmlTextWriter writer)
{
if (TitleParts.Count > 0)
{
using (new SPMonitoredScope("Paging information"))
{
if (!String.IsNullOrEmpty(PagingString))
{
int currentPage = GetCurrentPage();
if (currentPage > 1)
{
string pageTitle = TitleParts[TitleParts.Count - 1];
pageTitle = String.Format(PagingString, currentPage, pageTitle);
TitleParts[TitleParts.Count - 1] = pageTitle;
}
}
}
if (Reversed)
{
TitleParts.Reverse();
}
writer.Write(HttpUtility.HtmlEncode(String.Join(Separator, TitleParts.ToArray())));
}
}
First we ensure that the formatting pattern for including paging information in the title has been set. Then we retrieve the number of the current page using the previously defined GetCurrentPage method. If the page is greater than 1 we add the page information to the title.
As you remember in the CreateChildControls method we have obtained all the different parts of the hierarchical URL such as the title of the website, current subsite and current page. Depending on where the visitor is on the site currently some of that information might not be able. The good news is, that the last part of the URL, which represents the current page, is the part to which we want to add the paging information.
Simple paging information in the hierarchical URL
Having everything in place let’s check out the results:
As you can see the title of the overview changes as you move through the pages. There is however one more thing that you should take into account.
That one more thing aka. dealing with search results
Depending on your website you might be using one or more paged overviews. And while our control has been created to support all types of overviews with their own paging parameters, there is one more paged overview that you should take into account, if you’re using SharePoint search that is: the search results page.
If you try to search for something on our site (let’s search for producten** as it returns more results than fit on a single page) you will see that the hierarchical control doesn’t really support that kind of paging.
The reason for this is, that instead of the page number, the search results page uses the start record number to determine which page it should display. So even if we added the start parameter to our list of supported parameters, it wouldn’t do much good. The good news is, that we took this possibility into account already (we’ve marked the GetCurrentPage method as virtual, remember?) so it’s not that hard for us to add support for including the paging information from the search results page in the page title.
Depending on your customer you might or might not be using SharePoint search on your website. Since customer requirements are different for different solutions, it’s good to develop for flexibility, so that you will able to support all the different scenarios. For that reason I decided to separate the hierarchical title control with support for simple paging from the one with support for search results paging.
Extending hierarchical title with support for search results paging
Let’s start off with creating a new control that inherits from our previously created hierarchical title control:
public class HierarchicalPageTitle : SimpleHierarchicalPageTitle
{
}
While you might want to start by parsing the query string yourself, just like we did previously, there is a better – more reliable way of dealing with the paging information for the search results page. For this you will need a reference to the Microsoft.Office.Server.Search assembly.
Since we made the GetCurrentPage method virtual, the only thing that we need to do is to override its implementation in the HierarchicalPageTitle control:
public QueryId QueryId { get; set; }
protected override int GetCurrentPage()
{
int currentPage = 0;
using (new SPMonitoredScope("Search paging"))
{
QueryManager queryManager = SharedQueryManager.GetInstance(Page, QueryId).QueryManager;
if (queryManager != null)
{
LocationList list = null;
foreach (LocationList item in queryManager)
{
if (item != null)
{
list = item;
break;
}
}
if (list != null && list.ReturnedResults > 0)
{
currentPage = (list.StartItem / list.ItemsPerPage) + 1;
}
}
}
if (currentPage == 0)
{
currentPage = base.GetCurrentPage();
}
return currentPage;
}
As you might know, SharePoint search allows you to configure different query IDs for your search queries. If you’re using it in your solution, you can configure the right query ID to obtain the paging information from using the QueryId property. In all other scenarios you can stick with the default value which is set to QueryId.Query1 which happens to be default value used by the Search Results Web Part.
In order to retrieve the paging information from the search result, we need to retrieve the QueryManager first. We can do this using the SharedQueryManager.GetInstance method. The next step is to retrieve the LocationList which contains the information about returned results. Once we have it, we can check if any results have been returned and if so, calculate the page number.
**Important **As you can remember, although we obtained the different parts of the hierarchical title in the CreateChildControls method, we explicitly moved retrieving paging information to the Render method of our control. The reason for this is, that if you retrieved the value of the LocationList.ReturnedResults property in the CreateChildControls method, it would return 0. Because the information about search results is not available that early in the page lifecycle, we have to move the call to the GetCurrentPage method further down the execution pipeline.
In case no QueryManager is found (meaning the visitor is not on a search results page), we fall back to the previous implementation of the GetCurrentPage method which will try to retrieve the paging information from the query string.
Having that set, let’s check out the search results page. If you navigate to the second page of the search results, the paging information will appear in the page title just as it did on the blog overview:
And that’s all. Using just a few lines of codes we extended our hierarchical title to provide information about paging for multipage overviews and search results. And with that we have created a proper hierarchical title with support for paged overviews!
Technorati Tags: SharePoint 2010,Web Content Management