Google Events Integration with Sitecore

Purpose of this module

With the help this module user can easily create onclick events on different elements like anchors. Content editor can edit arguments of google events directly from Sitecore without opening code file.

What is google event tracking

  • Event Tracking is a method available in the ”ga.js” tracking code that we can use to record user interaction with website elements.
  • To track any event we need to call “on click” attribute with tracking arguments on anchor tag.
  • The specification for the _trackEvent() method is:
    _trackEvent(category, action, opt_label, opt_value, opt_noninteraction)

How this module work

To use this module please follow below steps –

  1. Install the provided Sitecore package. Package name is “GoogleEventTracking-1.0.zip”
  2. Update your web.config file to replace standard GetLinkFieldValue processor with the custom one
    1. Standard GetLinkFieldValue –
      <processor type=”Sitecore.Pipelines.RenderField.GetLinkFieldValue, Sitecore.Kernel” />
    2. Custom (Replace standard with this)
      <processor type=”Oasis.GoogleEventTracking.CustomGetLinkFieldValue, Oasis.GoogleEventTracking” />
  3. Once above setting is updated open Sitecore content tree. You can add google events to anchors using two fields type in Sitecore
    1. Rich Text Editor
    2. General Link
  4. To insert google event using Rich Text Editor follow below steps –
    1. Select any item which Contains RTE field.
      sitecorecode-GET1
    2. Select show editor option highlighted in above image. In RTE type any text like “Google Event”. Select this text and insert link on this text by selecting Hyperlink Manger from the tools of RTE.
      sitecorecode-GET2
    3. Select Analytics Events tab in Hyperlink Manager Popup and enter events details in the form as shown in below image
      sitecorecode-GET3
    4. Click ok when you are done
    5. Accept the changes in RTE and save the Sitecore item. This event will look like below in html of page. You can see this in Sitecore as well by clicking on HTML tab of RTE
      <a onclick=”_gaq.push(['_trackEvent','Category','Action','Label',1]);”>goolge event</a>
  5. To insert google event using General Link Field Type follow below steps –
    1. Select any item which Contains General Link field.
    2. Inset link detail by selecting Insert option Link
      sitecorecode-GET4
    3. To crate google event click on Google Event option highlighted in above image. It will open a popup with the form. Fill the form with proper argument for google event
      sitecorecode-GET5
    4. Click ok when you are done
    5. Save the Sitecore item. This event will look like below in html of page. You can see this in Sitecore as well by selecting raw value checkbox
      onclick=”_gaq.push(['_trackEvent','Category','Action','Label',Value]);”

Note – This package is based on assumption that webpages are already rending google event tracking js provided by google.

Sitecore Package is available on Sitecore market marketplace Click here to download

 

Share thisEmail this to someonePrint this pageTweet about this on TwitterShare on FacebookShare on Google+Share on TumblrShare on LinkedIn

How to use Sitecore dictionary domain in your Sitecore project

Purpose of this article is to explain new developers how to properly used dictionary domain. Good technical explanation of dictionary domain can be found here

Sitecore 6.6 introduces the concept of dictionary domains. In any database, you can create any number of dictionary domains, which are items based on the System/Dictionary/Dictionary Domain data template. On each dictionary domain you can specify the fallback domain. If certain key is not found in site specific dictionary domain then program will search key in fallback domain.

Follow below steps to use dictionary domain in your Sitecore website:

  1. Based on your Sitecore content tree structure create item of template “/configuration/sitecore/sites/site”. We normally use below structure in our project where we organize different sites in different folders in case of multi-site environment (you can use same structure for single website as well) and each site contains 2 node under it. One is used to store global setting (Used to store all global meta data used on different pages of website like header, footer) of this website and other is home item under which all pages of website get store
                Sitecore
                            Content
                                        Site One Node
                                                    Global Settings
                                                                Sample Dictionary Domain
                                                    Home
  2. Under dictionary domain folder you can add dictionary entries. You can create folder as well under dictionary domain to organize dictionary entries in logical structure. You can also nest dictionary domains
  3. Once dictionary domain structure is created in Sitecore content tree next step is to use dictionary in layout or sublayouts. There are two ways to use Sitecore dictionary

         i.    Define Dictionary domain in Sites setting in web.config.
                 a.  With this approach open web.config file and add dictionary domain attridute                                                                         (dictionaryDomain=”Sample Dictionary Domain”) to your  managed sites                                                                       (/configuration/sitecore/sites/site)
                b.  dictionaryDomain attribute in web.config could be name of dictionary domain or GUID of dictionary                                  domain
                c.  Use below code to get dictionary phrase using key in code
                                Sitecore.Globalization.Translate.Text(“key”);  

         ii.    You can also define dictionary domain in code as shown below                                                                                                  Sitecore.Globalization.Translate.TextByDomain(“Domian”,”Key”);

Must Read:

http://www.sitecore.net/Learn/Blogs/Technical-Blogs/John-West-Sitecore-Blog/Posts/2012/11/Sitecore-ASPNET-CMS-6-6-Features-Dictionary-Domains.aspx

As with any other pipeline, you can add processors to, remove processors from, and override processors in the getTranslation pipeline. For example, when porting an existing ASP.NET site into Sitecore, you could add a processor that looks for entries in the resource files from the old site if no entry for a key exists in the Sitecore dictionary system.

Share thisEmail this to someonePrint this pageTweet about this on TwitterShare on FacebookShare on Google+Share on TumblrShare on LinkedIn

SITECORE CDN CONNECTOR for Sitecore 7.x

Challenge – Existing Sitecore CDN connector available at click here is not working with Sitecore 7.2

https://marketplace.sitecore.net/en/Modules/Sitecore_CDN_Connector.aspx

Solution

Follow below steps –

  1. Download source code from github https://github.com/NTTDATA/SitecoreCDN
  2. Open this source code in visual studio. Go to project properties and update target framework to .Net framework 4.5zProject Property
  3. Update reference of below DLLs in this project to use new  DLLs from Sitecore 7.2
    1. HtmlAgilityPack
    2. Sitecore.Kernel
  4. Build the project and you should be all set to use this connector

In case of multisite environment you have to take care of 2 points –

  1. Update site name in sites patch define in config file SitecoreCDN.config

<sites>
<sitename="yoursitename">
<patch:attributename="cdnHostName">imagerepo</patch:attribute>
</site>
</sites>

  1. If you are using SiteDefinition.config to manage multiple sites then make sure SitecoreCDN.config execute after SiteDefinition.config file. One thing you can do is update name of SitecoreCDN.config by adding prefix “Z” like ZSitecoreCDN.config

CDN Sitecore connector package for Sitecore 7.2 can be downloaded from here

Conclusion – Existing CDN Sitecore connector contains reference of old DLLs  and .net framework. By updating reference it will start working with latest Sitecore version

Share thisEmail this to someonePrint this pageTweet about this on TwitterShare on FacebookShare on Google+Share on TumblrShare on LinkedIn

Custom Form Editor in Web Form For Marketer | Sitecore

Some time we encounter situation where we are using WFFM to create form but because of custom requirement we don’t want to use Sitecore in-built send mail action instead we want to write our own custom action.
In-built Send Email action editor GUI looks like below -

image001

Figure – 1

We want to update this GUI so that we can hide To, CC, BCC fields because we are not using these fields. Its always good to hide extra fields so that content editor will not get confuse. Now how can we do that? Answer is – follow below steps and you are all set:
1. There is an editor associated with inbuild send mail action. Sheet UI of this editor can be found at “website root\sitecore\shell\Applications\Modules\Web Forms for Marketers\Dialogs\Action Editor\SendEmail.xml” . UI of this editor is shown in fiture-1. First step is to create a copy this UI with name “CustomSendEmail.xml”
2. Open CustomSendEmail.xml file and change tag <SendMail.Editor> to <CustomSendEmail>

image002

3. In CustomSendEmail.xml file addd visible =”false” in below tags. This will hide to, CC, BCC fields from editor

image004

Please note – Right now we are only using existing editor code behind class that why we are only hiding controls not completely removing them from xml file. In next post I will explain you how you can create new class for editor

4. Now in Sitecore create a new custom action with name CustomSendEmail under /sitecore/system/Modules/Web Forms for Marketers/Settings/Actions/Save Actions. Update class name for custom action as shown in below image

image006

5.Now update editor name in field “Editor” under section “Editor” with value “Control: CustomSendEmail”. As shown in below image

image008

6. Save Custom save action item and you are all set.
7. Now assign CustomSendMail action to your form and UI of CustomSendMail will look like below.\

image010

Figure-2

Creating a custom action is 2 step process -
1. Create a class under your project in visual studio
2. Create custom action under “/sitecore/system/Modules/Web Forms for Marketers/Settings/Actions” and register custom action created in first step under it.

Share thisEmail this to someonePrint this pageTweet about this on TwitterShare on FacebookShare on Google+Share on TumblrShare on LinkedIn

Custom send email action with attachments in sitecore web form for marketer

Steps to send mail with attachment in web form for marketer by custom action

1. Create a custom send mail item under “/sitecore/system/Modules/Web Forms for Marketers/Settings/Actions/Save Actions” in sitecore.

2. Create custom class for this action and inherited by ‘ISaveAction, ISubmit’.

3. Enter Assembly name in Assembly field and class name in Class field of custom send mail item.

4. Create a custom send mail function (please note that tricky part of below code is getting reading attachment from media library)

// send email with attachments
public static bool SendEmailWithAttachments(string To, string From, string Subject, string Message, string atchmnt1, string atchmnt2, string atchmnt3) {
bool result = true;
try {
MailMessage mailMsg = new MailMessage();
// mailaddress of sender
MailAddress mailFrom = new MailAddress(From);
mailMsg.From = mailFrom;
// mail addresses for recipients
string[] mailAddressList = To.Split(',');
foreach (string str in mailAddressList) {
try {
MailAddress mailTo = new MailAddress(str.Trim());
mailMsg.To.Add(mailTo);
}
catch { }
}
mailMsg.Subject = Subject;
mailMsg.Body = Message;
mailMsg.IsBodyHtml = true;
if (!string.IsNullOrEmpty(atchmnt1)) {
mailMsg.Attachments.Add(ReadAttachment(atchmnt1));
}
if (!string.IsNullOrEmpty(atchmnt2)) {
mailMsg.Attachments.Add(ReadAttachment(atchmnt2));
}
if (!string.IsNullOrEmpty(atchmnt3)) {
mailMsg.Attachments.Add(ReadAttachment(atchmnt3));
}
var smtp = new SmtpClient(Sitecore.Configuration.Settings.MailServer, Sitecore.Configuration.Settings.MailServerPort);
smtp.Send(mailMsg);
}
catch {
result = false;
}
return result;
}
// get attachement by media item id
public static Attachment ReadAttachment(string value) {
MediaItem mediaItem = null;
ItemUri itemUri = ItemUri.Parse(value);
if (itemUri != null) {
Item item = Database.GetItem(itemUri);
if (item != null) {
mediaItem = new MediaItem(item);
}
}
// create attachment using media item properties
Attachment attachment = new Attachment(mediaItem.GetMediaStream(), string.Join(".", new string[] { mediaItem.Name, mediaItem.Extension}), mediaItem.MimeType);
return attachment;
}

 

Share thisEmail this to someonePrint this pageTweet about this on TwitterShare on FacebookShare on Google+Share on TumblrShare on LinkedIn

Some Html CSS tips and tricks

Some Html CSS tips and tricks Trick No. 1:We often need to use clear in our html so insted of using:
<divstyle="clear: both"></div> OR <divclass="clear"></div>

We can make use of pseudo selector :after,like this: ———–

.container {
        /*dummy attributes*/
        height:100%;
        width:100%
        margin:5px;
}
.container :after {
        display: block;
        clear: both;
        content: " ";
        height: 0;
        overflow: hidden;
}
.container childDiv {
       float:left;
}
——
It makes more sense if we are using LESS,as we can create a mixin for this as:
.clearfix() {
        &:after {
              display: block;
              clear: both;
              content: " ";
              height: 0;
              overflow: hidden;
       }
}
and then we can call this in our class,like this:
.container {
        /* this div has two floated child,*/
        /* so we must clear left/right after this div.*/
        /* calling the mixin,which will take care of clear.*/
        .clearfix;
        .div1 {
              float:left;
        }      
        .div2 {
              float:right;
        }
 }
Trick No. 2last-child/first-child are another pseudo selector,which are very useful,so if we want to apply some additional attributes to last/first child of certain class,we can use these selector. This is how these can be used:
.class-name {
     /* dummy attributes */
     height:100%;
     width:100%
     margin:5px;
 }
 .class-name:last-child {
     margin:0px;
 }
Trick No. 3:To select the next element, we can use + selector:
.class-name + span {
        /*dummy attributes*/
        height:100%;
        width:100%
        margin:5px;
 }
it will select the next span element. We can also select the next element with class name.

.class-name + .some-class {
        /* dummy attributes */
 }
Trick No. 4:If we want to make some portion of image clickable (hot spot),then we can insert an anchor with absolute position, e.g.:
.container {
       background: url('../images/container-bg.png') no-repeat;
       height:75px;
       width:75px;
       position:relative;
 }
 .hot-spot {
       position: absolute;
       bottom:0;
       right:0;
       height:28px;
       width: 28px;
       display: block;
       content:"";
 }
HTML for this
<div class="container">
        <!-- We can place this anchor anywhere under this div -->
        <a class=".hot-spot" href="#" alt="hot spot"></a>
        <!-- dummy text -->
        <p>
                Lorem ipsum dolor sit amet.Etiam a ipsum id purus.
        </p>
<div>
Note: if the element is positioned absolute, then its parent must be positioned relative.
Trick No. 5: For browser specific css, instead of creating different css/less files we should use this:
<!--[if IE 8 ]><head class="ie8"><![endif]-->
<!--[if (IE 9) |!(IE)]><!--><head><!--<![endif]-->
And define this class “ie8″ in the same css/less file. Happy Coding!!
Share thisEmail this to someonePrint this pageTweet about this on TwitterShare on FacebookShare on Google+Share on TumblrShare on LinkedIn

Import Export Content in Different Languages in Sitecore

Below image show content of a sample item in English language in fresh Sitecore instance.

Export

Now we will export it using Export language to a file wizard and Sitecore generates below XML

<sitecore>
<phrase path="/sitecore/content/Home/Sample Item" key="Sample Item" itemid="{9B53F11E-C767-4939-9587-E81FD1C401B1}" fieldid="Title" updated="20120921T155939">
<en>Sample Item</en>
</phrase>
<phrase path="/sitecore/content/Home/Sample Item" key="Sample Item" itemid="{9B53F11E-C767-4939-9587-E81FD1C401B1}" fieldid="Text" updated="20120921T155939">
<en>&lt;p&gt;Mitigate your risk and speed up time to market with our integrated solutions.&lt;/p&gt;</en>
</phrase>
</sitecore>

As we can see we have English content between the <en> tag.

Now, we will add content in some other languages.

It’s a very simple process, as we need to add content between the language specfic tag e.g., if we want to have content in French then we can add <fr> tag and we can add French content here.

Please note that we have to use language specific tags to enter content in that language. If you enter content of different language under<en>it will replace English language content for an item during import.

Now we have updated this xml to include translated content from different languages and produce below XML.

<sitecore>
<phrase path="/sitecore/content/Home/Sample Item" key="Sample Item" itemid="{9B53F11E-C767-4939-9587-E81FD1C401B1}" fieldid="Title"
updated="20120921T155350">
<en>Sample Item</en>
<fr>Article échantillon</fr>
<da>Sample Item</da>
<es>Muestra del artículo</es>
<ja-JP>サンプルアイテム</ja-JP>
</phrase>
<phrase path="/sitecore/content/Home/Sample Item" key="Sample Item" itemid="{9B53F11E-C767-4939-9587-E81FD1C401B1}" fieldid="Text"
updated="20120921T155350">
<en>&lt;p&gt;Mitigate your risk and speed up time to market with our integrated solutions.&lt;/p&gt;</en>
<fr>&lt;p&gt;Atténuer les risques et d'accélérer les délais de commercialisation de nos solutions intégrées.&lt;/p&gt;</fr>
<da>&lt;p&gt;Mindske din risiko og fremskynde time to market med vores integrerede løsninger.&lt;/p&gt;</da>
<es>&lt;p&gt;Mitigar el riesgo y acelerar el tiempo de comercialización de nuestras soluciones integradas.&lt;/p&gt;</es>
<ja-JP>&lt;p&gt;あなたのリスクを軽減し、当社の統合ソリューションを市場に出すまでの時間をスピードアップ。&lt;/p&gt;</ja-JP>
</phrase>
</sitecore>

When we imported above XML file in Sitecore it will automatically create different language version of Sitecore item present in file. After importing above xml file in Sitecore we can see 4 more languages items gets created for Sample Item. In below image we have select Japanese Version of Sample Item.

Import

Please note that if you don’t specify the language tag<fr> </fr>Sitecore will not detect the language while import.

 

Share thisEmail this to someonePrint this pageTweet about this on TwitterShare on FacebookShare on Google+Share on TumblrShare on LinkedIn

Add new tab in General Link field type of Sitecore

Task: Do you want to extend general link field type to include one more tab like create tab for tracking google events?

You can achieve this by following below steps:

1: Create a new item (Menu item) in core database under (/sitecore/system/Field types/Link Types/General Link/Menu).

2: Create a Class Library project.

3: Create a config file and write namespace, assembly and prefix.

<configuration xmlns:x="http://www.sitecore.net/xmlconfig/">
    <sitecore>
        <controlSources>
            <source mode="on" namespace="GoogleAnalyticsLib" assembly="GoogleAnalyticsLib" prefix="content"/>
        </controlSources>
    </sitecore>
</configuration>

4: Update the Control field of General Link Item by prefix (from config file) colon (:) class name which are responsible for handle message.

content:GoogleEvent

5: Write the content in message field of newly created item(Menu Item).

Ex. contentlink:GoogleEvent(id=$Target).

6: Create a class for open new tab in form window and inherit by Link class (Sitecore.Kernel).

Code -

public class GoogleEvent : Link
{
    // Sets the value.
    public void SetValue(string value)
    {
        Value = value;
    }
    // Gets the value.
    public string GetValue()
    {
        return Value;
    }
    // Handles the message.
    public override void HandleMessage(Sitecore.Web.UI.Sheer.Message message)
    {
        base.HandleMessage(message);
        if (message["id"] != ID || String.IsNullOrEmpty(message.Name))
        {
            return;
        }
        // in future can be some other message handling
        switch (message.Name)
        {
            case "contentlink:GoogleEvent":
            var url = new UrlString(UIUtil.GetUri("control:GoogleTrackinglink"));
            base.Insert(url.ToString());
            return;
        }
        if (Value.Length > 0)
        {
            SetModified();
        }
        Value = String.Empty;
    }
}
Note:The Message name should be same as new menu itemmessagefield content.

7: Create a XAML file with required fields.

Code of XAML for google event tracking:

<GoogleTrackinglink>
    <FormDialog
    Icon="Network/32x32/link.png"
    Header="Google Link"
    Text="Select the item that you want to create a link to and specify the appropriate properties."
    OKButton="OK" />
        <script type="text/javascript" language="javascript">
            function isNumberKey(evt)
            {
                var charCode = (evt.which) ? evt.which : event.keyCode;
                if (charCode > 40)
                if(charCode &lt; 48 || charCode > 57)
                {
                       return false;
                }
                return true;
            }
        </script>
        <CodeBeside Type="GoogleAnalyticsLib.GoogleEventLinkForm,GoogleAnalyticsLib"/>
        <DataContext ID="GoogleLinkDataContext"/>
        <GridPanel Columns="2" Width="100%" Height="100%" CellPadding="4" Style="table-layout:fixed">
            <Scrollbox Width="256" Height="100%" Background="transparent" Border="none" GridPanel.VAlign="top" GridPanel.Width="256">
                    <GridPanel CellPadding="2" Columns="2">
                            <Literal Text="Category:" GridPanel.NoWrap="true"/>
                            <Edit ID="Category"/>
                            <Literal Text="Action:" GridPanel.NoWrap="true"/>
                            <Edit ID="Action"/>
                            <Literal Text="Label:" GridPanel.NoWrap="true"/>
                            <Edit ID="Label1"/>
                            <Literal Text="Value:" GridPanel.NoWrap="true" />
                            <Edit ID="Value1" onkeypress="javascript:return isNumberKey(event);"/>
                            <Literal Text="Non-interaction:" GridPanel.NoWrap="true"/>
                            <Checkbox ID="Noninteraction"/>
                    </GridPanel>
            </Scrollbox>
        </GridPanel>
    </FormDialog>
</GoogleTrackinglink>
8: Create a class to handle the Dialog form fields
Code -
namespace GoogleAnalyticsLib
{
    public class GoogleEventLinkForm:DialogForm
    {
        protected Edit Category;
        protected Edit Action;
        protected Edit Label1;
        protected DataContext GoogleLinkDataContext;
        protected Edit Value1;
        protected Checkbox NonInteraction;
        Database masterDb = Sitecore.Configuration.Factory.GetDatabase("master");
        protected override void OnLoad(EventArgs e)
        {
            Assert.ArgumentNotNull(e, "e");
            base.OnLoad(e);
            if (Sitecore.Context.ClientPage.IsEvent)
            {
                return;
            }
            this.GoogleLinkDataContext.GetFromQueryString();
            string xml = StringUtil.GetString(new string[] { WebUtil.GetQueryString("va"), "" });
            string queryString = WebUtil.GetQueryString("ro");
            XmlDocument document = XmlUtil.LoadXml(xml);
            System.Xml.XmlNode node = document.SelectSingleNode("/link");
            string attribute = XmlUtil.GetAttribute("category", node);
            string str4 = XmlUtil.GetAttribute("action", node);
            string str5 = XmlUtil.GetAttribute("label1", node);
            string str6 = string.Empty;
            string str7 = XmlUtil.GetAttribute("value1", node);
            string str8 = XmlUtil.GetAttribute("noninteraction", node);
            this.Category.Value = attribute;
            this.Action.Value = str4;
            this.Label1.Value = str5;
            this.Value1.Value = str7;
            this.NonInteraction.Value = str8;
            string str11 = XmlUtil.GetAttribute("id", node);
        }
        // Handler for ok button click
        protected override void OnOK(object sender, EventArgs args)
        {
            Assert.ArgumentNotNull(sender, "sender");
            Assert.ArgumentNotNull(args, "args");
            this.GoogleLinkDataContext.GetFromQueryString();
            string xml = StringUtil.GetString(new string[] {WebUtil.GetQueryString("va"), ""});
            string queryString = WebUtil.GetQueryString("ro");
            XmlDocument document = XmlUtil.LoadXml(xml);
            System.Xml.XmlNode node = document.SelectSingleNode("/link");
            Packet packet = new Packet(document);
            SetAttribute(packet, "category", this.Category.Value);
            SetAttribute(packet, "action", this.Action.Value);
            SetAttribute(packet, "label1", this.Label1.Value);
            SetAttribute(packet, "value1", this.Value1.Value);
            SetAttribute(packet, "noninteraction", this.NonInteraction.Value);
            if (!string.IsNullOrEmpty(this.Category.Value) && !string.IsNullOrEmpty(this.Action.Value))
            {
                // get event tracking code from global header
                Item itm = ProServ.Globals.Common.GetGlobalHeader(masterDb);
                string onClickValues = itm.Fields["Google Event Tracking Code"].Value;
                string strParameters = null;
                strParameters = this.Category.Value;
                strParameters = strParameters + "," + this.Action.Value;
                if (!string.IsNullOrEmpty(this.Label1.Value))
                {
                    strParameters = strParameters + "," + this.Label1.Value;
                }
                if (!string.IsNullOrEmpty(this.Value1.Value))
                {
                    strParameters = strParameters + "," + this.Value1.Value;
                }
                if (!string.IsNullOrEmpty(this.NonInteraction.Value) && this.NonInteraction.Value=="1")
                {
                    strParameters = strParameters + "," + "true";
                }
                onClickValues = onClickValues.Replace("$EventDetail$", strParameters);
                string finalValues = onClickValues;
                SetAttribute(packet, "onclick", finalValues);
            }
            Sitecore.Context.ClientPage.ClientResponse.SetDialogValue(packet.OuterXml);
            base.OnOK(sender, args);
        }
        // set attribute name and value of controls
        private static void SetAttribute(Packet packet, string name, string value)
        {
            Assert.ArgumentNotNull(packet, "packet");
            Assert.ArgumentNotNullOrEmpty(name, "name");
            Assert.ArgumentNotNull(value, "value");
            packet.SetAttribute(name, value);
        }
    }
}

Share thisEmail this to someonePrint this pageTweet about this on TwitterShare on FacebookShare on Google+Share on TumblrShare on LinkedIn