Tuesday, 6 January 2015

Creating a Clicks report for Sitecore Email Experience manager (ECM)

Recently I was out on site with a client working through an ECM implementation and some questions came up around the reports that are provided out of the box. The reports that are provided out of the box are all looking at the value of a user interaction with an email, as opposed to whether they clicked a link in an email or not. While this provide you a much more rounded picture of how a user interact with an email and what value you can associate with a particular send a lot of people are still expecting the traditional "Click" report that you get from other email platforms.

So, I decided to build one.

The first thing to note is the ECM has been built to be extended and that it already collects all of the information to produce a click report. I recommend looking at the following to see how you can customise ECM:

Now that you have the background on where to customise ECM and where it stores its data, its just a matter of pulling the pieces together to build your own report.


I have open sourced an implementation on my git repository over at https://bitbucket.org/ctekempel/ecmreports and hope to add some more detail about the implementation when I get some time, but thought I would put it up now just in case I don't. Once you pull down the git repo you will need to:

  • Compile and copy across the appropriate files
  • Deserialize all of the items in the "items" folder
  • Add a report to each of the task types report pages in the ECM:
    • /sitecore/system/Modules/SPEAK/EmailCampaign/TaskPages/AdHockTaskPage/Reports
    • /sitecore/system/Modules/SPEAK/EmailCampaign/TaskPages/PeriodicalTaskPage/Reports
    • /sitecore/system/Modules/SPEAK/EmailCampaign/TaskPages/TrickleTaskPage/Reports

  • To add the report you need to add a “/sitecore/layout/Renderings/Email Campaign/Speak/ObjectDetailListObserver” control to the page and then set its datasource to “/sitecore/system/Modules/SPEAK/EmailCampaign/Controls/List views/Custom ECM Reports/Clicks”

If you have any questions before I get this post fully updated, drop a note in the comments and I will get back to it ASAP.

Also if anyone has ideas for other reports, or wants to contribute to it, please reach out.

Thursday, 2 October 2014

Sitecore Trendspot ANZ 2014

This week I had the opportunity to attend both the Sitecore Partner Summit and Trendspot down here in Sydney. Off the back of attending I thought I would share my top three take outs from the two events.

3. The Experience Database is the Future of Sitecore
More then anything else, the experience database is the key to success to Sitecore in the future and Sitecore is investing heavily in this area going forward.

If you haven't heard about it, it has been built as an efficient big data store for all of you data about people. I know that sounds like it is starting to take on the role of a CRM and it does feel like that when they present what it can do, but Sitecore has repeatedly said that it is not a CRM replacement, but it can certainly pull and push data into a CRM system.


The xDB, as its referred to, is tightly integrated into all parts of Sitecore, as you would expect, but has also opened up the ability to integrate data from a tonne of other sources. This is the major difference to the DMS that we have today.

2. The Device Ecosystem is Alive
At the moment I am feeling all inspired by the use of non-traditional digital channels by the partners and Sitecore themselves at the conference. 

There has been a lot of buzz for a while now around digital breaking out of the browser and the phone and starting to integrate with things like i-beacons, digital signage, second screen, etc. But to be honest it has all felt out of reach of the average project. This conference has shown that the technology has matured and it is now much easier to integrate these tools into you marketing plan, as well as into Sitecore. 

It has also shown what can be done when you start integrating all these things into Sitecore, leveraging some of the cool kit they have developed. With the new scale that's available  imagine the forms of communication you can have with your consumers if you connect  to one person via
  • in-store wi-fi 
  • iBeacons
  • web
  • print
  • TV/streaming
  • paid advertising
On top of that imagine if you can do it real time. This is what Sitecore is promising us and what some of the demonstrations have shown us.


1. Sitecore is not a CMS
The biggest take out for me from the conferences is that Sitecore is no longer just a CMS. With the work Sitecore is doing around experience marketing it is dramatically exceeding the boundaries of what we consider a CMS. I can see scenarios in the future where:

  • Sitecore is used to personalise and track sites that are built on other CMS's. Think legacy sites
  • Sitecore is used for email distribution
  • Sitecore is used as a pure marketing tool for tracking campaign success and consumer engagement across all platforms
Obviously all of these scenario's can be augmented by the CMS component of Sitecore, but in the future I see the CMS component of Sitecore be exactly that, a component in a bigger ecosystem of functionality that the platform provides.

Summary
The thing that surprised me most about what I have taken out of this conference, keeping in mind I'm a tech guy not a marketing guy, is that my take away's have all been around what can we do for people. There was certainly a lot of good tech presentations there, but I already have confidence in the platform from a tech point of view. The way the technology is evolving is allowing us to chase down those interesting cross platform project, which to be honest is quite exciting.

Monday, 7 July 2014

Leaving Global.asax in Sitecore Untouched

So one of the things I strive to do on each project I work on is to leave core systems completely untouched(where possible). There are two main reasons that I do this:
  1. The upgrade path. If you haven't modified the system you want to upgrade and you have no concrete dependencies on its files, then in theory you can upgrade it quite easily, by replacing it.
  2. Multi-tenant architectures. If you are working in a multi-tenant scenario, then avoiding modifying shared resources can make you life a lot easier, as individual applications are self contained.
With a lot of my work involving Sitecore, I come across these two scenarios quite regularly and up until recently I had strategies for managing:
  • Views/Layouts - separation by folder convention
  • Sitecore Items - separation by content tree convention
  • Sitecore configuration - separation by Sitecore config patching
  • .Net configuration - separation by asp .net configuration sections
But even with all of this I didn't have a great way of managing the separation of application start-up and shutdown events, that are typically setup in your global.asax file. Enter Web Activator (available on nuget here). To summarize the module simply it is a "A package that allows other packages to execute some startup code in web apps" (direct from the nuget site).

Now for an example, lets say we are using dependency injection and we want to setup our dependency configuration and then tear it down on application start-up/tear down and we don't want to alter and of the out of the box Sitecore files. The code looks something like:

   
[assembly: WebActivatorEx.PreApplicationStartMethod(typeof(UnityWebActivator), "Start")] 
[assembly: WebActivatorEx.ApplicationShutdownMethod(typeof(UnityWebActivator), "Shutdown")]

namespace Sample
{
    using System.Linq;
    using System.Web.Mvc;

    using Microsoft.Practices.Unity.Mvc;

    /// <summary>Provides the bootstrapping for integrating Unity with ASP.NET MVC.</summary>
    public static class UnityWebActivator
    {
        #region Public Methods and Operators

        /// <summary>Disposes the Unity container when the application is shut down.</summary>
        public static void Shutdown()
        { }

        /// <summary>Integrates Unity when the application starts.</summary>
        public static void Start()
        { }

        #endregion
    }
}

The important bits of this are:

  • WebActivatorEx.PreApplicationStartMethod - this invokes the specified type/static method combination for the global application start event.
  • WebActivatorEx.ApplicationShutdownMethod - this invokes the specified type/static method combination during application shutdown.
Now, armed with this, there is one less file you need to modify from a base Sitecore install.

Monday, 2 December 2013

Sitecore Parameters Template Field

As we move into using the DMS more and more often we are also starting to use the page editor more and more often. This leads to a need for making the way we insert sub-layouts/renderings easier for our users and it turns out Sitecore has made a start on this already by giving us small features that can make a big difference, in this case the "Parameters Template" field.

When you add a presentation component to a page in Sitecore you have the option of editing its component properties and this it what it looks like by default:



And if you wanted to customise the data being passed to this instance of the sub-layout(beyond the data source) you would need to add additional properties as key value pairs to the "Parameters" section. In my mind this is fraught with danger, it is free text and there is no guarantees around the names or types of values being passed to your control.
This is where the "Parameters Template" field comes into play. If you take a look at any of your sub-layout or renderings items you will notice there is a field called "Parameters Template"
By setting this field you are giving Sitecore a prompt on how to ask for the values when editing the "Component Properties" and allows you to name and type the values. 

All you need to do is create a template that inherits from the "Standard Rendering Parameters" template: create the fields you want and set the "Parameters Template" field to point to it.


And "Hey Presto!!", when you edit the component properties of the sub-layout you get the fields, named and typed. Therefore removing the possibility of typos and making the editing process that much nicer.


Now I should probably mention that this doesn't change anything form a code point of view in as much as these values all still come in via the parameters collection that you have without this field, its just making the editing process nicer.

Wednesday, 23 October 2013

Powershell File Watcher

Ok so today I had a situation where I needed a simple script to copy some website related artifacts to an output directory that would allow me to view the changes on a website. Now during this process I was making a lot of changes over time and wanted to automate the process.

PowerShell to the rescue.

The script below is fairly simple(and a little unrefined), but it does the job nicely. The script will continue to run until you press a key, at which point it will de-register all of its events and exit

The configurable parts are:

  • You can set the folder to watch with the $inputFolder variable
  • You can set the folder to copy changes to with the $outputFolder variable
  • You can set the extensions of the files that you want to copy with the $filters variable

$inputFolder = Resolve-Path '..\inputDirectory'
$outputFolder = Resolve-Path '..\outputDirectory'
$filters = @('*.css', '*.js', '*.html') 

$messageData = "$inputFolder|$outputFolder"


function RegisterWatcher($fileFilter)
{
    $fsw = New-Object IO.FileSystemWatcher $inputFolder, $fileFilter -Property @{IncludeSubdirectories = $true;NotifyFilter = [IO.NotifyFilters]'FileName, LastWrite'} 
     
    Register-ObjectEvent $fsw Changed -SourceIdentifier "FileChanged - $fileFilter" -MessageData $messageData -Action { 
        $sourceItem = $Event.SourceEventArgs.FullPath 
        $targetItem = $sourceItem.Replace($Event.MessageData.Split('|')[0], $Event.MessageData.Split('|')[1])

        Copy-Item $sourceItem $targetItem

        Write-Host "Copied $sourceItem"
    } 
}
 
foreach($filter in $filters)
{   
    RegisterWatcher $filter
}

Write-Host "Press any key to exit"

while ($true) {
    if ($Host.UI.RawUI.KeyAvailable) {
        break;
    }
    Start-Sleep -m 1000
}

foreach($filter in $filters)
{
    Unregister-Event "FileChanged - $filter"
}

Thursday, 10 October 2013

Webforms MVP and Sitecore 7 POCO/Content Search

Lately I have been doing some work with Sitecore 7 and I had a requirement to work with the webforms rendering engine(as opposed to the MVC rendering engine), while doing this implementation I came across a nice pattern, it turns out Webforms MVP and Sitecore POCO/Content Search play really well together.

Before I get into the details, let me explain what both of these tools are:

  • Webforms MVP is a in implementation of the Model View Presenter pattern that has been floating around the ASP .NET webforms world for a while now. It promotes the separation of rendering and logic concerns in a similar way to MVC. The project website is http://webformsmvp.com/ and there is a bunch more information there.
  • Sitecore POCO/Content Search is the new search API that has come out as part of Sitecore 7. The easiest way of thinking about it, and one if its most useful features, is LINQ to Lucene. This results in a nice strongly typed LINQ/IQueryable syntax for interacting with Lucene indexes, allowing you to bypass the Sitecore databases for a lot of queries, resulting in a faster site.
Now for the bit where these patterns work well together. 

Webforms MVP has been used by a lot of people in Sitecore development for a while, but has traditionally had one major floor in the resulting implementation - a lack of page editor support. With the MVP approach requiring the creation of a "model" class, a lot of developers pass this model up to the rendering layer and render the values using traditional asp .net controls (e.g. asp:literals, asp:hyperlink etc.), as opposed to using Sitecore controls(e.g sc:text, sc:image etc.). While this wasn't explicitly necessary it kind of happened by default, especially if you wanted to use test driven development on your repository/logic layers. 

But, things have changed. Sitecore 7 and its content search API is based around model classes, and facilitates test driven development in a way Sitecore 6 never did.

So if we are now working with model classes how do we use the page editor? Well Sitecore thought of this as they were developing their new API and introduced a class with a particular method: SearchResultItem.GetItem(). This method allows your to retrieve the Item relating to a model as long as it is based on SearchResultItem.

With all of this wired up we have a nice middle ground with somewhat testable code, a nice user experience and a nice separation of concerns.

A sample Model:
    public class SampleModel : SearchResultItem
    {
        public string NonEditableField { get; set; }
    }

A sample presenter with Content Search Query:
    public class SamplePresenter : Presenter<IView<SampleModel>>
    {
        public SamplePresenter(IView<SampleModel> view)
            : base(view)
        {
            this.View.Load += this.Load;
        }
        private void Load(object sender, EventArgs e)
        {
            var item = Sitecore.ContentSearch.ContentSearchManager.GetIndex("sitecore_web_index")
                .CreateSearchContext()
                .GetQueryable<SampleModel>()
                .FirstOrDefault(model => model.NonEditableField == "something");
            this.View.Model = item;
        }
    }

A sample view:
<%@ Control Language="C#"
    AutoEventWireup="true"
    CodeBehind="SampleView.ascx.cs"
    Inherits="Layouts.SampleView" %>
<asp:Literal runat="server" ID="nonEditableField"></asp:Literal>
<sc:Text runat="server" ID="editableField"/>

And its sample code behind:
[PresenterBinding(typeof(SamplePresenter))]
    public partial class SampleView : MvpUserControl<SampleModel>
    {
        protected override void OnPreRender(EventArgs e)
        {
            this.nonEditableField.Text = this.Model.NonEditableField;
            this.editableField.Field = "Editable Field";
            this.editableField.Item = this.Model.GetItem();
        }
    }

Tuesday, 9 July 2013

Sitecore 7 patch:source

One of my favourite new features in Sitecore 7 is actually a fairly small, seemingly insignificant one. If you browser the config viewer(/sitecore/admin/showconfig.aspx) in Sitecore it will now show you which config patch settings are applied from.

<sitecore>
 <events timingLevel="custom">
  <event name="item:deleted">
   <handler patch:source="Sitecore.Analytics.config"/>
  </event>
 </events>
</sitecore>


Now if you have ever worked on a project with a lot of config patch includes related to various modules, this can be extremely useful.

How to disable "Add Users" in Sitecore's Platform DXP

 I have seen a few posts going around the community asking how to disable the "Add Users" button in Sitecore Platform DXP.   This ...