skip to Main Content

Customising the Content Search Web (Part 4): Packaging & Deployment in Visual Studio

This is the final post in a series I have been writing on the Content by Search Web Part (aka CSWP):

  1. What you get in the box
  2. Custom Display Templates with JavaScript
  3. Going Old Skool with XSLT
  4. Packaging & Deployment in Visual Studio (this post)

So in this final post we will be looking at how your Content Search Web Parts can be deployed as WSP packages in Visual Studio.

The first thing you will need to decide is:


| Do you deploy the HTML Designer File? Or just the final JS file? |


This was triggered by a discussion I had with Chris O’Brien (@ChrisO_Brien) when we got talking about Content Search Web Parts and what the best approach was for deploying them.

In my opinion it really comes down to what environment you are deploying to, and whether the admin / power users will need to have access to a (much easier to modify) designer file.

Deploying the JS File

This is definitely the easiest approach as it doesn’t really involve anything too complicated. You would still start off with your HTML Designer file and deploy it to your DEV box, but you would then extract the compiled JS file and drop THAT file into Visual Studio.

You can then deploy it using a standard Module element.

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

<Elements xmlns=””>

<Module Name=”MJHDisplayTemplates” Url=”_catalogs/masterpage/Display Templates/Content Web Parts” Path=”MJH Display Templates” RootWebOnly=”TRUE”>

<File Url=”Item_MJHSummary.js” Type=”GhostableInLibrary” />



Deploying the HTML Designer File

This is a little bit more tricky. The main problem is that the JS file is compiled “on the fly” by an SPItemEventReceiver in the Master Page and Page Layouts Gallery. Of course, event receivers do not get fired when a file is dropped in from a module from a feature, so you basically need to go and give SharePoint a prod to make it “do its thing”.

My approach is to use a Feature Receiver to “touch” the file (which prompts the event receiver to fire) so that your JS file is then compiled.

In order to make this more dynamic we will inject the Feature ID as a property of the SPFile which is actually provisioned by the module. Thankfully this is a relatively easy thing to achieve.

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

<Elements xmlns=””>

<Module Name=”MJHDisplayTemplates” Url=”_catalogs/masterpage/Display Templates/Content Web Parts” Path=”MJH Display Templates” RootWebOnly=”TRUE”>

<File Url=”Item_MJHSummary.html” Type=”GhostableInLibrary”>

<Property Name=”FeatureId” Value=”$SharePoint.Feature.Id$” Type=”string”/>




The trick then is to have a Feature Receiver which looks for all of the files which have that property and modify the file in some way (I just pull the file bytes and push it back again, basically uploading a duplicate copy of the file, just calling SPListItem.Update() or SPFile.Update() didn’t seem to work!).

string featureId = properties.Feature.Definition.Id.ToString();

SPSite site = properties.Feature.Parent as SPSite;

SPFolder displayTemplateFolder = rootWeb.GetFolder(“_catalogs/masterpage/Display Templates/Content Web Parts”);



SPList parentList = folder.ParentWeb.Lists[folder.ParentListId];


SPFileCollection files = folder.Files;

var templateFiles = from SPFile f

in files

where String.Equals(f.Properties[“FeatureId”] as string, featureId, StringComparison.InvariantCultureIgnoreCase)

select f;


List<Guid> guidFilesToModify = new List<Guid>();

foreach (SPFile file in templateFiles)





foreach (Guid fileId in guidFilesToModify)


// instantiate new object to avoid modifying the collection during enumeration

SPFile file = parentList.ParentWeb.GetFile(fileId);


// get the file contents

byte[] fileBytes = file.OpenBinary();


// re-add the same file again, forcing the event receiver to fire

folder.Files.Add(file.Name, fileBytes, true);



So in the above code sample (which is inside a “Feature Activated” method) we are retrieving the Feature ID for the feature which is activating. We then proceed to the folder where we provisioned our files and did a simple query to pull out those files which have the feature ID in their properties (which we set in our module above).

We then pull the binary data of the file as a Byte Array, and then push exactly the same file back into the folder (which triggers the event receiver to fire).

And that should be all you need!

By Martin Hatch, Associate Principal SharePoint Consultant

About the Author

Our technical team contribute with blogs from their respective specialities, be that Azure, SQL, BizTalk, SharePoint, Xamarin and more. From the lead architect to developers and testers, each person provides content straight from their experience.

Back To Top
Contact us for a chat