Friday, 13 November 2015

How To Get "Near By Me" Location Using Sitecore Search?

Dear Sitecorians, to provide better experience to your website users sometimes you are asked implement a feature such as StoesNearByMe, EventsNearByMe or JobsNearByMe in your Sitecore solution.

In such scenarios, basically you need two information:
1) User's location (e.g latitude and longitude)
2) Search all stores, events or jobs near to user's location.

We have already seen how to get user's location in one the previous posts. If you haven't then I would suggest to read that post first.

Once you have user's location handy, then you can pass this information (e.g. latitude and longitude) to below method which will build Sitecore predicate search query to pull near by items.
  
// NearByMe | ToDo : impelement predicate for near by
public static Expression<Func<NewJobModel, bool>> ContainsNearByMe(Double Latitude, Double Longitude)
        {
            var predicate = PredicateBuilder.True<NewJobModel>();

            //Within 25 Miles (40.2336 KMs)
            double distance = 40.2336;

            // earth's radius in km = ~6371
            double radius = 6371;

            // latitude boundaries
            double minlat = Latitude - RadianToDegree(distance / radius);
            double maxlat = Latitude + RadianToDegree(distance / radius);

            // longitude boundaries (longitude gets smaller when latitude increases)            
            double minlng = Longitude - RadianToDegree(distance / radius / Math.Cos(DegreeToRadian(Latitude)));
            double maxlng = Longitude + RadianToDegree(distance / radius / Math.Cos(DegreeToRadian(Latitude)));

            //query = context.GetQueryable<NewJobModel>().Where(builder).Where
            predicate = Latitude.ToString().Aggregate(predicate, (current, temp) 
                => current.Or((item => (item.Latitude >= minlat && item.Latitude <= maxlat)              
                )));

            predicate = predicate.And(Longitude.ToString().Aggregate(predicate, (current, temp) 
                => current.Or((item => (item.Longitude >= minlng && item.Longitude <= maxlng)            
               ))));

            return predicate;
        }



  private static double RadianToDegree(double angle)
  {
      return angle * (180.0 / Math.PI);
  }


Above algorithm calculates near by location within 25 miles radius, you can change it as per your need.
Finally You can call above function using your PredicatBuilder like this:
  
 var builder = PredicateBuilder.True<newjobmodel>();

  //Location near me
  if (jobSearchModel.Latitude != 0 &amp;&amp; jobSearchModel.Longitude != 0)
  {
       builder = builder.And(ContainsNearByMe(jobSearchModel.Latitude, jobSearchModel.Longitude));
  }

This will be gold dust for your Sitecore search implementation.

Monday, 2 November 2015

Does Your Sitecore 8 Hang While Package Upload?

This is a quick tip for all those who are using Sitecore.NET 8.0 rev. 150223 (8.0 Update 2) and facing hang issue while uploading Sitecore package.


Solution:
There are two options to get rid of this issue.

Option-1:
Move to next upgrade as it is known issue and resolved in Sitecore 8.0 Update 3, you can find it at official release notes.


https://dev.sitecore.net/Downloads/Sitecore%20Experience%20Platform/8%200/Sitecore%20Experience%20Platform%2080%20Update3/Release%20notes

 But naturally this is not an easy solution.

Option-2:
This issue occurs when there is NO packages folder found under /Data folder at your Sitecore instance. So create packages folder manually under /Data folder in order to fix this issue.

Thanks to my colleague Mahek who introduced me this issue.

Enjoy your Sitecore Packaging now!

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!

Wednesday, 30 September 2015

Code Generation Error While Using Sitecore TDS + GlassMapper

Most of Sitecore developers are now using TDS and GlassMapper in their solution. It's an awesome combination!

But you may find some challenges when you are setting up auto code generation feature of TDS by using GlassMapper. One of such challenge is facing the code generation error as shown below.

So are you facing same error? If yes, then you are at right post.




Solution is very simple!

We found that when you download GlassHeader.tt and GlassItem.tt file, it has one extra blank line added in last line. Thanks to my colleague Mahek who helped me on this.

Remove this last blank line as suggested in below screens, and regenerate the code - you are done!



Hope this will help all those who are setting up TDS and GlassMapper in order to take advantage of auto code generation feature.

Have a Happy Sitecore Journey!

Friday, 18 September 2015

Sitecore Informatics Module: Now Compatible with Sitecore MVC Project!

Friends - many of you have already used Sitecore Informatics Module in your Sitecore Webform Project. If you have not used it yet, then give it a try - you will like it!

If you want to know more about Sitecore Informatics then visit my previous post about it. Sitecore Informatics will help you to view all your Sitecore Projects details at one place.

The information such as:
  • Total number of Sites in your Sitecore instance
  • Total number of Sublayouts in your Sitecore instance along with referrer pages and caching parameters
  • Total number of Templates in your Sitecore instance along with referrer pages
  • Total number of Content Items in your Sitecore instance
  • Total number of Media Items in your Sitecore instance
  • Total number of Users in your Sitecore instance

If you are using MVC in your Sitecore Project then previous version of Sitecore Informatics may not help you. Since I got few requests about MVC project support, thought to update this module and share it with community.




You can now download updated version from Sitecore MarketPlace: 
https://marketplace.sitecore.net/Modules/Sitecore_Informatics.aspx

You can also download source code along with Sitecore Package from github:
http://nileshthakkar.github.io/Sitecore-Informatics/

Hope you will enjoy this module!!!

Wednesday, 9 September 2015

Speed Up Your Sitecore Experience Editor Ribbon

This post is inspired from Sitecore Documentation article Improve the performance of the Experience Editor ribbon.

I will try to elaborate the same stuff by including step by step configuration and test case.

For any website, one of the crucial things is to improve it's performance. And one of the ways to gain the performance is to implement caching. So far as Sitecore is concern, we usually focus on live website by caching JS and CSS using different approach such as bundling and minification.

But what about Page Editor or Experience Editor performance? Experience Editor loads few extra Sitecore resources in order to render ribbon. So it would be really helpful if there is a way to cache this Sitecore Ribbon. In-fact, there is a way to accomplish this - and this blog post is all about that!

So let's see how to cache Sitecore Experience Editor Ribbon to improve site performance.

Steps:
1) Open [Sitecore Instance]\Website\sitecore\shell\client\Speak\Layouts\Layouts\Speak-Layout.cshtml

2) Add below string to the <HTML> tag.
 manifest="/sitecore/shell/client/Sitecore/ExperienceEditor/Html5AppCache.ashx"

So it would look like this:


That's it, you are done!

But you may have question - How can I confirm whether it's working? How can I check whether it's really caching Sitecore Experience Editor Ribbon?

You can confirm it by looking into Application Cache as shown in below figures.

Before ribbon caching:



After ribbon caching:



Hope this will give a smile to your Experience Editor user :) !!!

Special thanks to Martina who assisted me on this.

Sunday, 6 September 2015

How To Enable/Disable Code Generation For Particular Item in Sitecore TDS Project?

All of us know how to configure auto code generation in Sitecore TDS Project? It's very simple - you just need to select Enable Code Generation as shown in below figure.



But what if you want to exclude few items from this auto code generation? If you have such requirement then this post may help you.

Suppose you have configured Enable Code Generation for your Sitecore TDS project, so it will auto generate code for all of items under that project. Now if you want that some of items under that project should not be part of this auto code generation, then you can achieve it by configuring Code Generation Template property of all those items as highlighted below.


Configuring Code Generation Template as None will exclude that item from auto code generation and setting it back to blank will consider that item for auto code generation.

Wednesday, 2 September 2015

How to Access User Location - Latitude and Longitude?

You can now take advantage of HTML5 Geolocation API in order to get user's location details such as latitude and longitude.

What was our requirement?
1) Whenever user visits our website, we want to track user's location (e.g. latitude and longitude).  
2) Page should ask to access location only one time during that session, it should not ask every-time.
    Using geolocation API will ask user to whether user wants to share location or not?

Implementation:
Below code snippet shows how to use HTML Geolocation API and store user's location details in cookie so that it should not ask to share location each time.

Step-1:
Define two hidden textboxes to store user's latitude and longitude value.
   
   
Step-2: Write jQuery to access user's latitude and longitude and store it in cookie for future use.

HTML5 Geolocation API browser compatibility:
If you want to know which browsers support HTML5 Geolocation API then below screen-shot can help you.



User will be asked to share location only one time, then it will be stored in cookie for future use.



Hope this may help you to trace your user's location!

Is Dropdown Postback Not Working in Sitecore?

Wondering why your page is not getting postback when you select any dropdown item even-though you have set AutoPostback property to true?

If so, then it can be fixed by adding below configuration in your web.config file under    <typesThatShouldNotBeExpanded> section.
      
    
        System.Web.UI.WebControls.Repeater
        System.Web.UI.WebControls.DataList
        System.Web.UI.WebControls.GridView
        System.Web.UI.WebControls.ListView
        System.Web.UI.WebControls.FormView
        Microsoft.Reporting.WebForms.ReportViewer
        Telerik.Web.UI.RadGrid
        System.Web.UI.WebControls.LoginView
        System.Web.UI.WebControls.DropDownList
      

Thursday, 15 January 2015

Is your Sitecore 8 package installer goes in never ending loop?

Friends - Have you started your Sitecore 8 Journey? How's it? It's awesome.. right?
You will observe many new things while exploring Sitecore 8. This post will talk about one of such things.

Scenario:
If you find that your Sitecore 8 package installer is going in never ending loop, then this post may help you.


Reason:
If you look at your logs during package installation, then you may find few errors reported by Sitecore.Analytics.MongoDB. This tells that your Sitecore 8 instance is not able to connect with your Mongo DB.

Solution:
Well, solution is very simple. You need to start your MongoDB database process by firing below command:
mongod.exe --dbpath "[location of your MongoDB/data/db]"
For example:
mongod.exe --dbpath "C:\Program Files\MongoDB 2.6 Standard\data\db"

In case, if you haven't installed/configured MongoDB for your Sitecore 8 then you need to first setup MongoDB and then start MongoDB database process.

If you are looking for how to setup MongoDB then this link may help you.

After staring MongoDB database process, now try to install package in your Sitecore 8 instance and it should get installed without any issue.

Thursday, 1 January 2015

Happy New Year To All Of Sitecore Journey Readers!!!

Happy New Year 2015! 
A very happy new year to all the readers of Sitecore Journey blog. May 2015 be a successful and happy year bringing you and your family good health and a lot of happiness!


2014 - Year in Review
2014 was a very successful year for Sitecore Journey! In-fact 2014 was special year for Sitecore Journey as it took first child step on 30th January 2014.

Throughout this 2014 year, Sitecore Journey achieved many milestones. 
Here are few highlights:

This could not happen without your continuous reading and interest. I am thankful for having such a great crew of readers and associates who have continued to inspire me to always feel passionate about blogging.

Thank you for reading Sitecore Journey!!!