Skip to content

Custom Tokens in Email Campaign Manager

Recently I had a requirement from a client where they wanted to use Sitecore Email Campaign Manager to send registration emails, containing registration details and other dynamic custom data. Here is how to create tokens within a Email Campaign message and replace them with variables in a manually triggered email.

  1. Add your token(s) into the body text of the campaign message in the format $key$, ensure that the key text is lower case.

    Sitecore Custom Tokens

    Sitecore Email Campaign Manager Custom Tokens

  2. Get the message using the Sitecore API, replace the variables using the CustomPersonTokens dictionary and then trigger the send pipeline. The CustomPersonToken dictionary requires the key to be in lower case and requires the surrounding $$ to be removed.
//Get the message using the Sitecore API
var mi = Sitecore.Modules.EmailCampaign.Factory.GetMessage(messageId);

//Use the custom person token dictionary to replace the key with a string variable. Remember that the token key has to be lower case and remove the $$ surrounding the key
 mi.CustomPersonTokens.Add("username", "MikeTest");

//Send the message
new AsyncSendingManager(mi).SendStandardMessage(contactFromName);

Trigger Email and Replace tokens

Here is a reusable function that allows you to send an email campaign message from code and replace custom tokens.

public void SendEmailCampaignMessage(ID messageId, string userName, Dictionary<string, string> customTokens = null)
        {
            var mi = Sitecore.Modules.EmailCampaign.Factory.GetMessage(messageId);

            if (customTokens != null)
            {
                foreach (var token in customTokens)
                {
                    mi.CustomPersonTokens.Add(token.Key, token.Value);
                }
            }

            var contactFromName = Contact.FromName(userName);

            new AsyncSendingManager(mi).SendStandardMessage(contactFromName);
        }

Publish And Send For Translate Workflow Action

Here is a useful Custom Workflow action I’ve written allowing a content editor to publish a content item to live while also sending its alternative language version to a translate workflow state. This allows a content item to be published to live in a single language without being held up waiting on a translation to be completed.

  • 1. Create a workflow command to publish the content to the published state in workflow.
  • 2. Create a new custom workflow action underneath the publish command.
  • 3. Use the code below to automatically create a new language version and set the workflow state to translation state.
  • 4. Replace the parameters in the screenshot of the custom workflow action. Replace the targetstate parameter with the ID of the target language state. Replace language with the name of the target language

Publish And Translate Action

using Sitecore;
using Sitecore.Data;
using Sitecore.Data.Items;
using Sitecore.Data.Managers;
using Sitecore.Diagnostics;
using Sitecore.Globalization;
using Sitecore.Web;
using Sitecore.Workflows.Simple;

namespace MikeRobbins.SitecoreComponents.WorkFlow
{
    public class PublishAction
    {
        public void Process(WorkflowPipelineArgs args)
        {
            Item workFlowItem = args.DataItem;

            var targetLanguage = GetTargetLanguage(args.ProcessorItem.InnerItem);
            var targetVersion = Sitecore.Context.ContentDatabase.GetItem(workFlowItem.ID, targetLanguage);

            if (targetVersion.Versions.Count == 0)
            {
                targetVersion = targetVersion.Versions.AddVersion();
            }

            var targetWorkflowState = GetWorkflowState(args.ProcessorItem.InnerItem);

            SetWorkflowState(targetVersion, targetWorkflowState.ID);
        }

        private static void SetWorkflowState(Item welshVersion, ID targetWorkflowState)
        {
            welshVersion.Editing.BeginEdit();
            welshVersion.Fields[FieldIDs.WorkflowState].Value = targetWorkflowState.ToString();
            welshVersion.Editing.EndEdit();
        }

        private static Item GetWorkflowState(Item actionItem)
        {
            ID translateId = null;

            return ID.TryParse(WebUtil.ParseUrlParameters(actionItem["parameters"])["targetstate"], out translateId) ? Sitecore.Context.ContentDatabase.GetItem(translateId) : null;
        }

        public Language GetTargetLanguage(Item actionItem)
        {
            var language = WebUtil.ParseUrlParameters(actionItem["parameters"])["language"];

            Assert.IsNotNullOrEmpty(language, "Language needs to be specified as a parameter (&language=cy-gb)");

            return LanguageManager.GetLanguage(language);
        }
    }
}

Sitecore 7 Search ID Array Type Converter

This is a simple type converter that allows you to convert a collection of Sitecore IDs stored in a Lucene search index into a List.

public class ListIDConverter : TypeConverter
    {
        public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
        {
            if (sourceType == typeof(List<ID>))
            {
                return true;
            }

            return base.CanConvertFrom(context, sourceType);
        }

        public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
        {
            if (destinationType == typeof(List<string>))
            {
                return true;
            }
            return base.CanConvertTo(context, destinationType);
        }

        public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
        {
            var scIds = new List<ID>();

            var ids = (List<string>) value;

            foreach (var id in ids)
            {
                ID scId;
                if (ID.TryParse(id, out scId))
                {
                    scIds.Add(scId);
                }
            }

            return scIds;
        }
    }

To use the Type converter decorate your public property with the TypeConverter in your Search Result class.

    [TypeConverter(typeof(ListIDConverter))]
        [IndexField("_templates")]
        public List<ID> Templates { get; set; }

Sitecore 7 Search by base templates

Quick tip, when using Sitecore 7′s search API to build a general site search, you may want to return only pages rather than any other items within Sitecore. All my page items inherit from a base Item to implement page title, meta data and so on. Using linq we are able to check whether an item is based on a specific base template, to do this we need to tell Sitecore to index the base templates.

By default in Sitecore 7 indexing base templates is disabled to improve the indexing speed. This is very simple to switch on.

Inside the section within your index uncomment the line below.

 <field fieldName="_templates" storageType="yes" indexType="untokenized">Sitecore.ContentSearch.ComputedFields.AllTemplates, Sitecore.ContentSearch</field>

Rebuild your index and these base templates are now accessible in your search result class.

Sitecore Data Importer / Word docx Importer

I recently had a requirement from a client to allow them to import content into Sitecore items from word docx files. After looking on the Sitecore marketplace and git hub I realised nothing existed so decided on writing a module. I did quickly realise why nobody has written one before docx files are basically zip files containing a number of files with the main document content written in XML.

The document

To be useful I wanted the importer to be able to split the docx file into fields within a Sitecore item rather than drop the entire contents into one rich text editor field. This became an issue, how could I tell which section of the document related to which field.

The solution I came up was using the “Title” button in Microsoft Word to mark each section of the document. The title would match up exactly with the field name within Sitecore. Using this structure means that I could programmatically read all content between titles and know which field in Sitecore that content related too.

Sample Document

Sample Document

Import Module

The actual Sitecore data importer module has a simple interface allowing the upload of a file to import (Sitecore data importer supports docx files, csv’s and a zip file containing docx files) . The module also takes the path where you want the items created and the template of the items you want to create.

The main work of the importer parsing the docx file into fields is handled by the code below. Im using OpenXml to help read the docx format, and then iterating through each paragraph checking to see if it’s a title tag, storing the title in a variable and then grabbing the text paragraph(s). Each field name / value is stored in a dictionary which gets written out to the Sitecore API later on.  You can also upload a zip file containing multiple docx files which then gets uncompressed before passing each document off to this function.

Sitecore  Data Importer

Sitecore Data Importer

public Dictionary<string, string> ExtractFields(string path)

{

var fields = new Dictionary<string, string>();

using (var myDocument = WordprocessingDocument.Open(path, true))

{

var body = myDocument.MainDocumentPart.Document.Body;

var dictionaryKey = "";

foreach (var paragraph in body.Where(paragraph => !string.IsNullOrEmpty(paragraph.InnerText)))

{

if (paragraph.InnerXml.Contains("w:val=\"Title\""))

{

dictionaryKey = paragraph.InnerText;

}

else

{

if (fields.ContainsKey(dictionaryKey))

{

fields[dictionaryKey] = fields[dictionaryKey].EndsWith("</p>") ? fields[dictionaryKey] + "<p>" + paragraph.InnerText + "</p>" : "<p>" + fields[dictionaryKey] + "</p><p>" + paragraph.InnerText + "</p>";

}

else

{

fields.Add(dictionaryKey, paragraph.InnerText);

}

}

}

}

return fields;

}

Source Code and Sitecore Marketplace

Any issues or bugs with the module please let me know. The module does need testing with more docx structures, this is the initial release.

https://github.com/sobek1985/SitecoreDataImporter

http://marketplace.sitecore.net/en/Modules/Sitecore_Data_Importer.aspx

Sitecore YouTube Control

A very simple and useful YouTube control for Sitecore for embedding YouTube videos. You can either specify a Sitcore item to get the YouTube ID field from, otherwise it will use the context item.

  1. Create a class using the code below
  2. Register the control in the web.config
    <controls>
     <add tagPrefix="TB" namespace="ToolBox.SitecoreCMS.Web.UI.WebControls" assembly="ToolBox.SitecoreCMS" />
     </controls>
    
    
  3. Use the control within your sublayouts
    <tb:YouTube runat="server" Field="YouTubeID" Height="200" Width="400"/>
    

register the control within the web.config and use it within your sublayouts.

using System;
using System.Web.UI;
using System.Web.UI.WebControls;
using Sitecore.Data.Items;

namespace ToolBox.SitecoreCMS.Web.UI.WebControls
{
 public class YouTube : WebControl
 {
 public Item Item { get; set; }
 public string Field { get; set; }
 public override Unit Height { get; set; }
 public override Unit Width { get; set; }

protected override void Render(HtmlTextWriter writer)
 {
 writer.Write(BuildYouTube());
 }

private string BuildYouTube()
 {
return "<i frame width='" + Convert.ToInt32(Width.Value) + "px' height='" + Convert.ToInt32(Height.Value) + "px' src='http://www.youtube.com/embed/" + GetYouTubeVID() + "' frameborder='0' allowfullscreen></i frame>";
}

private string GetYouTubeVID()
 {
 return Item != null ? Item[Field] : Sitecore.Context.Item[Field];
 }
 }
}

How to use Sitecore Nuget

If you have ever used NuGet within any of your Visual Studio projects you will know how easy it is install 3rd party dependencies, update them and bring new developers onto a project, Wouldn’t it be useful to take advantage of NuGet in Sitecore.

With the power of Nuget and Powershell you can add files to your solution, add files to the inetpub folder containing your website and best of all insert items directly into the master database of your Sitecore instance.

To create a custom NuGet Package i use NuGet Package explorer. Its a friendly GUI for creating, updating and publishing NuGet packages (.nupkg) or a public or private NuGet repository.

How To Create A Sitecore Nuget Package

  1. Download NuGet package explorer. http://nuget.codeplex.com/releases/view/59864
  2. Open the sample Sitecore Nuget package. Sitecore.NuGet.Sample
    Open NuGet Package

    Open NuGet Package

    Sitecore NuGet Package

    Sitecore NuGet Package

  3. Edit the metadata for the package using the edit button on the left.
  4. The content folder if for any items (css, c# files, java script etc.) you want to add to your solution. The files will be added to reflect the folder structure here.

    Content Node

    Content Node for adding to the VS solution

  5. The tools folder is where the Powershell and DLL for Sitecore NuGet are contained. You can extend the powershell for pre-install and post-install events.

    Tools Node

    Tools Node

  6. Next we want to serialise Sitecore items to include them in the package. Within the Sitecore content editor navigate to the items you want to serialise and press the Serialize Tree button to serialise the content item and all decendants, do this for all items you want to include in your package.

    Serialise Sitecore Items

    Serialise Sitecore Items

  7. The items are then serialised to the disk. Navigate to your sealisation folder. (C:\inetpub\wwwroot\(ProjectName)\Data\serialization) Copy the serialised items you need into the serialsation folder in NuGet.

    Serialisation

    Serialisation

  8. Save or publish your package to your NuGet repository

Using Your NuGet Package

  1. Install Sitecore Rocks
  2. Create a connection to your Sitecore instance (Make sure the connection is outside the folder Sitecore NuGet can’t see the connection in here)

    Sitecore Rocks

    Sitecore Rocks

  3. Add a connection between your project and the Sitecore Rocks connection

    Connect to Sitecore

    Connect to Sitecore

  4. Now you can install your NuGet package directly into your solution and Sitecore instance
    NuGet Package Installer

    Nuget Package Installer

  5. Powershell and Sitecore rocks will now copy any files into your project and push your serialised items into the master Sitecore database

Sitecore 7 Add Single Item To Index

Recently I came up with a scenario where users were authoring content on the front end of a Sitecore site which then updated a list on the screen. The list was taking advantage of Sitecore 7′s new search API, so i needed to rebuild the index to display the newly inserted item.

Rebuilding the whole index for a single new item would be excessive, slow, CPU intensive and can cause issues for other users loading the page. Using JustDecompile to look through the ContentSearch Namespaces i found these useful functions to add, update or delete  a single item in the index. This performs really fast and solves all my issues about rebuilding the whole index.

Here are my methods wrapping the functionality.

public static void AddItemToIndex(Item item, string indexName)

{
var tempItem = (SitecoreIndexableItem)item;

ContentSearchManager.GetIndex(indexName).Refresh(tempItem);

}

public static void UpdateItemInIndex(Item item, string indexName)
{
var tempItem = (SitecoreIndexableItem)item;

ContentSearchManager.GetIndex(indexName).Update(tempItem.UniqueId);
}

public static void DeleteItemInIndex(Item item, string indexName)
{
var tempItem = (SitecoreIndexableItem)item;

ContentSearchManager.GetIndex(indexName).Delete(tempItem.UniqueId);

}

Registering A New Command

Registering a new Command within the Sitecore Content Editor
1. Create a class that implements the Command Class.
Command Class

Command Class

2. Add the new command to the Commands.Config, You need to specify a command name, the namespace and assembly of the command. (this must match the command for the button in the core database)
mike robbins commands config

Extending Commands Config

3. Add a new button to the Ribbon in the core database. /Sitecore/Content/Applications/Content Editor/Ribbons/(SectionName).
Add new button

Add new button

4. Set the click event of the new button to the command name you specified in the Commands.Config E.g. contenteditor:savePublish
5. Refresh the desktop and switch back to the master database.

Sitecore Save and Publish Button

I’ve noticed a common question with teaching new content editors how to create and publish content in Sitecore. “I’ve created my content and saved it, how do i get the content live on the site”

As we know saving content only writes the item to the Master database so the content appears in a draft status. The content editor then needs to publish the content to the web database for it to appear on the web site.

Some Sitecore instances don’t take advantage of workflow because the client doesn’t want or need it. In these cases the current method of saving the content and then navigating to the Publishing tab in the ribbon and clicking the publish button seems a little long winded.

Current Sitecore Content Editor Ribbon

Current Ribbon

This made me think of my umbraco days, umbraco has a save button to place content into preview mode. It also has a save and publish button, I wondered if I could replicate this idea within Sitecore.

Within Sitecore it’s easy to extend the ribbon in the content editor. The ribbon is controlled by items created within the content editor section of the core database.

I wanted to replicate exactly what the save and publish buttons did. The button commands are controlled by the Commands.config in the app_config folder. This shows me which classes in the Sitecore Kernel class were used for the commands using dependency injection.

commands.config

commands.config

Using the Commands.Config its easy to find out which classes are responsible for functions within the content editor. Using this i was able to find the classes responsible for the save action and for the publish action. Using JustDecompile (an excellent DLL decompiler) with the Sitecore kernel and the namespace information taken from the commands.config I was able to extract the code for the save command and the publish command.
It was an easy task for then create a new class implementing the Command class and replicating both the save and the publish command code together in the same class and register the command to a button in the content editor and extending the Commands.Config to point at my new class..
mike robbins commands config

Extending Commands Config

View the Package on Sitecore Marketplace View

Source Code GitHub

Follow

Get every new post delivered to your Inbox.

Join 121 other followers

%d bloggers like this: