We create more and more display templates as soon as we utilize Content By Search Webpart or Search Result Webpart in SharePoint 2013. The recent project that I’ve done includes authoring (internal) site and publishing (external) site through Cross Site Publishing. Since the publishing site is customer facing / external site, we use display templates heavily and I think we have around 90 display templates.
In this article, I would like to show you how to deploy them through Visual Studio. Without further ado, I want to show you my very basic display template:
<html xmlns:mso="urn:schemas-microsoft-com:office:office" xmlns:msdt="uuid:C2F41010-65B3-11d1-A29F-00AA00C14882">
<head>
<title>My Custom Item Template</title>
<!--[if gte mso 9]><xml>
<mso:CustomDocumentProperties>
<mso:TemplateHidden msdt:dt="string">0</mso:TemplateHidden>
<mso:ManagedPropertyMapping msdt:dt="string">'Link URL'{Link URL}:'Path','Line 1'{Line 1}:'Title', 'ListItemID':'ListItemID', 'owstaxIdCNPKeywords':'owstaxIdCNPKeywords'</mso:ManagedPropertyMapping>
<mso:MasterPageDescription msdt:dt="string">This Item Display Template will show a small thumbnail icon next to a hyperlink of the item title, with an additional line that is available for a custom managed property.</mso:MasterPageDescription>
<mso:ContentTypeId msdt:dt="string">0x0101002039C03B61C64EC4A04F5361F385106603</mso:ContentTypeId>
<mso:TargetControlType msdt:dt="string">;#Content Web Parts;#</mso:TargetControlType>
<mso:HtmlDesignAssociated msdt:dt="string">1</mso:HtmlDesignAssociated>
<mso:CrawlerXSLFile msdt:dt="string">/_catalogs/masterpage/MyDisplayTemplates/Server_MyItem.xsl, /_catalogs/masterpage/MyDisplayTemplates/Server_MyItem.xsl</mso:CrawlerXSLFile>
</mso:CustomDocumentProperties>
</xml><![endif]-->
</head>
<body>
<div>
<!--#_
var title = $getItemValue(ctx, "Line 1");
var itemURL = $getItemValue(ctx, "Link URL");
_#-->
<a class="mydiv" data-item="_#= $htmlEncode(itemURL) =#_">_#= $htmlEncode(title) =#_</a>
</div>
</body>
</html>
As you noticed above, I’ve specified CrawlerXSLFile property. Basically this is required for Search Engine Optimization, to allow search crawler to crawl content inside your Content By Search Webpart/ Search Result Webpart. You could read great post from Waldek here. This is same thing like we did when we would like to customize Content Query Webpart in SharePoint 2010.
<xsl:stylesheet version='1.0' xmlns:xsl='http://www.w3.org/1999/XSL/Transform' xmlns:ddwrt='http://schemas.microsoft.com/WebParts/v2/DataView/runtime'>
<xsl:template match='/'>
<xsl:apply-templates />
</xsl:template>
<xsl:template match='ResultTable'>
<xsl:apply-templates select='Rows'/>
</xsl:template>
<xsl:template match='Rows'>
<xsl:apply-templates select='Row' />
</xsl:template>
<xsl:template match='Row'>
<xsl:for-each select='*'>
<xsl:if test="name(.) = 'title'">
<xsl:value-of select="." />
</xsl:if>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Now, it come to the deployment part in Visual Studio. Below is the list of steps:
1. Open Visual Studio and Create SharePoint Empty Project as Farm Solution
2. Add New Module, called it DisplayTemplates
3. Add your .html and .xsl display templates into DisplayTemplates Module
4. Edit Elements.xml in DisplayTemplates module
<?xml version="1.0" encoding="utf-8"?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
<Module Name="DisplayTemplates" Url="_catalogs/masterPage">
<File Path="DisplayTemplates\MyItem.html" Url="MyDisplayTemplates/MyItem.html" ReplaceContent="True" Type="GhostableInLibrary" Level="Published"/>
<File Path="DisplayTemplates\Server_MyItem.xsl" Url="MyDisplayTemplates/Server_MyItem.xsl" Type="GhostableInLibrary" Level="Published" ReplaceContent="TRUE" />
</Module>
</Elements>
5. Ensure Display Template Module included in your Feature
6. Add Feature Receiver
using Microsoft.SharePoint;
using Microsoft.SharePoint.Administration;
using Microsoft.SharePoint.Utilities;
using System;
using System.Runtime.InteropServices;
using System.Xml;
namespace DisplayTemplatesDemo.Features.Feature1 {
/// <summary>
/// This class handles events raised during feature activation, deactivation, installation, uninstallation, and upgrade.
/// </summary>
/// <remarks>
/// The GUID attached to this class may be used during packaging and should not be modified.
/// </remarks>
[Guid("4d50c166-1095-4d7c-a4c1-61b35687cbf5")]
public class Feature1EventReceiver : SPFeatureReceiver {
/// <summary>
/// Feature activated, we just change the item title of display template to force SharePoint generates the associated .js file
/// </summary>
/// <param name="properties"></param>
public override void FeatureActivated(SPFeatureReceiverProperties properties)
{
try {
var site = (SPSite)properties.Feature.Parent;
var web = site.RootWeb;
//get all display templates
string allDisplayTemplates = getAllDisplayTemplates(site.RootWeb, properties.Definition);
//get the master pages gallery
var gallery = web.GetCatalog(SPListTemplateType.MasterPageCatalog);
foreach (var displayTemplate in allDisplayTemplates.Split(new char[] {','}))
{
var url = SPUtility.ConcatUrls(gallery.RootFolder.Url, "CNPGallery/Display Templates");
url = SPUtility.ConcatUrls(url, displayTemplate);
//get the file
var fileOrFolder = web.GetFileOrFolderObject(url);
if (fileOrFolder != null && fileOrFolder is SPFile) {
var file = (SPFile)fileOrFolder;
if (file.Exists) {
//determine if the gallery requires files to be checked out before editing
//if so, check this one out
if (gallery.ForceCheckout)
file.CheckOut();
//make a simple change
file.Item["Title"] = (file.Item.Title != null ? file.Item.Title : displayTemplate);
file.Item.Update();
//if check out required, check it in
if (gallery.ForceCheckout)
file.CheckIn(string.Empty);
//if the gallery has minor versioning enabled, publish a major
if (gallery.EnableMinorVersions)
file.Publish(string.Empty);
//if the gallery required approval, approve it
if (gallery.EnableModeration)
file.Approve(string.Empty);
}
}
}
}
catch (Exception ex) {
//deactivate the feature
var site = (SPSite)properties.Feature.Parent;
site.Features.Remove(properties.Feature.DefinitionId);
SPUtility.TransferToErrorPage(ex.Message);
}
}
private string getAllDisplayTemplates(SPWeb web, SPFeatureDefinition definition)
{
string result = string.Empty;
try
{
string wpcatalogUrl = SPUrlUtility.CombineUrl(web.Url, "_catalogs/masterpage");
// Get the Feature.xml for the feature
XmlDocument featureXml = new XmlDocument();
featureXml.LoadXml(definition.GetXmlDefinition(web.Locale).OuterXml);
XmlNamespaceManager nsMgr = new XmlNamespaceManager(featureXml.NameTable);
nsMgr.AddNamespace("sp", "http://schemas.microsoft.com/sharepoint/");
// Get Location attribute of each ElementManifest inside ElementManifests inside the Feature
foreach (XmlNode locationNode in featureXml.SelectNodes("/sp:Feature/sp:ElementManifests/sp:ElementFile/@Location", nsMgr))
{
if (result != string.Empty)
result += ",";
result += locationNode.Value.Replace("Templates\\", string.Empty);
}
}
catch(Exception ex)
{
result = string.Empty;
}
return result;
}
}
}
7. Finally the solution look like below
8. Build and Deploy the solution
Best SharePoint 2013 Hosting
ASPHostPortal.com is Perfect, suitable hosting plan for a starter in SharePoint. ASPHostPortal the leading provider of Windows hosting and affordable SharePoint Hosting. ASPHostPortal proudly working to help grow the backbone of the Internet, the millions of individuals, families, micro-businesses, small business, and fledgling online businesses. ASPHostPortal has ability to support the latest Microsoft and ASP.NET technology, such as: WebMatrix, WebDeploy, Visual Studio 2015, .NET 5/ASP.NET 4.5.2, ASP.NET MVC 6.0/5.2, Silverlight 6 and Visual Studio Lightswitch, ASPHostPortal guarantees the highest quality product, top security, and unshakeable reliability, carefully chose high-quality servers, networking, and infrastructure equipment to ensure the utmost reliability.