Share via


SharePoint 2013: Yammer Search Deep integration with SharePoint search

Introduction

As I have mentioned previously in my article that Yammer is the future enterprise social platform for SharePoint. People around the world have already started integrating yammer with SharePoint using either Web Part or Embed feeds.  Using REST api’s are also another approach. And for those who have switched to SharePoint 2013, they have Yammer Apps to integrate. On SharePoint Online you have the option to choose between Newsfeed and Yammer. So in my previous article I explained how to use Yammer web part and embed codes to display yammer feeds in SharePoint environment. In this article we will see deep integration of yammer search with SharePoint Search.

Case Statement

Now what comes first in my mind when I want to show yammer search along with the SharePoint search? It’s no other than Yammer web part, right? Yes you can place this web part on the SharePoint search result page and can see the yammer search results for the entered key word. But the limitation of this approach is that yammer result gets displayed separately and there is no categorization in Yammer results like we have in SharePoint search (Everything, People, etc ).

 

But let’s say the requirement comes like below:

Yammer is integrated with SharePoint 2013. We want to set up search like when end user starts to use search module the results should be displayed like below on search result page:

Everything tab: it should display everything from SharePoint as normal.

People tab: It should display users from the Yammer profile.

Conversation tab: It should display conversation or feeds from the Yammer.

So now the question will come into your mind that how can I achieve this? So here comes Yammer REST API to help you. 

Yammer REST API Concept

As like other social applications Yammer provides REST API for the custom development. They have opened some endpoints to interact with Yammer; those are: messages, groups, users, notifications, Suggestions, subscriptions, autocomplete, Invitations, networks and last but important: Search.

What you need to use the REST API is nothing but the ‘aapID’ and successful authentication of user. You can get more information about appID on Yammer REST API page. You also need to refer:

<script  src="https://assets.yammer.com/assets/platform_js_sdk.js"></script>

Here we will discuss only about Search endpoint. Search endpoint returns list of messages, users and groups that matches with the user’s query.

REST End Point: GET https://api.yammer.com/api/v1/search.json

It takes three Parameters:

search - The search query. Yammer fetches all results which matches this query.

page - Only 20 results of each type will be returned for each page, but a total count is returned with each query. page=1 (the default) will return items 1-20, page=2 will return items 21-30, etc.

num_per_page  - This allows you to limit the number of results of each type per page, up to a maximum of 20, the default value. This is helpful for the page navigation.

Following script shows how you can call this endpoint within JavaScript.

if (response.authResponse) { 
 yam.platform.request( 
 { 
 url: "https://api.yammer.com/api/v1/search.json"
 , method:  "GET"
 , data: { 'search': searchkey } 
 , success: function (msg) { 
 Display(msg); 
 } 
 , error: function (msg) { alert("Error..." + msg); } 
 } 
 ) 
}

 

In this way you can call other REST endpoints too. You need to be careful with the request method. In case of Search it is GET. To learn more about Yammer API follow the Yammer REST API page.

SharePoint 2013 tabs/navigation Concept

In SharePoint 2013 there is no more known as search scope but Result sources. And this helps to categorize the search. So on the search results what you see is some category tabs/links and end results. But what those tabs/links are??

Those links/tabs are known as Search navigation. Each link has its own page in SharePoint library. And each page contains Search Box web part, Search navigation web part and Search results web part with Result sources configured properly.

 You can configure/view those search navigation by going Site Settings -> Search Settings. 

So if you need to delete any link you can delete from here. Also if you got the requirement for new link you have to just create a new page and give page’s link to the Search Navigation. So simple, right. So we will use this concept for our case statement.

Solution to Case Statement

We see above how Yammer Search API works and how we can fetch the search result. Also, we see the concept of SharePoint search: how it displays search result. So what you can do here is reuse People and Conversation tabs/link related pages to display Yammer people result and Yammer conversation result. You can add new navigation link to display Yammer group results. Here i am going to explain steps for People link or tab; same steps can be used for others.

  1. First Save below People script to the people.htm file and upload to the SharePoint library.
  2. Navigate to the People link related page (generally it is: people.aspx).
  3. Open page in edit mode.
  4. Remove the existing Search Results web part only.
  5. Add content editor web part on the page.
  6. Provide the above uploaded file’s link as content link to the web part and save the page.
  7. Check in and publish the people search page.
  8. Done.
  9. Repeat those steps for all other links.

Here I have provided starting scripts for People, Groups and Conversation search results. Use them as base and make your custom application. I have tried this on on-premise SharePoint 2013 environment. It should work with SharePoint online environment also as it is JavaScript and REST calls. And the search center was Enterprise Search site.

Note: I have used Bootstrap framework to define html. This is demo application so I used Bootstrap. If you want to use this script as it is in commercial application then check Bootstrap’s license first.

Screenshot

Yammer People search Script:

<link  href="css\bootstrap.css" rel="stylesheet"> 
  
<div  class="container"> 
  
 <div  class="panel panel-default"> 
 <div class="panel-body"> 
  
 <div class="progress" style="display:none;" id="pgBarHolder"> 
 <div  id="pgbar" class="progress-bar progress-bar-success" role="progressbar" aria-valuenow="40" aria-valuemin="0" aria-valuemax="100" style="width: 5%;"> 
 <span class="sr-only">40% Complete (success)</span> 
 </div> 
 </div> 
 <div  id="tabs-1">  
 </div>  
 </div> 
 </div> 
  
  
 </div> 
  
 <script  src="https://assets.yammer.com/assets/platform_js_sdk.js"></script> 
 <script src="https://code.jquery.com/jquery-1.10.2.min.js"></script> 
 <script  src="js\bootstrap.min.js"></script> 
 <script src="js\holder.js"></script> 
  
<script type="text/javascript"> 
 yam.config({ appId: "{yourAppID}" }); 
  
 var m = 0; 
 var htmlStr = ""; 
 var htmlusers = ""; 
 var htmlGroups = ""; 
  
function getQueryStringsForFollow() { 
 var assoc = {}; 
 var decode = function (s) { return decodeURIComponent(s.replace(/\+/g, " ")); }; 
 var queryString = location.search.substring(1); 
 var keyValues = queryString.split('&'); 
  
 for (var i in keyValues) { 
 var key = keyValues[i].split('='); 
 if (key.length > 1) { 
 assoc[decode(key[0])] = decode(key[1]); 
 } 
 } 
  
 return assoc; 
 } 
  
 function Search() { 
  
 document.getElementById("pgBarHolder").setAttribute("style","display:block;"); 
 document.getElementById("pgbar").setAttribute("style","width:5%"); 
 htmlStr = ""; 
 htmlusers = ""; 
 htmlGroups = ""; 
 var qs = getQueryStringsForFollow(); 
 var searchkey =  qs["k"];//document.getElementById("searchkey").value 
 yam.platform.getLoginStatus(function (response) { 
 if (response.authResponse) { 
  
 yam.platform.request( 
 { 
 url: "https://api.yammer.com/api/v1/search.json" 
 , method: "GET" 
 , data: { 'search': searchkey } 
 , success: function (msg) { 
 Display(msg); 
 } 
 , error: function (msg) { alert("Error..." + msg); } 
 } 
 ) 
  
 } else { 
 yam.platform.login(function (response) { 
 if (!response.authResponse) { 
 yam.platform.request( 
 { 
 url: "https://api.yammer.com/api/v1/search.json" 
 , method: "GET" 
 , data: { 'search': searchkey  } 
 , success: function (msg) { 
 Display(msg); 
 } 
 , error: function (msg) { alert("Error..." + msg); } 
 } 
 ); 
 } 
 }); 
 } 
 }); 
  
 m++; 
 } 
  
 function Display(resp) { 
 debugger; 
  
 var counter = 100/resp.users.length;  
 var pgBarStatus = counter; 
  
 for (var j = 0; j < resp.users.length; j++) { 
  
 pgBarStatus =  parseInt(pgBarStatus) + parseInt(counter); 
 document.getElementById("pgbar").setAttribute("style","width:" + pgBarStatus +"%"); 
 var expertise =  "Not Available"; 
 var dept = "Not Available"; 
  
 if (resp.users[j].department != null) { 
 dept= resp.users[j].department; 
 } 
  
 if (resp.users[j].expertise != null) { 
 expertise = resp.users[j].expertise; 
 } 
  
 var n = resp.users[j].activated_at.indexOf(" "); 
 var d = resp.users[j].activated_at.substr(0,n); 
 var joinDate = new Date(d); 
  
 htmlusers = htmlusers + "<div class='panel panel-primary' style='padding:10px;'><div class='row'>"  
  
 + "<div  class='col-md-2'>" 
 + "<img src='" + resp.users[j].mugshot_url_template.replace("{width}x{height}", "75x75") + "' />" 
 + "</div>" 
 + "<div class='col-md-8'>" 
 + "<a  href='" + resp.users[j].web_url + "'>" + resp.users[j].full_name + "</a></br>" 
 + "Department: " + dept + "</br>" 
 + "Expertise: " + expertise + "</br>" 
 + "</div>" 
 + "<div  class='col-md-2'>" 
 + "Joined on: " 
 +  d //resp.users[j].activated_at 
 + "</div>" 
  
  
 + "</div></div>"; 
 } 
  
 setTimeout(function() { 
 document.getElementById("pgBarHolder").setAttribute("style","display:none;"); 
 }, 500); 
 $("#tabs-1").html(htmlusers); 
  
 } 
  
 </script>

Yammer Conversations search Script:

 

<link  href="css\bootstrap.css" rel="stylesheet"> 
<div class="container"> 
 <div  class="panel panel-default"> 
 <div class="panel-body"> 
  
 <div class="progress" style="display:none;" id="pgBarHolder"> 
 <div  id="pgbar" class="progress-bar progress-bar-success" role="progressbar" aria-valuenow="40" aria-valuemin="0" aria-valuemax="100" style="width: 5%;"> 
 <span class="sr-only">40% Complete (success)</span> 
 </div> 
 </div> 
  
 <div id="tabs-1">  
 </div>  
 </div> 
 </div> 
  
  
 </div> 
  
 <script src="https://assets.yammer.com/assets/platform_js_sdk.js"></script> 
 <script  src="https://code.jquery.com/jquery-1.10.2.min.js"></script> 
 <script src="js\bootstrap.min.js"></script> 
 <script  src="js\holder.js"></script> 
  
<script  type="text/javascript"> 
 yam.config({ appId: "{yourappID}" }); 
  
 var m = 0; 
 var htmlStr = ""; 
 var htmlusers = ""; 
 var htmlGroups = ""; 
  
function getQueryStringsForFollow() { 
 var assoc = {}; 
 var decode = function (s) { return decodeURIComponent(s.replace(/\+/g, " ")); }; 
 var queryString = location.search.substring(1); 
 var keyValues = queryString.split('&'); 
  
 for (var i in keyValues) { 
 var key = keyValues[i].split('='); 
 if (key.length > 1) { 
 assoc[decode(key[0])] = decode(key[1]); 
 } 
 } 
  
 return assoc; 
 } 
  
 function Search() { 
  
 document.getElementById("pgBarHolder").setAttribute("style","display:block;"); 
 document.getElementById("pgbar").setAttribute("style","width:5%"); 
 htmlStr = ""; 
 htmlusers = ""; 
 htmlGroups = ""; 
  
var qs = getQueryStringsForFollow(); 
 var searchkey =  qs["k"];//document.getElementById("searchkey").value 
  
 yam.platform.getLoginStatus(function (response) { 
 if (response.authResponse) { 
  
 yam.platform.request( 
 { 
 url: "https://api.yammer.com/api/v1/search.json" 
 , method: "GET" 
 , data: { 'search': searchkey } 
 , success: function (msg) { 
 Display(msg); 
 } 
 , error: function (msg) { alert("Error..." + msg); } 
 } 
 ) 
  
 } else { 
 yam.platform.login(function (response) { 
 if (!response.authResponse) { 
 yam.platform.request( 
 { 
 url: "https://api.yammer.com/api/v1/search.json" 
 , method: "GET" 
 , data: { 'search': searchkey  } 
 , success: function (msg) { 
 Display(msg); 
 } 
 , error: function (msg) { alert("Error..." + msg); } 
 } 
 ); 
 } 
 }); 
 } 
 }); 
  
 m++; 
 } 
  
 function Display(resp) { 
 debugger; 
  
 var htmlStr = ""; 
 var counter = 100/resp.messages.messages.length;  
 var pgBarStatus = counter; 
  
 for (var j = 0; j < resp.messages.messages.length; j++) { 
  
 pgBarStatus =  parseInt(pgBarStatus) + parseInt(counter); 
 document.getElementById("pgbar").setAttribute("style","width:" + pgBarStatus +"%"); 
  
  
 if (resp.messages.messages[j].client_type == "Yammer Embed") { 
 htmlStr = htmlStr + "<div class='panel panel-primary' style='padding:10px;'>" 
  
 + "<div>" 
 + resp.messages.messages[j].body.parsed 
 + "</div>" 
  
 + "<div>" 
 + resp.messages.messages[j].attachments[0].inline_html 
 + "</div>" 
  
 + "<div><br/>" 
 + "<a target='_blank' href='"+ resp.messages.messages[j].web_url  +"'>View Full conversation</a>" 
 + "</div>" 
  
 + "</div>"; 
 } 
  
 else if (resp.messages.messages[j].client_type == "Web") { 
 htmlStr = htmlStr + "<div class='panel panel-primary' style='padding:10px;'>" 
  
 + "<div>" 
 + resp.messages.messages[j].body.rich 
 + "</div>"; 
  
 if (resp.messages.messages[j].attachments.length > 0) { 
  
 if (resp.messages.messages[j].attachments[0].content_class == "Image") { 
 htmlStr = htmlStr + "<div><img height='200px' width='300px' src='" + resp.messages.messages[j].attachments[0].large_preview_url + "' /></div>" 
 } 
 } 
  
 htmlStr = htmlStr + "<div><br/>" 
 + "<a  target='_blank' href='"+ resp.messages.messages[j].web_url  +"'>View Full conversation</a>" 
 + "</div>" 
  
 htmlStr = htmlStr + "</div>"; 
 } 
 }  
  setTimeout(function() { 
 document.getElementById("pgBarHolder").setAttribute("style","display:none;"); 
 }, 500); 
 $("#tabs-1").html(htmlStr); 
 }  
  
 </script>

Yammer Group search Script:

<link href="css\bootstrap.css" rel="stylesheet"> 
  
<div class="container"> 
  
 <div class="panel panel-default"> 
 <div class="panel-body"> 
  
 <div class="progress" style="display:none;" id="pgBarHolder"> 
 <div id="pgbar" class="progress-bar progress-bar-success" role="progressbar" aria-valuenow="40" aria-valuemin="0" aria-valuemax="100" style="width: 5%;"> 
 <span class="sr-only">40% Complete (success)</span> 
 </div> 
 </div> 
  
 <div id="tabs-1">  
 </div>  
 </div> 
 </div> 
  
  
 </div> 
  
 <script src="https://assets.yammer.com/assets/platform_js_sdk.js"></script> 
 <script src="https://code.jquery.com/jquery-1.10.2.min.js"></script> 
 <script src="js\bootstrap.min.js"></script> 
 <script src="js\holder.js"></script> 
  
<script type="text/javascript"> 
 yam.config({ appId: "{yourappID}" }); 
  
 var m = 0; 
 var htmlStr = ""; 
 var htmlusers = ""; 
 var htmlGroups = ""; 
  
function getQueryStringsForFollow() { 
 var assoc = {}; 
 var decode = function (s) { return decodeURIComponent(s.replace(/\+/g, " ")); }; 
 var queryString = location.search.substring(1); 
 var keyValues = queryString.split('&'); 
  
 for (var i in keyValues) { 
 var key = keyValues[i].split('='); 
 if (key.length > 1) { 
 assoc[decode(key[0])] = decode(key[1]); 
 } 
 } 
  
 return assoc; 
 } 
  
 function Search() { 
  
 document.getElementById("pgBarHolder").setAttribute("style","display:block;"); 
 document.getElementById("pgbar").setAttribute("style","width:5%"); 
 htmlStr = ""; 
 htmlusers = ""; 
 htmlGroups = ""; 
 var qs = getQueryStringsForFollow(); 
 var searchkey =  qs["k"];//document.getElementById("searchkey").value 
 yam.platform.getLoginStatus(function (response) { 
 if (response.authResponse) { 
  
 yam.platform.request( 
 { 
 url: "https://api.yammer.com/api/v1/search.json" 
 , method: "GET" 
 , data: { 'search': searchkey } 
 , success: function (msg) { 
 Display(msg); 
 } 
 , error: function (msg) { alert("Error..." + msg); } 
 } 
 ) 
  
 } else { 
 yam.platform.login(function (response) { 
 if (!response.authResponse) { 
 yam.platform.request( 
 { 
 url: "https://api.yammer.com/api/v1/search.json" 
 , method: "GET" 
 , data: { 'search': searchkey  } 
 , success: function (msg) { 
 Display(msg); 
 } 
 , error: function (msg) { alert("Error..." + msg); } 
 } 
 ); 
 } 
 }); 
 } 
 }); 
  
 m++; 
 } 
  
 function Display(resp) { 
 debugger; 
  
 var htmlGroups = ""; 
 var counter = 100/resp.groups.length;  
 var pgBarStatus = counter; 
  
 for (var j = 0; j < resp.groups.length; j++) { 
  
 pgBarStatus =  parseInt(pgBarStatus) + parseInt(counter); 
 document.getElementById("pgbar").setAttribute("style","width:" + pgBarStatus +"%"); 
  
  
 var mugShotUrl =  ""; 
 var fullName = ""; 
 var description =  ""; 
 var date =""; 
 try 
 { 
 mugShotUrl =  resp.groups[j].mugshot_url_template.replace("{width}x{height}", "75x75"); 
 } 
 catch(err) 
 { 
 mugShotUrl =  ""; 
 } 
  
 try 
 { 
 fullName = resp.groups[j].full_name; 
 } 
 catch(err) 
 { 
 fullName = ""; 
 } 
  
  
 try 
 { 
 description = resp.groups[j].description; 
 } 
 catch(err) 
 { 
 description = ""; 
 } 
  
 try 
 { 
 var n = resp.groups[j].created_at.indexOf(" "); 
 date = resp.groups[j].created_at.substr(0,n); 
 } 
 catch(err) 
 { 
 date = ""; 
 } 
  
  
  
 htmlGroups = htmlGroups + "<div class='panel panel-primary' style='padding:10px;'><div class='row'>"  
  
 + "<div class='col-md-2'>" 
 + "<img class='img-responsive' src='" + mugShotUrl + "' />" 
 + "</div>" 
 + "<div class='col-md-8'>" 
 + "<a href='" + resp.groups[j].web_url + "'><strong>" + fullName + "</strong></a></br>" 
 + "Description: " + description + "</br>"  
 + "</div>" 
 + "<div class='col-md-2'>" 
 + "<strong>Created at: </strong>" 
 +  date 
 + "<br/><strong>Members: </strong>" 
 +  resp.groups[j].stats.members 
 + "</div>" 
  
  
 + "</div></div>"; 
  
 }  
   setTimeout(function() { 
 document.getElementById("pgBarHolder").setAttribute("style","display:none;"); 
 }, 500); 
 $("#tabs-1").html(htmlGroups); 
 } 
  
  
 </script>

 

See Also

SharePoint 2013: Integrate Yammer with SharePoint for Social Feature(s)