E-commerce Custom Macro in Online Marketing Process – Abandoned shopping cart


This article shows an example of creating a Custom Macro Method for use in the On-line Marketing process condition step, to detect an abandoned shopping cart. While the Custom Macro can be used anywhere in Kentico CMS with any Kentico License Edition, the On-line Marketing module is only available in the EMS license edition.

The aim of this article is to show an implementation and use of a custom macro method in the Online Marketing Process. In this particular example, we will detect when a user has placed items in his shopping cart, but did not follow through with an order.

First we will create a Custom Macro Method which will return true or false based on the existence of shopping cart entries for a specified contact, that is older than a specific time interval.

I would suggest that you make yourself familiar with generic Custom Macro Implementation. Following the article, create a new class in the App_Code directory of your web project, for example CustomMacroMethods.cs. Add the following to the list of default libraries:

using System.Data;

using CMS.SettingsProvider;
using CMS.GlobalHelper;
using CMS.OnlineMarketing;
using CMS.Ecommerce;
using CMS.EcommerceProvider;

Afterwards, define the custom macro method:

/// <summary> /// Find shopping carts older than specific time for a contact. /// </summary> public static bool OldShoppingCarts(ContactInfo contact, DateTime when) { if (contact != null) { DataSet ds = null; string where = ""; ds = MembershipInfoProvider.GetRelationships("MemberType = " + (int)MemberTypeEnum.EcommerceCustomer + " AND ActiveContactID = " + contact.ContactID, "MembershipCreated"); if (!DataHelper.DataSourceIsEmpty(ds)) { where = SqlHelperClass.AddWhereCondition(where, "ShoppingCartCustomerID in (" + TextHelper.Join(",", SystemDataHelper.GetStringValues(ds.Tables[0], "RelatedID")) + ")"); } ds = MembershipInfoProvider.GetRelationships("MemberType = " + (int)MemberTypeEnum.CmsUser + " AND ActiveContactID = " + contact.ContactID, "MembershipCreated"); if (!DataHelper.DataSourceIsEmpty(ds)) { where = SqlHelperClass.AddWhereCondition(where, "ShoppingCartUserID in (" + TextHelper.Join(",", SystemDataHelper.GetStringValues(ds.Tables[0], "RelatedID")) + ")", "OR"); } if (where != string.Empty) { where = SqlHelperClass.AddWhereCondition(where, "ShoppingCartLastUpdate < \'" + when + "\'"); InfoDataSet<ShoppingCartInfo> shoppingCarts = ShoppingCartInfoProvider.GetShoppingCarts(where, "ShoppingCartLastUpdate DESC"); if (!DataHelper.DataSourceIsEmpty(shoppingCarts)) { return true; } } } return false; }

As you can see, this macro will expect Contact info object and DateTime as a parameter. Based on the contact membership info, it will retrieve E-Commerce shopping cart information, and limit the query results according to specified DateTime. If any results are found, the macro will return true.

While this macro is perfectly suitable for use in the Online Marketing Process, you may wish to add a few more overloads to make the macro more versatile:
/// <summary> /// Find any shopping carts for current Contact. /// </summary> public static bool OldShoppingCarts() { return OldShoppingCarts(OnlineMarketingContext.CurrentContact, DateTime.Now); } /// <summary> /// Find any shopping carts for specified contact. /// </summary> public static bool OldShoppingCarts(ContactInfo contact) { return OldShoppingCarts(contact, DateTime.Now); }

This way, you will be able to use the macro even if you do not wish to use all of its parameters.

Afterwards, you will need to create a wrapper object for your methods which will group them for registering as single Custom Macro Method:
/// <summary> /// Wrapper for OldShoppingCarts methods, suitable for registration as a macro method. /// </summary> /// <param name="parameters">Parameters of the method</param> public static object OldShoppingCarts(params object[] parameters) { switch (parameters.Length) { case 0: return OldShoppingCarts(); case 1: return OldShoppingCarts(parameters[0] as ContactInfo); case 2: return OldShoppingCarts(parameters[0] as ContactInfo, ValidationHelper.GetDateTime(parameters[1], DateTime.Now)); default : throw new NotSupportedException(); } } This wrapper will call different macro methods based on number of parameters specified. To finish the macro definition, create a registration method and add a code snippet for your method: public static void RegisterMethods() { // Registers OldShoppingCarts with two parameter overloads. MacroMethod oldShoppingCarts = new MacroMethod("OldShoppingCarts", OldShoppingCarts) { Comment = "Returns Shopping Cart Objects for the Contact older than specified DateTime.", Type = typeof(string), AllowedTypes = new List<Type>() { typeof(DateTime) }, MinimumParameters = 0 }; oldShoppingCarts.AddParameter("contact", typeof(ContactInfo), "ContactInfo object."); oldShoppingCarts.AddParameter("when", typeof(DateTime), "Specific DateTime."); MacroMethods.RegisterMethod(oldShoppingCarts); // Registers a code snippet for OldShoppingCarts. MacroMethod oldShoppingCartsSnippet = new MacroMethod("OldShoppingCartsSnippet", OldShoppingCarts) { Comment = "Calls OldShoppingCarts to retrieve all shopping carts older than 30 minutes.", Type = typeof(string), AllowedTypes = new List<Type>() { typeof(string) }, Snippet = "OldShoppingCarts(ECommerceContext.Contact, ToLower(DateTime.Now.AddMinutes(-30)));" }; MacroMethods.RegisterMethod(oldShoppingCartsSnippet); }

Finally, you need to load your Custom Macro Method upon application restart. This can be done by creating a module loader. First, add a new class in your App_Code directory and replace the default contents with these:
using System; using System.Collections.Generic; using System.Linq; using System.Web; using CMS.SettingsProvider; [MacroMethodLoader] public partial class CMSModuleLoader { /// <summary> /// Attribute class ensuring the registration of custom macro methods. /// </summary> private class MacroMethodLoader : CMSLoaderAttribute { /// <summary> /// Called automatically when the application starts. /// </summary> public override void Init() { // Calls the registration method. CustomMacroMethods.RegisterMethods(); } } }

That is it. If you restart your site in CMS Site Manager -> Administration -> System -> Restart application, the method will be available in the macro designer across the CMS.

I suggest testing the macro by placing it in the suitable web part and testing if it returns any results. If you have trouble triggering the macro, debug your project and test if CustomMacroMethods.RegisterMethods();
Gets triggered at all.

The second part of this article will showcase how to use it in Online Marketing process. This feature is available only in the EMS license.

For testing purposes, set the wait interval to 1 minute. Afterwards, enter this macro in the condition step:

OldShoppingCarts(Contact, Now.AddMinutes(-1))

Finally, set up basic email notification using Send e-mail step.

You can test this process by manually assigning a contact to run in the Contacts tab of this process. If the contact has active shopping cart, you will receive email notification. When you are ready to enable the process, add the following trigger in the Triggers tab:

Display name: Product added
Type: Activity performed
Activity type: Product added to shopping cart

Now you are all set. I suggest testing this process using a completely fresh user.
Example implementation of the code above is attached to this article.



See also:
Code Example
Custom Macro Methods
Online Marketing Automation Process
Email templates

Applies to: Kentico CMS 7.x


Share this article on   LinkedIn

Josef Dvorak

Hello, I am a Solution Architect with Kentico. My primary focus is the E-Commerce module, however it is not uncommon for me to help with other modules as well.