This content is archived. See latest version here

Last updated: May 17 2016

Discounts [BETA]

Creating a custom promotion (discount)

To create a new promotion type, you need to create three things. First you need a PromotionData, which is the definition of a promotion, that is, the metadata needed to run the promotion.

Secondly, you need a processor. The processor is responsible for evaluating if a promotion can be applied on an order group.

Finally, you need a result returned from the processor. The result is responsible for indicating if a reward should be applied, and the logic for applying the reward. The reward is the benefits that should be applied to the user's order.


PromotionData should contain all properties needed to evaluate an order group and apply a reward. For example, a PromotionData contains entries to which the promotion applies and the discount. Any property that should be edited by a marketer when setting up a promotion needs to be added to this type.  Some basic metadata properties, like name and valid dates, are provided from the base class.

PromotionData comes in three flavors, see below. When creating a promotion, you should inherit from one of them, never from PromotionData directly.


This promotion applies its reward to a specific entry.


This promotion applies its reward to the full order.


This promotion applies its reward to the shipping cost of the order.

Connecting description to properties using colors [New in X.X]

It's possible to connect a property to a specific part of the promotion description, using different colors. This makes it easier to understand what each property means in the UI. By adding the attribute "PromotionRegion" to a property on the promotion content type, it will be marked for being included in the connection to the description. The attribute can also be used on a block property, to make all properties in the block being connected to the same part of the promotion description.

The attribute takes one parameter to its constructor, a string. This string will be used when deciding coloring of the property. There is some pre-defined constants in the type EPiServer.Commerce.Marketing.PromotionRegionName that are used by the internal promotion types. Those should also be used when creating custom promotion types.

Like all content types, it's possible to translate the name and description for the types by adding an element in the xml-file with the same name as the content type. A new sub-element called "formdescription" can be used for the connection between properties and the description. By adding "{regionname}some text{/}" in the text, the part "some text" will get the color matching that region. Both {regionname} and {/} will be removed before the description is displayed in the UI.


Here we have a custom promotion type with two properties, one block property, and one number. The "ConditionBlock" will be colored in the UI with a css-class indicating that it is a condition, and the "Percentage" will get a css-class indicating that it is a reward.

[ContentType(GUID = "76EBFEFF-2CFB-42F2-B4A3-EA5EA5A41515")]
public class CustomPromotion : EntryPromotion
    public virtual CustomPromotionBlock ConditionBlock { getset; }
    public virtual int Percentage { getset; }
[ContentType(GUID = "15B7BEA8-967A-4C5C-87F3-7346E71CBCC9")]
public class CustomPromotionBlock : BlockData
    public virtual int RequiredQuantity { getset; }
    public virtual IList<ContentReference> Targets { getset; }

The description is specified in the "formdescription" element in the translation xml.

  <name>My custom promotion</name>
  <create see="/contenttypes/custompromotion/name" />
  <description>Buy at least X items from categories/entries and get a % discount on the cheapest item.</description>
  <formdescription>Buy {condition} at least X items from categories/entries{/} and get {reward}a % discount{/} on the cheapest item.</formdescription>

IPromotionProcessor and PromotionProcessorBase

After creating promotion data, you need to make a processor. The processor evaluates if a promotion should apply a reward to an order group. You can implement the IPromotionProcessor interface directly, but the recommended way is to inherit from the abstract class PromotionProcessorBase<TPromotionData>. TPromotionData in this case should be the promotion data you created in the step above.

PromotionProcessorBase has one abstract method that needs to be implemented, Evaluate. The method is supplied with an IOrderGroup, which would be the cart, and a PromotionData, and is responsible to evaluate if a reward should apply. The Evaluate method should return an IPromotionResult with information about if and how to apply the promotion.


A promotion result should contain three things.

  • An ApplyReward method that applies the reward to an IOrderGroup and returns a list of PromotionInformation, which describes any applied rewards.
  • A Description that describes the promotion.
  • A Status flag, indicating if the promotion is not, almost, somewhat, or fully fulfilled.


The ApplyReward method should return a collection of PromotionInformation objects for each applied reward. A PromotionInformation has five properties:

  • PromotionInformationId - primary key of object; read-only.
  • Description - readable description of what reward was applied.
  • SavedAmount - the monetary amount, if any, that was saved by applying this reward.
  • LineItem - which line item, if any, that was affected.
  • IsActive  - whether the promotion was applied to the order.

Discount engine priority handling [New in 9.5]

The Discount Priorities view allows a merchandiser to manage priority and exclusivity for discounts. This view lets the promotion engine evaluate discounts in priority order and ignore excluded promotions. Promotions with a higher priority are evaluated first.

The following PromotionData properties are used for this view:

  • Priority - order of priority; the smaller the Priority value is, the higher the priority.
  • ExcludedPromotions - list of excluded promotions; these are ignored when the promotion is evaluated.

Adding money collections to your promotion

Your promotion may need a collection of currencies and amounts as part of the condition evaluation or reward logic. To achieve this, add an IList<Money> property to the custom promotion class. When used on a promotion type, such a Money collection is tightly coupled with the currencies available on the parent campaign.

Initially, any existing currencies related the promotion's campaign market added to the collection have an amount of zero. Changing the campaign market also changes available currencies in the property. Consider this when developing discount processors, because you must decide the desired behavior when one, or even all, amounts are set to zero.

The same goes for when working with the MonetaryReward type, as it uses an IList<Money> to store some of its values.

Adding help text for custom groups [New in 9.2]

To include help texts for custom groups on a campaign or promotion form, you need to add the Display attribute with the GroupName property set to the name of a specific node within the "groups" section in the resource files. The groups sections are content-type specific, so should be placed under contenttypes node for your specific type.


[Display(GroupName = "MyNewGroup")]
public virtual decimal Money { get; set; }

The resource file will be like this
        <help>This is help text for my new group</help>

See also Property attributes for more information.


Do you have feedback on this documentation? Send an email to For development-related questions and discussions, refer to our Forums on