Show Upcomming Birthdays Based on SharePoint 2013 User Profiles with Search (Office 365)


A lot of customers like to have some kind of anniversary webpart on their corporate intranet. In SharePoint 2013 and Office365 you can provide this functionality using the SharePoint User Profile and Search (and some Javascript).

2013-10-02_22h27_30

In the SharePoint User Profile, users are able to provide their birthday by default. These values are automaticly crawled but you will not be able to apply filters using search. In this blog post I will describe the configuration steps for Office365.

> Go to the Site Settings -> Site Collection Administration -> Search Schema (you can also configure this in the SharePoint Admin level)
> Search for RefinableDate00, Edit the mapping (for SharePoint Onpremise, you are able to add a new one with type Date)
> Give it an alias like Birthday01
> Add “People:SPS-Birthday” as crawled field mapping

2013-10-02_22h07_48

> Be sure you have some people filled in their birthday on their profile
> You are done, o365 will need to wait at most 1 week (yes, you are reading it right). Full crawls are now performed once a week, if you need it by tomorrow you can submit a support ticket to MS support, they will initiate a full crawl on request. Onpremise users just fire off a full crawl.

To test if your managed property is working you can perform a query to your search center.
https://tenantname.sharepoint.com/search/Pages/peopleresults.aspx?k=Birthday01>”01-01-2000″

Our prerequisities are met, and we are able to query for a birthday. So why should we need any code…
As you can see in the “test” query above, we are using the year 2000 to query, this is not just a coincidence. SharePoint stores the Date no Year fields using the year 2000, and SharePoint Online is not different on this one. Unfortunately this makes our Search Results webpart unusefull because you can only use keywords like today-5, yesterday, last week, last month and last year.

The javascript below will perform a restcall to the search service to retrieve the birthdays which are in range (30 days in this example).

(note: jquery is required)

<div id="resultsDiv"></div>
<script type="text/javascript">// <![CDATA[
$(document).ready(function () {
    var e = ExecuteOrDelayUntilScriptLoaded(executeQuery(), "sp.js");
});

Date.prototype.AddDays=function(days)
{
	this.setDate(this.getDate() + days);
	return this;
}

function executeQuery() {

    Results = {
        element: '',
        url: '',

        init: function (element) {
            Results.element = element;

	    var birthday = 'Birthday01';
	    var space = '%20'; var colon = '%3A'; var quote = '%22'; var gt = '%3E'; var lt = '%3C'; var amp = '&';

            // Get current date
            var currentTime = new Date();
	    var startMonth = currentTime.getMonth()+1;
	    var day = currentTime.getDate();

            // Get current date + 30
	    var endTime = new Date();
            var endTime = currentTime.AddDays(30);
	    var endMonth = endTime.getMonth()+1;
            var endDay = endTime.getDate();

            var querytext = "";

	    // build query with the magic 2000 year
            if(startMonth!='12')
	    {
		querytext += birthday + gt + quote + day + '-' + startMonth + '-' + '2000' + quote + space + 'AND' + space + birthday + lt + quote + endDay + '-' + endMonth + '-' + '2000' + quote;
	    }
	    else
	    {
		querytext += birthday + gt + quote + day + '-' + startMonth + '-' + '2000' + quote + space + 'OR' + space + birthday + lt + quote + endDay + '-' + endMonth + '-' + '2000' + quote;
	    }
            Results.url = _spPageContextInfo.webAbsoluteUrl + "/_api/search/query?querytext=%27" + querytext + "%27&sourceid=%27B09A7990-05EA-4AF9-81EF-EDFAB16C4E31%27&selectproperties=%27Title,"+ birthday +",Path%27&sortlist=%27"+ birthday +":ascending%27";
        },

        load: function () {
            $.ajax(
                    {
                        url: Results.url,
                        method: "GET",
                        headers: {
                           "accept": "application/json; odata=verbose",
                        },
                        success: Results.onSuccess,
                        error: Results.onError
                    }
                );
        },

        onSuccess: function (data) {
            var results = data.d.query.PrimaryQueryResult.RelevantResults.Table.Rows.results;
	    var months = [ "januari", "februari", "maart", "april", "mei", "june", "juli", "augustus", "september", "oktober", "november", "december" ];
            var html = "<div class='birthday'>";

            for (var i = 0; i < results.length; i++) {
		var name = results[i].Cells.results[2].Value;
		var date = new Date(Date.parse(results[i].Cells.results[3].Value));
                var link = results[i].Cells.results[4].Value

                html += "<span>";
                html += "<a href='"+link+"'>" + name + "</a>";
                html += " "
                html += date.getDate() + " "+ months[date.getMonth()];
                html += " ";
            }

	    if (results.length == 0)
            {
              html += "Er zijn geen verjaardagen (bekend).";
            }

            html += "</div>";
            Results.element.html(html);
        },

        onError: function (err) {
            alert(JSON.stringify(err));
        }
    }

    Results.init($('#resultsDiv'));
    Results.load();

}

// ]]></script>
Advertisements

About SharePoint Architect Joran Markx
I have been working on SharePoint projects since 2003. In addition to (lead) developer and software architect, I am certified SharePoint Technology Specialist and active in design and development of Enterprise SharePoint platforms. In 2011 I have achieved a Master of Science in IT Management. This made me capable to solve complex issues from the business in an efficient and structured way. As SharePoint Architect I am working on various challenging projects with a variety of clients. Within my organisation I fullfill a leading role when it comes to internal development and sharing of knowledge. My goal is to provide reliable and predictable services to our clients with a strong focus on the results achieved for the organisations I am working for.

26 Responses to Show Upcomming Birthdays Based on SharePoint 2013 User Profiles with Search (Office 365)

  1. Tijo says:

    I have developed a asp.net MVC web application.

    How i show a sharepoint page in my MVC web application.

    View Page

    This link is Working properly.But i want to show this link on inside IFrame.

    I used to display this code for inside viewing.

    in that time one error generated.

    “Load denied by X-Frame-Options: http://win-spserver/_layouts/15/start.aspx#/SitePages/Home.aspx does not permit cross-origin framing.”

    Please solve this issue.

    is it possible or not ?

  2. Berkay says:

    Hi Joran, Thanks for the article. I tried to develop your sample for sharepoint online, but when i try to map People:SPSBirthday property to a RefinableDate, i can’t see the People:SPSBirthday property on mapping screen. If you want , i can provide screenshot. Do you have an idea about this problem? Thanks for your help.
    Regards.

    • Javier says:

      i can’t see the People:SPSBirthday property on mapping screen to, can you fix that?

      • Bastiaan says:

        Search for: SPSBirthday. Then you will find it.

    • Pat Beautz says:

      Same thing happened to me. The People:SPSBirthday shows up though once you have some user profiles with data in that field…..

  3. Hi Berkay, the property should be named People:SPS-Birthday. Maybe you ‘ll have to fill one profile with a birthday at least.

  4. Karen says:

    Hi,

    How could this be used to show upcoming anniversaries?

    Thanks

  5. Bevan says:

    Hi Joran, great article and worked perfectly. I have the same query as Karen, what would be the best way to show upcoming anniversaries based off the People:SPS-HireDate field.

    Thanks

    • Benjamin Olesen says:

      I’m able to execute the script, but I really miss the total age. Any ideas how to accomplish this?

      And what about work anniversary – Have anyone worked out a solution for that as well?

      Best regards
      Benjamin

      • The default birthday field in sharepoint does not contain the birth year. So You Will need a custom field to accomplish this requirement. I don’t think you can get these results filtered using search. For the work anniversary this will workout pretty fine, because you can filter for a date minus 5 years, 10 years, etc.

      • Bart says:

        Benjamin, in the example query there is a part which generate the “html” if want an age displayed, you need to create a javascritp variable which calaculates based on the date of today and the birthday date, then display this variable on a new line by updating the html code.

        something like html += ” age: ” + yourvar;

        where yourvar is calculated on the input

  6. Yuri says:

    Hi Guys. I’m a noob, and I need this to work on our intranet. We are using SP 2013 Enterprise.
    I have tried following the steps,. How and where do I use the script? Can I insert it inline, when I edit a page?

    • Hi, you can use the content editor webpart with a reference to a script file.

      • Yuri says:

        Hi, can you explain how to do this?

  7. Javier says:

    Hi Joran, i can put this in a sharepoint online app?

    • Yes you can, but you probably need to rewrite some code to perform cross domain scripting

  8. Great article! Thanks

  9. Bart Abels says:

    Your solution works like a charm, i just want to know if it is possible to display the profile image also, is this possible?

  10. Bart Abels says:

    Here an update, so if someone can help me with the variables , this is really appreciated.

    I managed to get the url , but now it is not yet dynamic.

    The html code for the (in this case dutch) image path location is:

    html +=”<img src='https://-my.sharepoint.com/User%20Photos/Profielafbeeldingen/__onmicrosoft_com_SThumb.jpg'&gt;”;

    However if you logon with your own domain, it will be ____SThumb.jpg

    if i can retrieve the domain info and convert it to _, then i have found a way to add an image

    Any suggestions?

  11. Bart Abels says:

    hmm seems the code is not correctly displayed, should be

    https://tenantname-my.sharepoint.com/User%20Photos/Profielafbeeldingen/lastnameofuser_yourdomain_yourprefix (nl,org, com)_SThumb.jpg

  12. Bart Abels says:

    Has anyone a solutions to retrieve the picture from the profiles? This would be nice if this is possible with the application described in this blog

    • I would think you can grab some code from the DisplayTemplate (2013) or XSLT for the people search to add a profile picture to the results.

  13. Jack says:

    Hi,

    I am having an issue with the code, I can get it to return results, but not for the dates I am expecting.

    I have January birthdays in my user profile service, but none show up in the web part. If I extend the endtime to = currentTime.AddDays(60);

    Then I do get a result, but it is for a person who has a birthday in August. His birthday is entered correctly as August 07.

    Any ideas?

    Thank you

    • What date notification do You use?

      • jack says:

        Not sure exactly what you mean by date notification.

        Using the built in birth date with no year, so month day.

        Sorry if i am missing something obvious and appreciate the swift response.

        Jack

      • The example code uses the dutch date notation for the query (day-month-year). Maybe just update the query to month-day-year will fix your issue.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: