25 August 2015

Sitecore 8 tracking media download

As part of the implementation, we sometime have question about tracking. It happened few time in the past where clients wanted to track PDF download on there website. Using Sitecore 6 was a bit tricky as it was kind of tricky. In the past, I tried a few things including overriding the  Media Handler to trigger an event "Download PDF". Eventhough this was working I did not like the idea of overridding the media handler as it is always painful for Sitecore upgrade and else.

Well I have to say that I was quite pleased to see that this is now handled out of the box on Sitecore 8. This is done through Media Assets. You can find more about it in the following link: https://doc.sitecore.net/sitecore%20experience%20platform/marketing%20taxonomies/classify%20a%20media%20item%20as%20a%20digital%20marketing%20asset

So what do you need to do:

1- Open your Marketing Control Panel and add a New Taxonomy Asset Item:


2- Deploy your Media Asset folder:


3- You can now use your Media Asset on your Media Item directly:

4- Now the only thing left to do is to setup the Event tracking on your media item:

5- setting up the event on the media item, means that everytime someone will request the media item, sitecore will track the Media Assets with the corresponding event: Download. The event already exist in sitecore and is already hooked to the Marketing report:

There you go you are now tracking the Media requests.

Just a quick look at the magic behind, if you quickly uncompile the Sitecore DLL, look for the MediaRequestHandler class that processes '~/media' requests raise 'media:request' event.



Analytics defined in 'Sitecore.Analytics.RobotDetection.Media.MediaRequestHandler' handler that is supposed to do processing will checks:
  1. If Analytics is enabled for the site
  2. If requested item has some data in a tracking field
  3. Launches 'Tracker.StartTracking()' API which would initialize tracker ( 'startAnalytics' pipeline )
Happy coding

16 August 2015

Loop through renderings in presentation and get the associated datasource

Today I was asked for how you can programmatically loop through all the renderings for an item and get the datasource information for each of the rendering. That sounded like an interesting question so I decided to post it here... What we wanted to do was to push the datasource items through workflow when the main item is beeing approved. We will split this in 2 posts so it is not too long here. So on this first post we will just see some code that will loop through the presentation and retrieve the list of item set in the renderings datasource. To make it a little different, lets try to find those where the rendering is inside a specific placeholder and a device

Well I first started to create a context class that will have method like the following:  
        /// 
        /// Return renderings for a specific Placeholder for the current item and a specific device
        /// 
        /// 
        /// 
        /// 
        public IEnumerable GetRenderings(string placeholderKey, string deviceName)
        {
            var currentItem = Sitecore.Context.Item;

            Sitecore.Data.Fields.LayoutField layoutField = new Sitecore.Data.Fields.LayoutField(currentItem);
            Sitecore.Layouts.RenderingReference[] renderings = layoutField.GetReferences(GetDeviceItem(deviceName));

            var filteredRenderingList = new List();

            foreach (var rendering in renderings)
            {
                if (rendering.Placeholder.Contains(placeholderKey))
                {
                    filteredRenderingList.Add(new RenderingItemWrapper(rendering.RenderingItem));
                }
            }

            return filteredRenderingList;
        }

        /// 
        /// Return the settings including datasource ID for the renderings in a specific placeholder 
        /// For current item and specific device
        /// 
        /// 
        /// 
        /// 
        public IEnumerable GetRenderingsSettings(string placeholderKey, string deviceName)
        {
            var currentItem = Sitecore.Context.Item;

            Sitecore.Data.Fields.LayoutField layoutField = new Sitecore.Data.Fields.LayoutField(currentItem);
            Sitecore.Layouts.RenderingReference[] renderings = layoutField.GetReferences(GetDeviceItem(deviceName));

            var filteredRenderingList = new List();

            foreach (var rendering in renderings)
            {
                if (rendering.Placeholder.Contains(placeholderKey))
                {
                    filteredRenderingList.Add(new RenderingSettingsWrapper(rendering.Settings));
                }
            }

            return filteredRenderingList;
        }

        /// 
        /// Get the Device from the context database and the Device name
        /// 
        /// 
        /// 
        private Sitecore.Data.Items.DeviceItem GetDeviceItem(string deviceName)
        {
            if (Sitecore.Data.ID.IsID(deviceName))
            {
                return Sitecore.Context.Database.Resources.Devices.GetAll().Where(d => d.ID.Guid == new Guid(deviceName)).First();
            }
            else
            {
                return Sitecore.Context.Database.Resources.Devices.GetAll().Where(d => d.Name.ToLower() == deviceName.ToLower()).First();
            }
        }



You will note the difference between the IRenderingItemWrapper and IRenderingSettingsWrapper
The later has all the information about the Datasource Item.

Then you can have a method that will loop through your IEnumerable then check your datasource information:

        /// 
        /// Get the Datasources for all renderings inside a placeholders
        /// 
        /// 
        /// 
        public IEnumerable GetRenderingDatasources(string placeholderKey)
        {
            var renderingDatasources = new List();

            IEnumerable renderingsSettings = _presentationContext.GetRenderingsSettings(placeholderKey);
            foreach (var renderingSettings in renderingsSettings)
            {
                if (renderingSettings.DataSource != null)
                {
                    Sitecore.Data.Items.Item datasourceItem;
                    if (Sitecore.Data.ID.IsID(renderingSettings.DataSource))
                    {
                        datasourceItem = _sitecoreContext.GetItem(new Guid(renderingSettings.DataSource));
                    }
                    else
                    {
                        datasourceItem = _sitecoreContext.GetItem(renderingSettings.DataSource);
                    }

                    if (datasourceItem == null)
                        continue;

                    renderingDatasources.Add(datasourceItem);
                }
            }

            return renderingDatasources;
        }


Hope that help anyone...