Lucene Spatial Search Support Module

Lucene Spatial Search Support Module with Sitecore 8.1

I came across a need to implement a search based on zip code, latitude, longitude, and a radius. I quickly found out that this is a tall order in a short amount of time if implementing this type of functionality from scratch. However, the Lucene Spatial Search Support module came to the rescue…or did it? I am implementing a Sitecore 8.1 instance and it looks like the module was only good through 7.5 at the time of this post. There is an option to use SOLR Spatial Search Support module, and that IS updated through 8.1, but I didn’t have a driving need for SOLR on this project since my records being indexed were low in nature. So what is a Sitecore developer to do? Luckily, the Lucene Spatial Search Support module source code was available on GitHub, so I set out to get this module upgraded to 8.1. Time to get our hands dirty!

After cloning the repository from GitHub, I tried to build the project and there were many references missing, so I quickly grabbed a vanilla instance of Sitecore 8.1 rev. 160302 and added the references I needed to build the project. They are below:

Added to Sitecore.ContentSearch.Spatial project:

  • Sitecore.ContentSearch.dll
  • Sitecore.ContentSearch.Linq.dll
  • Sitecore.ContentSearch.Linq.Lucene.dll
  • Sitecore.ContentSearch.LuceneProvider.dll
  • Sitecore.Kernel.dll
  • Sitecore.Logging.dll

Added to Sitecore.ContentSearch.Spatial.DataTypes project:

  • Sitecore.ContentSearch.dll
  • Sitecore.Kernel.dll

I then had a build issue in this constructor in the LuceneSearchWithSpatialContext.cs:

protected LuceneSearchWithSpatialContext(ILuceneProviderIndex index, CreateSearcherOption options = CreateSearcherOption.Writeable, SearchSecurityOptions securityOptions = SearchSecurityOptions.EnableSecurityCheck)
: base(index, options, securityOptions)
{
Assert.ArgumentNotNull(index, "index");
this.index = index;
this.settings = this.index.Locator.GetInstance();
}

The Sitecore community never fails, and I found this on the Sitecore Stack Exchange where another developer simply commented out this constructor. I did the same and rebuilt the project but was missing a reference to a Sitecore.Abstractions.dll:

Sitecore.Abstractions Reference Missing

Sitecore.Abstractions Reference Missing

After adding in the Sitecore.Abstractions.dll to the Sitecore.ContentSearch.Spatial project, my project was successfully building. So I added this to the list of project references in addition to what was listed above:

Added to Sitecore.ContentSearch.Spatial project:

  • Sitecore.Abstractions.dll

Now it was time to make sure that the Sitecore.ContentSearch.Spatial.config was configured properly for 8.1. To my joy, it looks like there is a .config setup for version 8 that is disabled when I pulled from GitHub. I disabled Sitecore.ContentSearch.Spatial.config and enabled Sitecore.ContentSearch.Spatial.v8.config. Next, I added in my template criteria for my locations with the Template ID, LatitudeField, and LongitudeFields and then modified the index to use “sitecore_master_index” since I am testing this out locally and in live mode.

I added in the following .dll’s and .config file to the project I am working on that needs the spatial search feature:

  • Lucene.Net.Contrib.Spatial.dll
  • Sitecore.ContentSearch.Spatial.DataTypes.dll
  • Sitecore.ContentSearch.Spatial.dll
  • Spatial4nCore.dll
  • Sitecore.ContentSearch.Spatial.v8.config

After publishing my files and testing out, I got an error that said, “Current Index is not configured to use Spatial Search.

After some research, I realized that my index was set to use the wrong index earlier in code. Not only that, but one that wasn’t setup properly to for spatial search at all. After pointing to the correct index, publishing from Visual Studio, and then rebuilding my “sitecore_master_index” I was getting results back.

As I stated earlier, you can also perform spatial search with SOLR. If you have a client that has this type of environment (which is most right!?), I would take a hard look at SOLR for your client’s search provider.

You must use Solr if you have a scaled environment. This means you have:

  • two or more content delivery servers
  • two or more content authoring severs
  • separate servers for email, processing, reporting and publishing

Solr supports calls over HTTP(S) which means that the indexes are available to all servers in the environment that require it (content management and processing servers).

Big shout out to Ahmed Okour for the help that he provided for questions I had during the process. Happy coding!

Exposing Sitecore Item Properties when Using Code Generation with Glass.Mapper

When initially setting up TDS and with Glass.Mapper code generation in your solution, by default you get the initial properties from the Sitecore item:

  • Id – The ID for the item
  • Language – The language for the item
  • Version – The version of the item

However, what if you want something like the item name available to you like you have available when going through the standard Sitecore API? Don’t worry, the Glass.Mapper team has you covered and you can extend the GlassBase and IGlassBase respectively to get you your desired results.

After you got your initial setup of Code Generation setup with TDS, you simply go to your “glassv3header.tt” file and there you can extend the GlassBase/IGlassBase. However, if you start coding in this file you will have no Visual Studio Intellisense, so I actually wrote code in my ViewModel so I could see what was available in the SitecoreInfoType object. Below are a few:

SitecoreInfoType.Name
SitecoreInfoType.DisplayName
SitecoreInfoType.ContentPath

Once you can see what is available via Intellisense you can set them in the “glassv3header.tt” file appropriately when generating the code as such.

public partial interface IGlassBase
{
[SitecoreId]
Guid Id{ get; }


[SitecoreInfo(SitecoreInfoType.Language)]
Language Language{ get; }


[SitecoreInfo(SitecoreInfoType.Version)]
int Version { get; }

}

public abstract partial class GlassBase : IGlassBase
{

[SitecoreId]
public virtual Guid Id{ get; private set;}


[SitecoreInfo(SitecoreInfoType.Language)]
public virtual Language Language{ get; private set; }


[SitecoreInfo(SitecoreInfoType.Version)]
public virtual int Version { get; private set; }


[SitecoreInfo(SitecoreInfoType.Url)]
public virtual string Url { get; private set; }


[SitecoreInfo(SitecoreInfoType.Name)]
public virtual string Name { get; private set; }

}

This will work to get the item name. However, I noticed that ASP.NET MVC when using Html.Helpers with names of “name” will pull in the Item name into the textbox as the value. Hence, I had to change from “Name” to “ItemName” as such and I was back happy coding again and relieved myself of regression testing after making this change. Below is my modification to get the item name property:

[SitecoreInfo(SitecoreInfoType.Name)]
public virtual string ItemName { get; private set; }

Glass.Mapper, TDS, and Code Generation is a phenomenal tool and highly recommended for rapid development with Sitecore. Play around with it and you can get what you need every time. Happy Holidays!

Modifying Code to Add a Visitor to an Engagement Plan when upgrading from Sitecore 6.6 to 8.1

In my recent efforts during an upgrade from 6.6 to 8.1 I had to refactor some code to work with Sitecore 8.1 to add a visitor to an engagement plan. Below are my findings:

These were the .dlls that were referenced in the previous solution in 6.6:

* Sitecore.Analytics
* Sitecore.Automation.MarketingAutomation

I added in the Sitecore.Analytics.dll and that wasn’t all I needed apparently as I got some errors upon building the project.

using Sitecore.Analytics;
using Sitecore.Analytics.Automation.Data;

Looked like the Automation in Sitecore.Analytics was no longer there and has been moved. After a quick look through Reflecting on the Analytics libraries I had to add the Sitecore.Analytics.Automation.dll as a reference which would give me the Automation and MarketingAutomation that I needed.

Sitecore 8.1 Analytics

Sitecore 8.1 Analytics Libraries

Once that was in place I was able to refactor the code to work with the new Analytics code libraries for Sitecore 8.1.

Before:

using System;
using System.Collections.Generic;
using Sitecore.Analytics;
using Sitecore.Analytics.Automation.Data;
using Sitecore.Analytics.Data.DataAccess;
using Sitecore.Data;
using Sitecore.Rules;
using Sitecore.Rules.Actions;
using Sitecore.Form.Core.Configuration;
 
namespace Sitecore.Sandbox.Actions
{
    public class AddVisitorToEngagementPlan<T> : RuleAction<T> where T : RuleContext
    {
        public string ItemId { get; set; }
 
        public override void Apply(T ruleContext)
        {
            if (!Tracker.IsActive)
                Tracker.StartTracking();
 
            if (!Settings.IsAnalyticsEnabled || string.IsNullOrEmpty(ItemId)) return;
 
            var engagementPlanState = Sitecore.Context.Database.GetItem(ID.Parse(ItemId));
            if (engagementPlanState.TemplateID != ID.Parse("8CE2707A-3742-4A89-933B-065E5BE02BC9")) return;
 
            var engagementPlan = engagementPlanState.Parent;
 
            var visitor = Tracker.Visitor;
            var visitorLoadOption = new VisitorLoadOptions { Options = VisitorOptions.AutomationStates };
            visitor.Load(visitorLoadOption);
 
            if (Tracker.Visitor.DataSet.AutomationStates.Count > 0) return;
 
            AutomationManager.Provider.CreateAutomationStatesFromBulk(new List<Guid> { Tracker.CurrentVisit.VisitorId }, engagementPlan.ID.Guid, engagementPlanState.ID.Guid);
        }
    }
}

After:

You will notice that Sitecore.Automation.MarketingAutomation changed to Sitecore.Analytics.Automation.MarketingAutomation.

using System.Linq;
using Sitecore;
using Sitecore.Analytics;
using Sitecore.Analytics.Automation.MarketingAutomation;
using Sitecore.Data;
using Sitecore.Rules;
using Sitecore.Rules.Actions;
 
namespace Sitecore.Sandbox.Actions
{
    public class AddVisitorToEngagementPlan<T> : RuleAction<T> where T : RuleContext
    {
        public string ItemId { get; set; }
 
        public override void Apply(T ruleContext)
        {
            if (!Tracker.IsActive)
                Tracker.StartTracking();
 
            if (!Tracker.Enabled || string.IsNullOrEmpty(ItemId)) return;
 
            var engagementPlanState = Context.Database.GetItem(ID.Parse(ItemId));
            if (engagementPlanState.TemplateID != ID.Parse("8CE2707A-3742-4A89-933B-065E5BE02BC9")) return;
 
            var engagementPlan = engagementPlanState.Parent;
 
            Tracker.Current.Session.Identify(Context.User.Profile.UserName);
            var manager = Tracker.Current.Session.CreateAutomationStateManager();
 
            if (!manager.GetAutomationStates().Any()) return;
            manager.EnrollInEngagementPlan(ID.Parse(engagementPlan.ID.Guid), ID.Parse(engagementPlanState.ID.Guid));
        }
    }
}

Thanks goes to Brian Pederson for his blog post, which helped me on this issue: https://briancaos.wordpress.com/2015/01/26/sitecore-8-and-engagement-plans/

TDS Code Generation Best Practice for Images and Links Using Glass.Mapper

Just a few weeks ago, I ran into an issue with TDS where all the “Image” fields in my solution were not generated correctly by TDS during code generation. Hence, I had hundreds of “Image” fields that had no reference.

If you are not familiar with using TDS for code generation with Glass.Mapper, I would highly recommend you take a look here, as it truly is a phenomenal tool for rapid development by generating models from Sitecore items:

http://www.glass.lu/Mapper/Sc/Tutorials/Tutorial24

I was stumped as to why this might have happened. After taking a look around my Sitecore instance, and getting some tips from the Sitecore Community on Slack in room “TDS”, I was able to find out what the problem was. I had an “ImageBase” base template that was originally setup on a template. However, I inadvertently created another Image field on the template itself with the same field title. Hence, when it came time to code generate, TDS threw up an error, but then couldn’t come back from the code generation “Image” fields issue. Basically, I had hundreds of mis-referenced “Image” fields in my code generated models file.

After speaking with Kamruz Jaman, he gave me a pointer to possibly just explicitly reference the Image object. Great Idea right!? So my solution to this issue was by going into my glassv3item.tt file and searching for Image. Once I found it, I changed it from:

case "image":
    return "Image";
 
case "general link":
case "general link with search":
    return "Link";

to

case "image":
    return "Glass.Mapper.Sc.Fields.Image";

case "general link":
case "general link with search":
    return "Glass.Mapper.Sc.Fields.Link";

I did this for both the Image and Link so if me or my development team ever ran into this issue of double creating a field with the same name, working with bases and the template item, that TDS code generation would not break on the referencing of Image and Link fields. Hence, I consider it a best practice to explicitly reference those fields just for safe measure in all your projects with TDS & Glass.Mapper code generation. Happy coding!

No Analytics Tracking in Sitecore 8.1

Recently, I was diagnosing an issue as to why Sitecore Analytics was not working for one of our 8.1 recent installations. I started with this helpful blog post by one of the guys at nonlinear digital:

http://www.nonlinearcreations.com/Digital/how-we-think/articles/2015/10/Troubleshooting-Sitecore-8-XP-Analytics.aspx

Well, after thoroughly going through all the steps my analytics were still not working and no data was being received by MongoDB in my Interactions collection and my Reporting database (analytics) was not receiving any data. After speaking with Sitecore Support, they mentioned that in the Global.asax file you must derive from the Sitecore.Web.Application to support the session end handler. When I checked my Global.asax it was set to derive from System.Web.HttpApplication. Once I set to derive from Sitecore.Web.Application this cleared up a couple of errors within the solution relating to the VisitorIdentification SitecoreHelper for MVC (@Html.Sitecore().VisitorIdentification()) and using statement (@using SItecore.Mvc.Analytics.Extensions). But most important, tracking started working as my collections in MongoDB and Reporting DB started receiving data.

Moral of the story, don’t miss this step upon setup of your solution in the beginning of your setup to work with Sitecore 8 as it will prove hard to diagnose. Hopefully, this helps out others who run across this situation. Happy coding!

5 Steps To Content Editor Ribbon Buttons Using Sitecore Powershell Extensions

I have been playing around with Sitecore PowerShell Extensions now for about week or so and love the module. If you haven’t had an opportunity to really dive into SPE, I highly recommend you take a little time to learn a little bit about it as it will really open your eyes on how to get things done in Sitecore fast and efficiently. There is a bit of learning curve, but the reward is worth it when you see just how quickly you can get things done with little code once you get the hang of things. Here is a link to the SPE module on the Sitecore Marketplace:

https://marketplace.sitecore.net/Modules/S/Sitecore_PowerShell_console

For this blog post, I am going to be doing a walk-through of a basic Language Version Utility. I will show how to create a button in the ribbon that when clicked upon will show a dialog box with some instructions and a drop-down list, then allow the user to select a value from the drop-down list, and then and then execute a script passing in the value from the drop-down list as a parameter. All using Sitecore PowerShell Extensions and not one bit of C# code folks! Yes, I was blown away by this as well! You don’t even have to create the buttons in the ribbon the traditional way in the Core database as you typically needed to. SPE does it all for you!

Okay, enough of my excitedness (might not be a word, but I’m excited) on this module and let’s get down to business.

Step 1: I started with downloading the module and installing it. I know you got that part covered so moving on.

Step 2: Next, I right-clicked the Script Library item at /sitecore/System/Modules/Script Library and then Insert–>Module. I named it Language Version Utility and then clicked on the check box for Content Editor Ribbon then clicked Proceed. After a little bit, the script finishes and I have a new PowerShell Script Module called Language Version Utility in the Script Library. That looks something like this:

New Module Called Language Version Utility

New Module Called Language Version Utility

Step 3: For this utility I wanted to put a couple of buttons in the Versions tab of the Contextual Ribbon and group them in a chunk. Using SPE, all I had to do was create a new PowerShell Script Library under Versions, which I named “Copy” and then I simply added to 2 PowerShell Scripts called “Copy To Version” and “Create Versions” as children of “Copy” as such:

New Copy Chunk In Versions Tab Of Contextual Ribbon

New Copy Chunk In Versions Tab Of Contextual Ribbon

Step 4: I just picked some icons that I think would be snazzy for the PowerShell Scripts, “Copy To Version” and “Create Versions”, and then on to a super cool part. I simply opened up the PowerShell ISE in the Development Tools of the Sitecore Admin Desktop as seen below:

PowerShell ISE In Sitecore Desktop Development Tools

PowerShell ISE In Sitecore Desktop Development Tools

Then I clicked on the Settings tab, and clicked on the Rebuild All drop-down, and then clicked the option for Sync Library with Content Editor Ribbon. A script will run, and voila now I have a new chunk in the Versions Tab of the Contextual Ribbon called “Copy” with 2 Large buttons called “Create Versions” and “Copy To Version”:

Copy Chunk In Versions Tab Of Contextual Ribbon

Copy Chunk In Versions Tab Of Contextual Ribbon

Step 5: Now it’s time to start creating my script I want to run when I click either of the buttons. For this example, I will only discuss the “Create Versions” button. So all I have to do is right-click on the “Create Versions” PowerShell Script item and then click on “Edit with ISE” as seen below:

Edit With ISE

Edit With ISE

That will take me right into the PowerShell ISE so I can start creating my script I want to run when I click the “Create Versions” button.

The scripting itself is out of scope on this post, as you will need to familiarize yourself with the scripting using the manual to really start understanding how to script. However, I will post up my script that I used and give you some pointers on what I did to show you. Keep in mind that there are many examples that also come with the module as well. Look for what you can in the examples, repurpose, extend, and ask questions to those in the Slack channel for “module-spe” and you will be sure to receive some help from some Sitecore folks. We are all here to help!

Anyways, here is my script that runs when I click the “Create Versions” button:

$result = Read-Variable -Parameters `
 @{ Name = "languageItem"; Title="Choose A Language"; 
 Source="DataSource=/sitecore/system/Languages"; 
 editor="droplist"} `
 -Description "This script will recursively create language versions for each item under the currently selected node in the content tree using the selected language below. Make sure the correct node is selected now in the content tree. If not, cancel and choose your node in the content tree and try again." `
 -Title "Create Versions Script" -Width 400 -Height 200 -OkButtonName "Create Versions" -CancelButtonName "Cancel" -ShowHints

if($result -ne "ok")
{
 Exit
} 

Get-ChildItem -Recurse . | Add-ItemLanguage -TargetLanguage $languageItem.Name

Basically, I am creating a variable called $result that is taking a result from the Read-Variable cmdlet. Keep your eye on the Name parameter as we will use $languageItem later in the script as that is where the value will be stored when the user chooses a language. This can be a bit confusing at first. You will notice there is also a title, description, and some specs on the dialog box. But once, we get to the bottom, that’s where the important part is. I am basically getting the child items recursively of the item that was selected in the content tree, then adding a new version to each of the child items in the selected language from the user input, which in this case is Spanish. In order to create the version I needed the language name, which I got from the $languageItem.Name. Once this script is saved (after thorough testing in PowerShell ISE to ensure its working), we can try it out.  Let’s take a look at what happens now when I click on the “Create Versions” button using my selected item in the content tree and using a new language I added for Spanish:

Selected Item In Content Tree With No Child Spanish Versions

Selected Item In Content Tree With No Child Spanish Versions

Script Output For Create Versions

Script Output For Create Versions

Now, for those wondering, I could just have well put in a droptree in here to select a content tree item instead of having the user choose an item from the content tree and then click the button. However, I felt this might be a better user experience and a non-duplication of efforts. Also, that type of utility might be found in the Control Panel. But, remember…with SPE you can take advantage of all that and so much is possible! So experiment with what you feel works for the client!

Anyways, I choose the Spanish language and click on Create Versions and my script runs and when it’s done I now have a Spanish version for “Sample Item CA” and “Sample Item CB”.

New Spanish Version of Sample Item CA

New Spanish Version of Sample Item CA

Again, all this was done with no C# code at all! SPE is awesome, and I am sold on the efficiency and ease of use now after diving in first-hand and gaining some knowledge. I will be blogging on the module much more as I gain more familiarization with more advanced topics. Happy coding!

Typical Roles and Permissions Setup for Sitecore 8+

When initially setting up the roles and permissions for your new Sitecore 8+ site, you may be asking yourself what roles do I need for my organization typically? When you use the Role Manager to create your roles you may be asking yourself what roles do I need to create and what roles do they need to be a Member Of so my that role can have the correct functionality in Sitecore to perform their job? You also may be asking what permissions do I need to give to these roles in Security Manager?

Below is a typical setup seen in a lot of companies that are using Sitecore 8+. Keep in mind that the business needs will dictate what roles you may have and also that someone may be in more than one role, one person may be all roles, or there may be a separate person for each role. It’s all up to the business and it’s all customizable to the business needs.

Typically, you will want to have a couple of Administrators on the site so someone can always get in and perform Administrative type of duties if someone on vacation or out for some reason. This is as simple as choosing your power Sitecore user at the company and then typically Developers have Administrator access as well. Some will choose to create a Global SItecore Administrator role, which is a member of all roles. This works fine too. The added benefit, if needed, is that this role DOES NOT bypass workflows like the Administrators account does. In addition, it’s easy to see who your administrators are in one role.

As for everyone else that is non-designated power user or a developer, they will fall into one of these typical role buckets. Examples are for a company called “Sitecore Sandbox”:

SS Content Editor:

Typically, the Content Editors are the marketing or web team that are going to be in charge of editing content in Sitecore.

Member Of:

  • Author
  • Designer
  • Experience Editor
  • Sitecore Client Translating

SS Content Publisher:

Typically, the Content Publishers are the marketing team managers that will make final decisions to approve the content and then publish it live to the web.

Member Of:

  • SS Content Editor
  • Sitecore Client Publishing

SS Marketing Analyst:

Typically, the Marketing Analysts are the marketing team people who will be analyzing the effectiveness of the marketing efforts and possibly putting together reports for higher ups.

Member Of:

  • Analytics Reporting
  • Analytics Advanced Testing
  • Analytics Management Reporting
  • Analytics Content Profiling
  • Analytics Testing
  • Analytics Personalization

SS Marketing Administrator:

Typically, the Marketing Administrators are the marketing management team that has all the functionality of the Marketing Analysts but can also edit content as well.

Member Of:

  • SS Content Editor
  • SS Marketing Analyst

The permissions can be setup easily by going into the Security Editor and selecting the role you want to give permissions to. You will want to give read/write/rename/create/delete/administer permissions based on the role, but typically read/write/rename/create/delete is sufficient.

Now, when you setup the users in those roles they may not see what all they have access to UNLESS they check the “Hidden items” checkbox in the Views tab–>View chunk in the Contextual Ribbon. Make sure they know to do this or you may have them coming back to you with questions and you may be scratching your head on why they can’t see the items they need access to. Happy coding!