Wednesday, 28 October 2015

Sitecore "Add To Calendar" Module

Whether you are building corporate website, commercial website or any other type of website, one of the famous feature demanding from your client is Calendar Event. There should be feature in your website from where user should be able to download calendar event (e.g. .ICS) file and save it as reminder. Such calendar event is required typically on news or event section of your website.



Clicking on Add To Calendar link will download calendar event - .ICS file as shown below.




If you are looking for similar thing, then you are at right place. Add To Calendar Sitecore module is all about this.

Features of Add To Calendar module:

1) Supports multiple time zones
It will convert date and save calendar event based on end user's timezone no matter in which time zone you have configured event.
For example: If you have configured event in US time zone and if end user is downloading that event from India, then it will convert event timings in IST.

2) Supports multiple occurrence of event in a week
If you have multiple occurrence of event falling under one week, then this module will pick best suitable event for the user which means it will download very next upcoming occurrence of that event.

For example: If you have configured event for Monday, Wednesday & Friday and if the user downloads event on Tuesday then module is intelligent enough to understand very next event and will download Wednesday event for the user.

3) Calendar details are fully configurable
You can manage event title, subject and body content straight away from Sitecore.

4) You can customize it if you want
The code of Add To Calendar Sitecore module is available on GitHub, so you can customize or contribute it as per your wish at https://github.com/nileshthakkar/AddToCalendar

Download

You can download this module from Sitecore Market Place.

Configuration

Once you install it, you will find this module at /sitecore/system/Modules/Add To Calendar
Second column in Event Dates field is for timings. You can specify any time range in 24 hours format.



The templates are at:



The controller can be found at:



So the only thing you need to do is add this controller to your page and you are good to go!


Make sure that you set the data source of Calendar Event item to AddToCalendar controller.


Source Code

In case if you are NOT using MVC and want to have this module working, then you can create a sublayout and inject below code on click of your "Add To Calendar" link.

 public void Download(Item calenderItem)
        {          
            DateTime chatStartDate = DateTime.Today;
            DateTime chatEndDate = DateTime.Today;
            string strTimings = string.Empty;
            NameValueCollection collection = 
            Sitecore.Web.WebUtil.ParseUrlParameters(calenderItem["Event Dates"]);
            if (collection.Count > 0)
            {
                for (int i = 0; i <= 6; i++)
                {
                    foreach (string day in collection.AllKeys)
                    {
                        if (chatStartDate.Date.AddDays(i).DayOfWeek.ToString() == day)
                        {
                            chatStartDate = chatStartDate.Date.AddDays(i);
                            strTimings = collection[day];
                            i = 7;
                            break;
                        }
                    }
                }
            }

            string[] chatTimings = 
            strTimings.Split(new[] { '-' }, StringSplitOptions.RemoveEmptyEntries);
            if (chatTimings.Length > 0)
            {
                if (chatTimings[0] != null)
                {
                    TimeSpan ts = new TimeSpan(int.Parse(chatTimings[0]), 0, 0);
                    chatStartDate = chatStartDate.Date + ts;
                }

                if (chatTimings[1] != null)
                {
                    TimeSpan ts2 = new TimeSpan(int.Parse(chatTimings[1]), 0, 0);
                    chatEndDate = chatStartDate.Date + ts2;
                }

                if (calenderItem["Time Zone"] != null)
                {
                    Item timeZoneItem = Sitecore.Context.Database.GetItem(calenderItem["Time Zone"]);

                    chatStartDate = 
                    convertDateToTimeZone(chatStartDate, timeZoneItem["Name"], "UTC");
                    chatEndDate =
                    convertDateToTimeZone(chatEndDate, timeZoneItem["Name"], "UTC");

                    CalendarFile calendarFile = new CalendarFile(calenderItem["Subject"], chatStartDate, chatEndDate);
                    calendarFile.location = calenderItem["Location"];
                    calendarFile.description = calenderItem["Body"];

                    this.Response.Clear();
                    Response.Expires = 0;
                    this.Response.Buffer = true;
                    Response.ContentType = "text/calendar";
                    Response.AddHeader("Content-Disposition", "inline; filename=" + calenderItem.Name + ".ics");
                    this.Response.Write(calendarFile.ToString());
                    this.Response.Flush();
                    this.Response.End();
                }
            }
        }

        public DateTime convertDateToTimeZone(DateTime nextDate, string fromTimeZone, string toTimeZone)
        {
            TimeZoneInfo cstZone = TimeZoneInfo.FindSystemTimeZoneById(fromTimeZone);
            TimeZoneInfo cstZone2 = TimeZoneInfo.FindSystemTimeZoneById(toTimeZone);
            nextDate = DateTime.SpecifyKind(nextDate, DateTimeKind.Unspecified);
            DateTime cstDateTime = TimeZoneInfo.ConvertTime(nextDate, cstZone, cstZone2);
            return cstDateTime;
        }


Feel free to customize or contribute this module by forking it at: https://github.com/nileshthakkar/AddToCalendar

Hope this effort will help someone to add Calendar Event feature in his/her project!

Tuesday, 20 October 2015

How To Create Bulk Items in Sitecore Using Powershell Script?

Many times you need to create bulk items in Sitecore for some reason. May be you want to check the performance of your newly implemented feature. Let's say you want to check how your code (e.g search code) is performing when there are tons of items.

So once again you can take the advantage of Sitecore Powershell script here. Below is the small yet powerful Sitecore Powershell script (.ps) which will empower you to create desired number of items based on given template.
#This script will create sitecore items based on given count and template
$InputCount = Show-Input "How many items do you want to create?"
$InputTemplate = Show-Input "Using which template you want to create item?"
$getCurrentItem = Get-Item .
$NewItemPath = $getCurrentItem.FullPath
$CurrentChildCount = $getCurrentItem.Children.Count+1
for ($index = $CurrentChildCount; $index -lt $CurrentChildCount+$InputCount; $index++) 
{
   new-item -Path $NewItemPath -Name $index -type $InputTemplate
}
You can create the script named Create Bulk Items  under /sitecore/system/Modules/PowerShell/Script Library/Package Generator/Content Editor/Context Menu/Packaging



When you run above script, it will ask you:

1) How many number of items do you want to create?


2) Using which template you want to create items?


Below screen summarizes the entire step by step process to create bulk items in Sitecore.


This script is powered by Sitecore Powershell Extensions, so please make sure that you have Powershell extensions installed in your Sitecore instance. If you want to download Sitecore Powershell Extensions, click here for the same.

Empower you Sitecore Journey by using Sitecore Powershell Extensions!

Thursday, 15 October 2015

Are You Getting "Key Does Not Exist In This Pattern Space" Error?

This post is related to my previous post where I illustrated how to deal with persona and pattern card programmatically.

If you are working on such stuff and found below mentioned error in log, then this post may help you to understand why it is happening and how to get rid of this error.

Message: Key 'Network Infrastructure' does not exist in this pattern space
Source: Sitecore.Analytics
   at Sitecore.Analytics.Patterns.PatternSpace.GetKeyIndex(String key)
   at Sitecore.Analytics.Patterns.PercentagePatternMapper.GetPoints(PatternSpace space, IProfileData values)
   at Sitecore.Analytics.Patterns.PatternSpace.CreatePattern(IProfileData profile)
   at System.Linq.Enumerable.<>c__DisplayClass2`3.<CombineSelectors>b__3(TSource x)
   at System.Linq.Enumerable.WhereSelectArrayIterator`2.MoveNext()
   at System.Linq.Enumerable.FirstOrDefault[TSource](IEnumerable`1 source)
   at Sitecore.Analytics.Data.Items.ProfileItem.get_MappedPatterns()
   at Sitecore.Analytics.Data.Items.ProfileItem.MatchPattern(IProfileData profile, IPatternDistance distance)
   at Sitecore.Analytics.Tracking.Profile.UpdatePattern()


Reason:
Whenever we call profile.UpdatePattern(), Sitecore is updating all profile keys of that profile using profile key item field name instead of profile key item name.

While Sitecore is storing profile item name as key in Pattern XML field.

How to get rid of this error?
Change name to Network and Infrastructure from Network Infrastructure then it will NOT complain above error.



That's it. Have a learning Sitecore Journey!

Tuesday, 13 October 2015

How to Set Persona/Pattern Card Programmatically in Sitecore?

Recently came across a very interesting requirement of analyzing user's pattern based on search action performed by user on the site.

Every webiste has one common functionality implemented - site search. Here you can hook your code to understand user's pattern by observing the keywords user is searching.

For example: whenever user search terms like softwareprogramming or computer then system should be intelligent enough to understand that - user matches with one of the existing persona Software Engineering.


Being a Sitecore developer, you know that how to set persona on any Sitecore item which is straight forward process (e.g. select desired persona from right top corner of content tab). But how about setting persona or pattern card programmatically at runtime?

Here are the steps I followed to accomplish above mentioned requirement.

1) Provided facility to configure all search keywords or tags.


2) Added one custom field Persona Tags in pattern card template which lists all above mentioned search tags.



3) The final step is to write custom code which will set current user's profile/persona based on search terms by associating with existing Sitecore pattern cards. You can hook this code on search button click as shown in very first screen-shot of this post.

public static void SetPatternCard(string searchedTerm)
        {
            try
            {
                Stopwatch sw = Stopwatch.StartNew();
                Sitecore.Data.Database db = Sitecore.Context.Database;

                //Get persona tag from Data folder matching the searched keyword
                var peronaDataTagsQuery = string.Format("/sitecore/content/Home/Data/Persona Tags//*[@name='{0}']", searchedTerm);
                Item matchedPeronaTag = db.SelectSingleItem(peronaDataTagsQuery);

                if (matchedPeronaTag != null)
                {
                    //Get all pattern cards which has matching persona tag as per searched keyword                
                    var query = string.Format("/sitecore/system/Marketing Control Panel/Profiles//*[@@templateid='{0}' and contains(@Persona Tags,'{1}')]", "{4A6A7E36-2481-438F-A9BA-0453ECC638FA}", matchedPeronaTag.ID);
                    Item[] allPatternCards = db.SelectItems(query);

                    foreach (Item patternCard in allPatternCards)
                    {
                        //Set current profile with respective pattern
                        var profile = Sitecore.Analytics.Tracker.Current.Interaction.Profiles[patternCard.Parent.Parent.Name];

                        Sitecore.Data.Fields.XmlField xmlData = patternCard.Fields["Pattern"];
                        XmlDocument xmlDoc = xmlData.Xml;

                        XmlNodeList parentNode = xmlDoc.GetElementsByTagName("key");
                        var scores = new Dictionary();

                        foreach (XmlNode childrenNode in parentNode)
                        {
                            if (childrenNode.Attributes["value"].Value != "0")
                            {
                                float keyValue;
                                float.TryParse(childrenNode.Attributes["value"].Value, out keyValue);
                                scores.Add(childrenNode.Attributes["name"].Value, keyValue * 3);
                            }
                        }

                        profile.Score(scores);
                        profile.UpdatePattern();
                        sw.Stop();
                        Sitecore.Diagnostics.Log.Audit("SetPatternCard took total " + sw.ElapsedMilliseconds.ToString() + " milliseconds.", new Exception());
                    }
                }
            }
            catch (Exception ex)
            {
                Sitecore.Diagnostics.Log.Error("Error occured in SetPatternCard " + ex.ToString(), new Exception());
            }

How can you confirm that it has really set the associated pattern?
Answer is simple!
You can personalize any page component based on pattern card condition. So for above Software Engineering example, you can personalize component as suggested in below screens.




This implementation will definitely add value to your digital marketing strategy!

Monday, 5 October 2015

Sitecore Package Generator Module: No Manual Packaging Now!

In day to day life of Sitecore Developer, one of the repeating task is to create a package. For every release, you need to perform this task which is boring and time consuming. But at the same time, you need to be accurate while generating Sitecore package for deployment.

If you miss even a single item to add in package, your release will fail. So you must be keeping record of all Sitecore items somewhere - may be in notepad, which can help you to create package at the time of deployment.

No need to create manual package now!

Yes - you can take advantage of this little but very useful module named Sitecore Package Generator. You only need to provide your Sitecore items detail in form of CSV file and rest of all will be managed by this module. It will auto generate Sitecore Package for you!!!

You can download Sitecore Package Generator module from marketplace.

This module is powered by Sitecore Powershell Extensions, so please make sure that you have Powershell extensions installed in your Sitecore instance. If you want to download it, click here.

This is how you can auto generate Sitecore Package:



This is will open pop-up to provide CSV file path.







Your CSV file should have below format. If you want to add items with child items in package, mention "Yes" in Include Child column else "No".


Hope you will now save your time and effort while packaging!

A Big Thanks To SITECORE POWERSHELL EXTENSIONS team - Adam, Andrej, James, Michael West, Michael Reynolds and Szymon for creating such a fabulous Sitecore Powershell Extensions module.

Thursday, 1 October 2015

How To Hide Any Page OR Section from Live Sitecore Website?

Recently came across a very small but interesting question - how to hide any section or page from live website in Sitecore?

Well, as Sitecore is famous for its flexible architecture which can definitely accommodate this requirement. But Sitecore newbies are not aware about it and on top of that - you will not find any answer to this question on internet easily.

Hence thought to share it with this post - I am sure this will really help to beginners!

But before we jump to solution - I have a very small question for you.

Do you know whenever you access Sitecore Website (preview mode), under which user account does your website run?

If you know this answer then your half journey to find the solution is done. Yes - you are thinking right - it's under extranet\Anonymous user account.

So for what are you waiting now? You need to disable read access rights for extranet\Anonymous user account on that item. It's simple but tricky. isn't it?

Here are step by step screen grabs to configure the same which will remove read access rights for extranet\Anonymous user, so that page will NOT be shown on your Sitecore website.


This will open up Access Viewer pop-up window. Make sure that you select extranet\Anonymous user.


Clicking on Assign button will open another pop-up window where you need to remove read access rights.


Finally, click on OK and you are done.

Have a Happy Sitecore Journey!