Sitefinity provides the ability to index all of your content so that it is easily searchable by your visitors. You can also partition the contents of the search into separate indexes based on the different content types, such as News, Blogs, Events, etc. However, what if you have multiple blogs but want your visitors to be able to limit their search to a single specific blog? That's the focus of today's post.
Sitefinity Publishing System
The backbone of this solution comes by making use of and customizing the Sitefinity Publishing System, which is the collection of components responsible for pushing and pulling data in and out of Sitefinity. The publishing system is comprised of two key components: Publishing Points, and Pipes. A full walkthrough of these components is beyond the scope of this post, but you can find more details about the different parts and how they are used in this article: Registering custom pipes in Sitefinity. Fortunately, the problem we want to solve doesn't involve creating or registering any custom pipes, because the Search system in Sitefinity already does this. Instead, we'll simply create a separate search index for each blog, then modify the default behavior to index a specific blog by specifying the individual blog’s id.
Create the Blogs
For this example I've created three simple blogs, each with a different number of posts so we can verify that the results we get are different for each index. I also created a separate page for each blog, to which we will later add the individual instances of the Search Box widget. These will point to their individual corresponding index, as well as to the Search Results page I also created. But first, we need to create the indexes so that they can be selected.
Create the Search Indexes
To keep things simple, I'm going to use the convention that the Search Index Title we create exactly matches the Title of the Blog which it will index. This means we need to create three indexes, one for each blog. When creating each index, be sure to select the Blog content to be indexed by checking only that box: Now we can go back to each individual blog page and add the Search Box widget, selecting the index that corresponds to the blog, as well as pointing them all to the search results page to view results. However, if we were to search any of the blogs now, it returns results from all three blogs, even though in this example we're specifying the Blog 1 index. This is, of course, expected behavior, because again by default, each index is configured to search the Blogs module as a whole. Now is where the real fun begins.
Modify the Default Search Pipe Settings
As I mentioned before, we don't need to create a custom pipe, or do any kind of registering of custom pipe settings or anything tricky like that, because Sitefinity already created and setup the pipes when we created each index. Instead, we need to iterate through all of the Pipe Settings that exist for the Content Type of BlogPost from each index that we created, and update it to only search the Blog that matches its name. We'll do this by simply creating a temporary WebForm page (like Test.aspx) and add the following code to the Page_Load method in the code behind:
protected void Page_Load(object sender, EventArgs e) { PublishingManager manager = PublishingManager.GetManager(PublishingConfig.SearchProviderName);
var blogs = App.WorkWith().Blogs().Get();
foreach (var blog in blogs)
{
// get matching blog search publishing point
var title = blog.Title.Value.ToString();
var publishingPoint = manager.GetPublishingPoints().FirstOrDefault(p => p.Name == title);
if (publishingPoint == null) continue;
// update the matching pipe settings, add the blog as a filter
var pipeSettings = publishingPoint.PipeSettings.FirstOrDefault(ip => ip.PipeName == ContentInboundPipe.PipeName && ((SitefinityContentPipeSettings)ip).ContentTypeName == typeof(BlogPost).FullName) as SitefinityContentPipeSettings;
pipeSettings.ContentLinks = new Guid[] { blog.Id };
manager.SaveChanges();
}
}
Basically what we're doing is first getting the PublishingManager that corresponds to the Search Index, whose name is exposed by the static PublishingConfig.SearchProviderName property. Next, we iterate through each blog in the Blogs module, and find a matching publishing point (that is, the Search Index) which has the name matching that blog's title, skipping any blogs that don't have a matching index. Now, because each search index exposes several pipe settings (one for each content type it can index in the checkboxes as shown in the image above), we need to make sure that we select the one that is of type ContentInboundPipe.PipeName (which is the generic content pipe) and also corresponds to the BlogPost type. Finally, we cast that pipe to the correct SitefinityContentPipeSettings so that we can access the ContentLinks property, which is an array of Guids that identify which blogs to index. In our case, we only want the id of the matching blog, which is what we pass to the array. Now we simply save changes, build, and run this temporary page once, so that each index can be permanently updated with the id of the blog it should search. One final important step to remember before searching is to first re-index each of the search indexes from the actions menu of each search index so that it can update its contest from its corresponding blog. Now at last, when searching the same individual blog index as before, we see that indeed we only get the results that correspond to that blog:
Wrapping Up
With a few lines of code and a simple naming convention, we were able to separate our blog content into separately indexable searches to help partition your content for your users. With simple modifications you could achieve many different setups, such as indexing multiple (but not all) blogs together to group results, as well as a separate "All Blogs" master index to search everything, giving you complete control over your search indexes. I hope this was helpful!
Enjoyed this post and/or found it useful?