Follow Us:
I recently got a request from a client that had a lot of employee engagement around blogging and they wanted to bring that front and center on their intranet home page. We were already rolling up an executive blog to the front page using the Content Query Web Part styled with some custom XSLT. They wanted it styled to look exactly the same, but using the CQWP again was out of the question since these employee blogs were coming from the user My Sites. The CQWP can’t roll content from other site collections, so we will use the new Search display templates in SharePoint 2013 to accomplish this goal of rolling all blog posts from across their environment.
If you don’t care about all this, you can download these files and try them out for yourself at the bottom of this post.
First, let’s talk about the structure of display templates. I’m not going to go into a huge amount of detail, that has already been covered on a great blog on Technet. There are two main files that control your display template and this example will update both of those. Essentially, there is a wrapper called Control_SearchResults.html that contains the global formatting and elements for all search results, and lots of files to style individual items. These files are all located in the Master Page gallery > Display Templates > Search folder. I recommend not modifying any of the original files, instead open one of the existing files and save as a new file. I typically do all of this work in SharePoint Designer.
The first thing to do is create a new wrapper file, so I saved Control_SearchResults.hml as a new file called Control_SearchResultsBlogSummary.html. (Creative, right?) Never edit the JavaScript files for your templates, SharePoint creates and maintains those as you edit your HTML file. I didn’t do too much to modify this template with the exception of taking almost all of it out. This is a very basic display and I don’t need much in the way of formatting or detailed info, I just need the title, employee image, and a summary of the post. So, this is what I ended up for the control template:
<html xmlns:mso="urn:schemas-microsoft-com:office:office" xmlns:msdt="uuid:C2F41010-65B3-11d1-A29F-00AA00C14882"> <head> <title>Blog Summary Result</title> <!--[if gte mso 9]><xml> <mso:CustomDocumentProperties> <mso:TemplateHidden msdt:dt="string">0</mso:TemplateHidden> <mso:MasterPageDescription msdt:dt="string">Displays the Search Results control.</mso:MasterPageDescription> <mso:ContentTypeId msdt:dt="string">0x0101002039C03B61C64EC4A04F5361F385106601</mso:ContentTypeId> <mso:TargetControlType msdt:dt="string">;#SearchResults;#</mso:TargetControlType> <mso:HtmlDesignAssociated msdt:dt="string">1</mso:HtmlDesignAssociated> <mso:HtmlDesignConversionSucceeded msdt:dt="string">True</mso:HtmlDesignConversionSucceeded> <mso:HtmlDesignStatusAndPreview msdt:dt="string">https://sharepoint.goodwillsp.org/_catalogs/masterpage/Display Templates/Search/Control_SearchResults_BlogSummary.html, Conversion successful.</mso:HtmlDesignStatusAndPreview> <mso:CrawlerXSLFile msdt:dt="string"></mso:CrawlerXSLFile> <mso:HtmlDesignPreviewUrl msdt:dt="string"></mso:HtmlDesignPreviewUrl> </mso:CustomDocumentProperties> </xml><![endif]--> </head> <body> <div id="Control_SearchResults"> <div class="ms-srch-result" id="Result" name="Control" style="margin-top:1px; width:280px;"> <div id="Groups" class="ms-srch-result-groups"> <!--#_ ctx.ListDataJSONGroupsKey = "ResultTables"; _#--> _#= ctx.RenderGroups(ctx) =#_ </div> </div> </div> </body> </html>
That dropped the file from over 300 lines down to about 35, so it is much easier to read. The only real thing I added to this file was the styling on the ms-srch-result div. It would have been just as easy to put in my custom CSS file, but for demo purposes, I left it inline. This file calls the template that you configure in your search results web part using the _#= ctx.RenderGroups(ctx) =#_ line, so you can modify this file as needed.
Next, I modified the Item_Discussion.html file to get my display template formatted for my blog roll. I started with that template because it already had most of what I needed in a format that looked pretty close to what I was after.
Again, I mostly stripped out what I didn’t need, but this time I did add some content back in. We needed to have the employee’s picture next to the post to make it a bit more interesting on the page. I’m sure there are better ways to do this using all the search tools, but I banged my head against it for a while and went the easy way. I’ll add in some of the code that is actually new for this file, and you can find the full files available for download below.
if (!$isEmptyString(ctx.CurrentItem.AuthorOWSUSER)) { author = Srch.U.getDisplayNameFromAuthorField(ctx.CurrentItem.AuthorOWSUSER); var userPersonaId = id + "_peopleUserPersona"; var authorUsername = Srch.U.getUsernameFromAuthorField(ctx.CurrentItem.AuthorOWSUSER); var authorPicUrl = "https://mysites.webApplication.com/User%20Photos/Profile%20Pictures/" + authorUsername.split("\\")[1] + "_MThumb.jpg"; authorPic = "<img src='" + authorPicUrl + "' style='width:70px;height:70px;float:left;margin:0 5px 5px 0;'>"; }
These lines get the current author from the search results, then just build a URL to the image library on the My Sites web application that stores the images. Since these are stored in a consistent manner based on username, this was the easiest way to go for me. Then, to add the output of that to our template, we just insert _#= authorPic =#_ into the HTML wherever you want the JavaScript variable to render.
<div>_#= authorPic =#_</div> <div id="_#= $htmlEncode(id + Srch.U.Ids.body) =#_"> <div id="_#= $htmlEncode(id + Srch.U.Ids.title) =#_" class="ms-srch-item-title"> <h3 class="ms-srch-ellipsis" style="padding-bottom:2px;"> <a clicktype="Result" id="_#= $htmlEncode(id + Srch.U.Ids.titleLink) =#_" href="_#= $urlHtmlEncode(ctx.CurrentItem.Path) =#_" style="font-size:15px;" title="_#= $htmlEncode(ctx.CurrentItem.Title) =#_" onfocus="_#= showHoverPanelCallback =#_"> _#= Srch.U.trimTitle(title, maxTitleLengthInChars, termsToUse) =#_ </a> </h3> </div>
There are variables in the JavaScript in this page to control how long the blog title and text teaser are, so they are pretty easy to adjust. Once these files are saved and published, it is time to configure the search web part to use them. Just add a Search Results web part to your page, and edit the properties. Open the Query Builder and add ContentType:Post Title<>"Welcome to my blog!" -ContentClass=urn:content-class:SPSPeople as the Query text. This will prevent the default “Welcome to My Blog” posts that everyone gets when a blog is created from showing up on your page.
Set the following options in the Display Templates section and click OK. If all goes according to plan, you should see a nicely formatted blog roll on your page. The options in the drop-down come directly from the <Title> element of your HTML files, so you can name them whatever you want. </p>
Feel free to download these files below. Just note that you will need to modify the URL to point to your My Site web application on line 79 of the Item_BlogSummary.html file.
Search Display Templates Download
For more information on C5 Insight or this blog entry, please Contact Us.
Nevermind, the string returned does not contain any slashes ("//") when retrieving the user name. There are two "|" characters. Once I get the email, I need to replace the . and the @ with _ for the picture URL to work. if (!$isEmptyString(ctx.CurrentItem.AuthorOWSUSER)) { author = Srch.U.getDisplayNameFromAuthorField(ctx.CurrentItem.AuthorOWSUSER); var userPersonaId = id + "_peopleUserPersona"; var authorUsername = Srch.U.getUsernameFromAuthorField(ctx.CurrentItem.AuthorOWSUSER); var authorEmail = authorUsername.split("|")[2]; var authorFormattedName = authorEmail.replace(/\./g,'_'); var authorFormattedName = authorFormattedName.replace("@","_"); var authorPicUrl = "https://betach1-my.sharepoint.com/User%20Photos/Profile%20Pictures/" + authorFormattedName + "_MThumb.jpg"; authorPic = ""; }
Kyle - My images are not showing up. If I check the url being of the broken images I get the following: https://my.sitename.com/User%20Photos/Profile%20Pictures/charlie.price_LThumb.jpg
Interesting, I assume if you put in https://my.sitename.com/User%20Photos/Profile%20Pictures/charlie_price_LThumb.jpg you will get a valid image? If that is the case, you could change authorUsername.split("\\")[1] to authorUsername.split("\\")[1].replace(".","_") and that should replace the period in your username with an underscore. I'm not sure why it didn't change that on its own though. If you go to your My Site, does it have the period in your username in the URL?
Kyle - that fixed the problem! Thanks a ton! No, our mysites don't have periods in them. That's why I was a little confused what was going on!
Thanks for posting this, I've been looking for a solution like this for a few days now. But I can't seem to get the image to display properly next to the post. I'm getting this for my thumbnail image URL: https://betach1-my.sharepoint.com/User%20Photos/Profile%20Pictures/undefined_MThumb.jpg I did not edit anything in the file besides the base url for this line: var authorPicUrl = "https://betach1-my.sharepoint.com/User%20Photos/Profile%20Pictures/" + authorUsername.split("\\")[1] + "_MThumb.jpg";
The HTML is... %div id="_#= $htmlEncode(userPersonaId) =#_" class="ms-srch-hover-postPersona"%%/div% Replace the % with the appropriate markup...sorry don't know how to get it to display properly here
One quick question on line 79 where the username is placed the script keeps altering my username for example Charlie.price gets rendered to Charlie_price Is there a way to have it keep the same format of my username?
Charlie, SharePoint automatically replaces periods in your username with underscores when it creates My Sites, etc because periods would mess up the URLs to your MySite. Are you displaying the username somewhere, or are your image links not working?
Thank you! The AuthorOWSUSER property was a life saver. I missed the getUsernameFromAuthorField in the post and opted for a regular expression to get the login name from the claims token. The regex I used to capture the login name is /#\.[w]\|.+\\(.+)$/ and could also be used to capture the domain name. Also I'm not sure if hardcoding the mysite url. There's a REST endpoint to get the profile picture url for a specific user that could be used to extract the base url (you'll need the domain name for this). Of course this would take the complexity of the display template to another level. The endpoint is /_api/SP.UserProfiles.PeopleManager/GetUserProfilePropertyFor(accountName=@v,propertyName='PictureURL')?@v='domain\loginname'
FYI, this is the code needed to render the full user details with hover over details (changed AssignedTo to whatever field it is)... In your script... var id = ctx.CurrentItem.id; var userPersonaId = id + "_peopleUserPersona"; var authorUsername = Srch.U.getUsernameFromAuthorField(ctx.CurrentItem.AssignedToOWSUSER); EnsureScriptFunc("searchui.js", "Srch.SSU", function() { AddPostRenderCallback(ctx, function() { Srch.SSU.renderPersona(authorUsername, userPersonaId); }); }); And then in the HTML... Hope this helps you or someone else. --TheKid
The complementary paper includes over 12 years of research, recent survey results, and CRM turnaround success stories.
Request Download
This 60-second assessment is designed to evaluate your organization's collaboration readiness.
Learn how you rank compared to organizations typically in years 1 to 5 of implementation - and which areas to focus on to improve.
This is a sandbox solution which can be activated per site collection to allow you to easily collect feedback from users into a custom Feedback list.
Whether you are upgrading to SharePoint Online, 2010, 2013 or the latest 2016, this checklist contains everything you need to know for a successful transition.