Showing posts with label DMS. Show all posts
Showing posts with label DMS. Show all posts

December 6, 2013

Creating an HTTP Referrer Condition

By: Craig Taylor
December 6, 2013

Creating an HTTP Referrer Condition

Having the ability to tailor the site experience to your users is one of the major selling points of Sitecore.  One way to customize this user experience is to change content based on the HTTP referrer.

You can see Sitecore's out-of-the-box conditions in the content tree under "\sitecore\System\Settings\Rules\Conditional Renderings\Conditions".  While Sitecore has a folder called "Referrers" here that contains conditions that involve the referrer, there is not one included that compares the name of the referrer. I was surprised to see that Sitecore didn't already have a built-in condition for this, but it doesn't matter too much as Sitecore is easily extensible.  Let's create a new condition to check against.

Creating the Condition

Creating our new condition involves two steps:

  1. Writing code that can check the referrer.
  2. Wiring up the condition to our code that we created in step #1.
We need to write the code for the condition.  Either create a new solution or open up an existing solution that you would like to add your condition to.  I have opened a 'common' solution that contains common code that can be used across multiple sites.

using Sitecore.Rules;
using Sitecore.Rules.Conditions;
using System.Web;

namespace Client.Common.Conditions
{
    public class HttpReferrerContains : WhenCondition where T : RuleContext
    {
        public string HttpReferrer { get; set; }

        protected override bool Execute(T ruleContext)
        {
            if (!string.IsNullOrEmpty(HttpReferrer))
            {
                if (HttpContext.Current.Request.UrlReferrer != null && HttpContext.Current.Request.UrlReferrer.ToString().ToLower().Contains (HttpReferrer.ToLower()))
                {
                    return true;
                }
            }
            return false;
        }
    }
}

So what's going on here?  We are creating a new class that implements "WhenCondition" and "RuleContext."  We specify a public string (HttpReferrer) that will be passed into this class from Sitecore.  We override the base "Execute" method so that we can perform our own check to see if the referrer matches the value that we are looking for as passed in from Sitecore.  If the current UrlReferrer matches the value that we passed in from Sitecore, we return a "true" and we return "false" otherwise.

Now we move on to wiring up the condition inside of Sitecore.  Let's go down to the "\sitecore\System\Settings\Rules\Conditional Renderings\Conditions" folder mentioned earlier.  Right-click on the "Referrers" subfolder and insert a new condition.

Sitecore Conditions

The two fields we are interested in here are "Text" and "Type."  The "Text" field is where you specify how the condition will appear to the content author.

Sitecore Condition Text Field
The first portion of this field is the text that is displayed to the content author.  Inside the square brackets, the field consists of 4 parameters:

  1. 1st parameter: Name of the parameter being passed into your custom code.
  2. 2nd parameter: Name of a macro item.  Here, you can choose an item from "\sitecore\System\Settings\Rules\Common\Macros" and have that macro pop up when the content author clicks the 'clickable' word.
  3. 3rd parameter: Path passed to the macro parameter. (2nd parameter)
  4. 4th parameter: The 'clickable' word.
Our example generates the following box:

Sitecore Rule Set Editor


When the content author clicks on "specific value", they are prompted to enter a value to compare.  Also note that "where" is clickable as well and can be switched to "except where."

In the "Type" field, we add a reference to the assembly we created/added to in step #1.

Sitecore Condition Type Input

And that's it!  Now, when you go to personalize a component on the page, you can do so based on the HTTP referrer.

Additional Reading

See how Pieter created a condition and used a slightly different approach where you store the referrers as Sitecore items in the content tree as opposed to allowing free-text entry into the condition by the content author: http://newguid.net/sitecore/2011/sitecore-rules-engine-how-to-create-a-custom-condition/ 

September 20, 2013

Editing DMS Reports to be Multi-Site Friendly

By: Craig Taylor
September 20, 2013

Making DMS Reports Mult-Site Friendly
My client is using a single instance of Sitecore with multiple sites.  While reveiwing Sitecore's built-in reports for DMS, I noticed something that was going to make it difficult to produce reports that could be broken down by site.

Specifically, when looking at the "Latest Visits" report and when drilling down to the "Visit Detail (Session)" report, I noticed that I can't differentiate between the separate sites.  I would only see the visits as "/home" or "/contact-us."  It is impossible to know which site on the instance the visitor visited.

The Solution

In order to see which site was visited, we need to edit the default report provided by Sitecore.  In this example, we'll look at the "Visit Detail (Session)" report.  This can be accomplished in two steps:

  1. Edit the SQL Query for the report
  2. Edit the Report

Edit the SQL Query for the report

The SQL query for the "Visit Detail" report is located at \sitecore\System\Settings\Analytics\Reports SQL Queries\Visit Pages.  We need to update this query to include the site that was visited.  Luckily, DMS logs this information and stores it in the "Visits" table, in the "MultiSite" column.  We can add this "MultiSite" column to our query and once updated, the (SQL) query should look like this:
SELECT [Duration], [Url], [PageId], [PageId] as [PageIdObject], [Visits].[MultiSite] as [Site]
FROM [Pages] INNER JOIN [Visits] ON [Pages].[VisitorId] = [Visits].[VisitorId] AND [Pages].[VisitId] = [Visits].[VisitId]
WHERE 
  [Visits].[VisitId] = @VisitId
ORDER BY [DateTime], [VisitPageIndex]
I've given my "MultiSite" column an alias of "Site" for clarity.

Note: Even if you're not using Oracle, you might as well update the Oracle script as well in case a database switch is made later down the road:
SELECT "DURATION", "URL", "PAGEID", "PAGEID" as "PAGEIDOBJECT", "VISITS"."MULTISITE" as "SITE"
FROM "PAGES" INNER JOIN "VISITS" ON "PAGES"."VISITORID" = "VISITS"."VISITORID" AND "PAGES"."VISITID" = "VISITS"."VISITID"
WHERE 
  "VISITS"."VISITID" = :VisitId
ORDER BY "DATETIME", "VISITPAGEINDEX"

Edit the Report

Now that the report query has been updated to include which site was visited, we need to update the report to display this information.  While viewing the report, you can click the "Design" button in order to open the Stimulsoft Reports Designer application to edit the report.  I'm sure this might work well, but I wasn't able to get it to work correctly.  I instead went straight to the ".mrt" file in order to edit the report.  The mrt file for the "Visit Detail" report is located at \Website\sitecore\shell\Applications\Analytics\VisitDetail.mrt.  Open it up in your favorite text editor and you will see that it's just XML.

I searched in this file for where the other columns of the report query were being used.  I found the list of columns that were added and I added an additional column for my 'site' column:
<value>Site,System.String</value>
I also incremented the 'count' value for the columns.  The complete section looks like this:
<VisitPages Ref="5" type="Stimulsoft.Report.Dictionary.StiSqlSource" isKey="true">
        <Alias>VisitPages</Alias>
        <Columns isList="true" count="8">
          <value>Url,System.String</value>
          <value>Duration,System.Int32</value>
          <value>Hour,Hour,System.Int32,VisitPages.Duration_x002F_3600</value>
          <value>Minutes,Minutes,System.Int32,VisitPages.Duration_x002F_60</value>
          <value>PageId,System.Guid</value>
          <value>PageIdObject,System.Object</value>
          <value>DurationTimespan,DurationTimespan,System.TimeSpan,new_x0020_TimeSpan_x0028_0_x002C__x0020_0_x002C__x0020_0_x002C__x0020_0_x002C_VisitPages.Duration_x0029_</value>
          <value>Site,System.String</value>
        </Columns>
        <CommandTimeout>0</CommandTimeout>
        <Dictionary isRef="1" />
        <Name>VisitPages</Name>
        <NameInSource>DataConnection</NameInSource>
        <Parameters isList="true" count="1">
          <value>_x0040_VisitId,,14,0</value>
        </Parameters>
        <SqlCommand />
      </VisitPages>

This allows the report to make use of the field, but we now need to add the field to the report.  I then searched for where the text was being built for displaying the page visited.  I found this and added the site name in:
<Text>{string.IsNullOrEmpty(VisitPages.Url)|| VisitPages.Url == "/" ? VisitPages.Site + "/default.aspx" : VisitPages.Site + VisitPages.Url}</Text>

The complete section looks like this:
            <Text21 Ref="58" type="Text" isKey="true">
              <Brush>Transparent</Brush>
              <ClientRectangle>4.83,0,13.97,0.4</ClientRectangle>
              <ComponentStyle>GeneralText</ComponentStyle>
              <Conditions isList="true" count="0" />
              <Font>Arial,10</Font>
              <Margins>0,0,0,0</Margins>
              <Name>Text21</Name>
              <Page isRef="11" />
              <Parent isRef="55" />
              <Text>{string.IsNullOrEmpty(VisitPages.Url)|| VisitPages.Url == "/" ? VisitPages.Site + "/default.aspx" : VisitPages.Site + VisitPages.Url}</Text>
              <TextBrush>Black</TextBrush>
              <TextOptions>HotkeyPrefix=None, LineLimit=False, RightToLeft=False, Trimming=None, WordWrap=True, Angle=0, FirstTabOffset=40, DistanceBetweenTabs=20,</TextOptions>
              <Type>Expression</Type>
            </Text21>

The Results

Now, when drilling down from the "Latest Visits" report to the "Visit Detail" report, we can see that the (redacted) site name is now present on our report:
DMS Visit Detail Multisite Report

August 1, 2013

Creating a GeoIP Lookup Provider for Sitecore using MaxMind’s GeoLiteCity Database

By: Craig Taylor
August 1, 2013

GeoIP lookup provider in Sitecore
Sitecore ships with a built-in GeoIP lookup provider that is configured to use MaxMind’s lookup service. This service is provided for free with a “number of free lookups for testing and implementation convenience” (Engagement Analytics 6.6 Configuration Reference) This service works great, but what happens when your ‘number of free’ lookups expires?

GeoIP Options

When your free intro period expires, you essentially have two options if you want to continue to perform GeoIP lookups.
  1. Migrate to the MaxMind-Sitecore integrated service. (http://www.maxmind.com/en/sitecore) 
  2. Write your own, custom lookup provider.
While the MaxMind-Sitecore integrated service is amazingly simple to implement and run, I wanted to see what else could be used.  

The provider is essentially a ‘black box’ to Sitecore.  It doesn’t matter if it uses a web service, a local database or even a local file to return data lookups.  I decided to try to integrate with a local version of the GeoLiteCity database that is available for free download and use from MaxMind. (http://dev.maxmind.com/geoip/legacy/geolite/)

Creating a new Lookup Provider

Creating a new provider is as simple as creating a class that overrides the “GetInformationByIp” method.  
All we need to do is map the path to the database:

string geoLitePath = Settings.GetSetting(ModuleName + ".DatabaseLocation.GeoLiteCity", "~/app_data/GeoLiteCity.dat");

Pass the IP address to the look up service:

var lookUpService = new LookupService(HostingEnvironment.MapPath(geoLitePath), LookupService.GEOIP_STANDARD);

var location = lookUpService.getLocation(ip);

and populate the “WhoIsInformation” object so that Sitecore can use it:

WhoIsInformation information = new WhoIsInformation();
...
if (location != null)
{
    information.Country = location.countryCode ?? string.Empty;
    information.Region = location.regionName ?? string.Empty;
    ...
}

return information;



Update the Config

After you have created your new provider, update the “Sitecore/lookupManager/Providers” node in the web.config to include a reference to it.  It’s best to do this through a patch include file.


      
        geoLite
        
          />
        
      

And that’s it!  Sitecore makes it easy to change your GeoIP provider to anything else you may want to use. 
You can find complete source code and everything necessary to run this solution in the Sitecore Marketplace.