Blog posts by Bewildered in Episerver world2018-05-30T17:23:53.0000000Z/blogs/bewildered-in-episerver-world/Optimizely WorldHow to use visitor groups to control access to non-content/blogs/bewildered-in-episerver-world/dates/2018/5/how-to-use-visitor-groups-for-controlling-access-to-non-content/2018-05-30T17:23:53.0000000Z<!DOCTYPE html>
<html>
<head>
</head>
<body>
<p>This post is intended for developers and is mostly code examples.</p>
<p>How to use visitor groups to control access to content is well documented here at episerver world: <a href="/link/efa49f3e699b419dabbee5ad4ca908d7.aspx">https://world.episerver.com/documentation/developer-guides/CMS/personalization/</a></p>
<p>It also goes in depth on how easy you can create your own custom visitor groups, but I found it lacking when it came to describe a way to use visitor groups for non-content.</p>
<h3></h3>
<h3>Background</h3>
<p>A customer with a commerce site came to me and requested a way to limit access to certain shipping methods so that only companies could use them, he also wanted a way to define who should be counted as a company himself. Had shipping methods been content we could have used visitor groups just out of the box but as it is not, but rather a very old part of commerce that doesn't even know visitor groups exist, it proved to be a challenge to figure out how to get it to work.</p>
<h3>Solution</h3>
<p>To begin with we need a way to define which visitor groups define companies, this was added to a settings page in the cms as a custom property:</p>
<pre class="language-csharp"><code>[Display(Name = "Visitor groups for companies")]
[UIHint("visitorgroupselector")]
public virtual IList<Guid> CompanyVisitorGroups { get; set; }</code></pre>
<p>Turns out visitor groups are stored with their Guid:s in an IList and the magic is added with a UIHint attribute as so often is the case. Unfortunately it is not present among the EPiServer.Web.UIHint constants, you must know that the selector is named "visitorgroupselector" and enter it as a string manually.</p>
<p>That took care of the problem with letting the customer configure who is a company now we just need a way to check if the current visitor is a member in any of those groups, for that i wrote a little service:</p>
<pre class="language-csharp"><code>public class VisitorGroupService
{
private readonly IVisitorGroupRepository _visitorGroupRepository;
private readonly IVisitorGroupRoleRepository _visitorGroupRoleRepository;
public VisitorGroupService(IVisitorGroupRepository visitorGroupRepository, IVisitorGroupRoleRepository visitorGroupRoleRepository)
{
_visitorGroupRepository = visitorGroupRepository;
_visitorGroupRoleRepository = visitorGroupRoleRepository;
}
public bool IsCurrentUserInAnyVisitorGroup(IList<Guid> visitorGroupIds)
{
if (HttpContext.Current == null)
{
return false;
}
var context = new HttpContextWrapper(HttpContext.Current);
return IsPrincipalInAnyVistorGroup(context.User, visitorGroupIds, context);
}
public bool IsPrincipalInAnyVistorGroup(IPrincipal principal, IList<Guid> visitorGroupIds, HttpContextBase context)
{
if (context == null || visitorGroupIds == null)
{
return false;
}
foreach (var groupId in visitorGroupIds)
{
var group = _visitorGroupRepository.Load(groupId);
if (_visitorGroupRoleRepository.TryGetRole(group.Name, out var groupRole) && groupRole.IsMatch(principal, context))
{
return true;
}
}
return false;
}
}</code></pre>
<p>Fairly easy to follow the code but not much is documented around these classes. Some points of interest here is that we must load the VisitorGroup just because the IVisitorGroupRoleRepository only takes the Name and not the Id, the TryGetRole is also the single function defined on this interface.</p>
<p>All that is left for us is to call the service and pass in the page property:</p>
<pre class="language-csharp"><code>var isCompany = _visitorGroupService.IsCurrentUserInAnyVisitorGroup(page.CompanyVisitorGroups);</code></pre>
<p>Now we are free to filter whatever we want based on visitor groups. I hope this can provide you with a clear guide to improve personalization on all your sites. :)</p>
<p>Footnote</p>
<p>There is a EPiServer.Personalization.VisitorGroups.VisitorGroupHelper you can use to simplify the code a little bit, it wraps the IVisitorGroupRoleRepository and does the call to VisitorGroupRole.IsMatch, I used the repository directly more for transparency than anything else.</p>
</body>
</html>How to enable CMS search for catalogs/blogs/bewildered-in-episerver-world/dates/2017/9/how-to-enable-cms-search-for-catalogs/2017-09-29T13:17:24.0000000Z<!DOCTYPE html>
<html>
<head>
</head>
<body>
<p>This will be a more concrete example on how a developer can change the search function in the catalogs gadget, but I will also show how this adds real value for editors so if you aren't a developer read through and focus on the why and what instead of the where and how.</p>
<h3>Background</h3>
<p>I have an old site that we have migrated to a newer EPiServer version as the new asset system was introduced we needed to install the EPiServer.Search NuGet package so that the media search worked. As I was experimenting with EPiServer.Search I noticed that the Catalog UI was indeed triggering the right CMS IContent events and indexing catalog content into the same search index, a fact that even EPiServer developer support was unaware of and required proof of when I asked them, so don't feel bad if you never heard of it either <img src="/Scripts/tinymce/plugins/emoticons/img/smiley-surprised.gif" alt="surprised" />.</p>
<p>However, the search in the Catalogs gadget was already working before we installed the NuGet since that uses an entirely different search index. Now when we have installed EPiServer.Search it makes two search indexes that is being populated with catalog content but only one that is ever being queried for it. This is my story about how I changed it so that both the Catalogs and the Media gadget queried the same CMS search index.</p>
<h3>Enabling the custom search</h3>
<p>This is really straightforward but it took me a long time getting there:</p>
<pre class="language-csharp"><code> [SearchProvider]
public class CustomCatalogSearchProvider : EPiServerSearchProviderBase<EntryContentBase,ContentType>
{
private readonly LocalizationService _localizationService;
public override string Area => "Commerce/Catalog";
public override string Category => _localizationService.GetString("/Commerce/Edit/Provider/SearchProductCatalog/Category");
protected override string IconCssClass => "epi-resourceIcon epi-resourceIcon-page";
public CustomCatalogSearchProvider(LocalizationService localizationService, SiteDefinitionResolver siteDefinitionResolver, IContentTypeRepository<ContentType> contentTypeRepository, EditUrlResolver editUrlResolver, IContentRepository contentRepository, ILanguageBranchRepository languageBranchRepository, SearchHandler searchHandler, ContentSearchHandler contentSearchHandler, SearchIndexConfig searchIndexConfig, UIDescriptorRegistry uiDescriptorRegistry) : base(localizationService, siteDefinitionResolver, contentTypeRepository, editUrlResolver, contentRepository, languageBranchRepository, searchHandler, contentSearchHandler, searchIndexConfig, uiDescriptorRegistry)
{
_localizationService = localizationService;
}
public CustomCatalogSearchProvider(LocalizationService localizationService, SiteDefinitionResolver siteDefinitionResolver, IContentTypeRepository<ContentType> contentTypeRepository, EditUrlResolver editUrlResolver, ServiceAccessor<SiteDefinition> currentSiteDefinition, IContentRepository contentRepository, ILanguageBranchRepository languageBranchRepository, SearchHandler searchHandler, ContentSearchHandler contentSearchHandler, SearchIndexConfig searchIndexConfig, UIDescriptorRegistry uiDescriptorRegistry, LanguageResolver languageResolver, UrlResolver urlResolver, TemplateResolver templateResolver) : base(localizationService, siteDefinitionResolver, contentTypeRepository, editUrlResolver, currentSiteDefinition, contentRepository, languageBranchRepository, searchHandler, contentSearchHandler, searchIndexConfig, uiDescriptorRegistry, languageResolver, urlResolver, templateResolver)
{
_localizationService = localizationService;
}
public CustomCatalogSearchProvider(LocalizationService localizationService, ISiteDefinitionResolver siteDefinitionResolver, IContentTypeRepository<ContentType> contentTypeRepository, EditUrlResolver editUrlResolver, ServiceAccessor<SiteDefinition> currentSiteDefinition, IContentRepository contentRepository, ILanguageBranchRepository languageBranchRepository, SearchHandler searchHandler, ContentSearchHandler contentSearchHandler, SearchIndexConfig searchIndexConfig, UIDescriptorRegistry uiDescriptorRegistry, LanguageResolver languageResolver, UrlResolver urlResolver, TemplateResolver templateResolver) : base(localizationService, siteDefinitionResolver, contentTypeRepository, editUrlResolver, currentSiteDefinition, contentRepository, languageBranchRepository, searchHandler, contentSearchHandler, searchIndexConfig, uiDescriptorRegistry, languageResolver, urlResolver, templateResolver)
{
_localizationService = localizationService;
}
}</code></pre>
<p>All we need to do is register our own class with the [SearchProvider] attribute, which will enable EPiServer to set everything up during the regular initialization.</p>
<p>It is the Area:"Commerce/Catalog" property that informs the Catalog UI that this SearchProvider should be called when the "Catalogs" gadget is used.</p>
<p>Everything needed to do the actual query is already implemented in EPiServerSearchProviderBase we just had to configure it to do it for EntryContentBase.</p>
<p>EPiServer uses the base class in their own search providers for pages, blocks and media files that are all included in the CMS.</p>
<h3>Disabling the legacy search</h3>
<p>I personally consider this to be legacy as EPiServer inherited it when they bought the commerce platform, they haven’t written it themselves which is also why support can be a trial, but it is however not obsolete as they have yet to provide an alternative.</p>
<p>Unfortunately, I have found no easy way to do this. I will have to look into implementing a dummy version of Mediachase.Search.SearchProvider and configure EPiServer to use it by entering it in the Mediachase.Search.config file. If you do this don't forget to turn off the two indexing jobs under CMS->Admin->Scheduled Jobs.</p>
<h3>Adding node search</h3>
<p>The legacy search only indexed entries so that was all that could be queried, however during my experiments I noticed that the CMS index was indeed being populated not only with entries but also with nodes, so naturally i set out on a quest to modify the Catalogs gadget to return nodes as well as entries when the editors did a search.</p>
<p>To do this all I did was to change the setting for EPiServerSearchProviderBase to the right base class:</p>
<pre class="language-csharp"><code>public class CustomCatalogSearchProvider : EPiServerSearchProviderBase<CatalogContentBase, ContentType></code></pre>
<p>Searching in the Catalogs gadget did indeed return not only the entries as before but also a node. However, double-clicking on it does not navigate to the node in the Catalog UI. I am sorry but it will take someone better on JavaScript than me to make that happen, since I haven't mustered the courage to enter the dojo yet.</p>
<p>All is not for nothing though since even though the navigation doesn't work the drag-and-drop does, which enables editors to easily find nodes when they are populating content areas on pages inside cms and also when putting together promotions in marketing.</p>
<h3>Conclusion</h3>
<p>With very little code, it took me personally some significant effort to work all of this out but hopefully it was easier for you <img src="/Scripts/tinymce/plugins/emoticons/img/smiley-wink.gif" alt="wink" />, we added some real value for editors as they can now search for nodes in the catalogs gadget and drag-and-drop them into content areas both in the CMS site but also for promotions in marketing. We also made life a bit simpler for us developers later on as we removed the dependency on an old search index.</p>
<p>Known limitations:</p>
<ol>
<li>Double-clicking a node for navigating to it doesn't work.</li>
<li>If you like me have a preexisting site and adds EPiServer. Search you have to do your own indexing to populated it initially.</li>
<li>This have not been thoroughly tested and there might very well be pitfalls down the road.</li>
</ol>
<p>Footnote: this was done in CMS 10.10.1 and Commerce 11.2.0.</p>
</body>
</html>Marketing: The sorrows of exclusion/blogs/bewildered-in-episerver-world/dates/2017/6/marketing-the-sorrow-of-exclusion/2017-06-01T16:31:36.0000000Z<!DOCTYPE html>
<html>
<head>
</head>
<body>
<p>Today I would like to share with You how exclusion in the new Episerver promotion engine works and what marketers needs to be aware of.</p>
<p>Let's start by setting up the premise.</p>
<p>We are selling clothes in an online store and a customer have added two different pants to their cart.</p>
<h3>No discounts:</h3>
<table border="1" cellspacing="4" cellpadding="2">
<tbody>
<tr>
<td>Article</td>
<td>Category</td>
<td>Brand</td>
<td>Price</td>
<td>Discounted Price</td>
</tr>
<tr>
<td>Purple party pants</td>
<td>Pants</td>
<td>Chic clothes cooperation</td>
<td>500</td>
<td>500</td>
</tr>
<tr>
<td>Soft sienna slacks</td>
<td>Pants</td>
<td>Amazing apparel association</td>
<td>1000</td>
<td>1000</td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td>Sum: 1500</td>
</tr>
</tbody>
</table>
<p> </p>
<p>Now our marketing departments adds a discount for 30% off on everything in the pants category, which of course affects both items in the cart.</p>
<h3>30% off pants:</h3>
<table border="1" cellspacing="4" cellpadding="2">
<tbody>
<tr>
<td>Article</td>
<td>Category</td>
<td>Brand</td>
<td>Price</td>
<td>Discounted Price</td>
</tr>
<tr>
<td>Purple party pants</td>
<td>Pants</td>
<td>Chic clothes cooperation</td>
<td>500</td>
<td>350</td>
</tr>
<tr>
<td>Soft sienna slacks</td>
<td>Pants</td>
<td>Amazing apparel association</td>
<td>1000</td>
<td>700</td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td>Sum: 1050</td>
</tr>
</tbody>
</table>
<p> </p>
<p>So far so good but then marketing wants to clear the warehouse of the "Chic clothes cooperation" and adds a discount of 50% to that brand.</p>
<h3>30% off pants and 50% off brand:</h3>
<table border="1" cellspacing="4" cellpadding="2">
<tbody>
<tr>
<td>Article</td>
<td>Category</td>
<td>Brand</td>
<td>Price</td>
<td>Discounted Price</td>
</tr>
<tr>
<td>Purple party pants</td>
<td>Pants</td>
<td>Chic clothes cooperation</td>
<td>500</td>
<td>175</td>
</tr>
<tr>
<td>Soft sienna slacks</td>
<td>Pants</td>
<td>Amazing apparel association</td>
<td>1000</td>
<td>700</td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td>Sum: 875</td>
</tr>
</tbody>
</table>
<p>Now this is not what we wanted, the Purple party pants shouldn't get both discounts we just want it to have 50% since that is the highest discount.</p>
<p>(It gets a 65% discount since the result is: price*(1-0.3)*(1-0.5) = price*0.35)</p>
<p> </p>
<p>Ok we see that discounts stacks and to counter that we add an exclusion on the two discounts in Episerver Marketing, we also make sure to set the priority of the "Chic clothes cooperation" discount higher than the other one so that the customer gets the best of the two discounts.</p>
<h3>30% off pants and 50% off brand with exclusion:</h3>
<table border="1" cellspacing="4" cellpadding="2">
<tbody>
<tr>
<td>Article</td>
<td>Category</td>
<td>Brand</td>
<td>Price</td>
<td>Discounted Price</td>
</tr>
<tr>
<td>Purple party pants</td>
<td>Pants</td>
<td>Chic clothes cooperation</td>
<td>500</td>
<td>250</td>
</tr>
<tr>
<td>Soft sienna slacks</td>
<td>Pants</td>
<td>Amazing apparel association</td>
<td>1000</td>
<td>1000</td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td>Sum: 1250</td>
</tr>
</tbody>
</table>
<p>Great now we get the 50% discount on the Purple party pants, but wait! Compared to when we only had the discount for all pants the price on the cart has actually gone up with 200? The Soft sienna slacks now cost full price and doesn't get the 30% discount anymore, why is that?</p>
<p>The answer is that even thou our two discounts are both item level discounts the exclusion always operates on the order level.</p>
<p> </p>
<h2>Conclusion:</h2>
<p>Exclusion only operates on the whole order/cart, it can't be used to avoid stacking discounts on a single item.</p>
<p>As a marketer, You have the following options:</p>
<ol>
<li>Accept the stacking and pay the price, the easy way :)</li>
<li>Avoid creating overlapping promotions, easier said than done</li>
<li>Create special promotions for the non-overlap, in our example this would mean a discount for pants of all other brands that isn't excluded, very hard to maintain</li>
<li>Use the exclusion and try to handle the frustrated customers that are affected, bad for user experience</li>
</ol>
<p> </p>
<p>At times like these I am glad I am not a marketer. ;)</p>
<p> </p>
<p>Disclaimer: all article and brand names are pure fictional and any similarity with existing articles and brands are fully accidental and unintentional.</p>
</body>
</html>First look at the new Episerver promotions/blogs/bewildered-in-episerver-world/dates/2016/7/first-look-at-the-new-episerver-promotions/2016-07-13T15:44:52.0000000Z<p>The long awaited new promotion engine from Episerver has finally arrived, fashionably late but looking smart.</p> <p>For all of us that have worked with the old one inherited from Mediachase I expect standing ovations as we no longer need to work with expressions and the Expression Editor will become a mere memory. </p> <p>But I am getting ahead of myself, lets get started with the admin interface.</p> <p> </p> <p>The new interfaces are named Marketing and can be found under Commerce:</p> <p><a href="/link/d6baef98c59a4728891569992ccbaa87.aspx"><img title="image" style="border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-top-width: 0px" border="0" alt="image" src="/link/6fd84f955198491d8a7ec1cbb54dabb8.aspx" width="410" height="70" /></a></p> <p>The structure is the same as in the old setup: campaigns are supposed to be a grouping of promotions, aka discounts, with a common target. </p> <p> </p> <h2>The campaign</h2> <p>First off we need to create a new Campaign, also known as “Sales campaign”.</p> <p><a href="/link/ff7b27eecbb34fcf9aa06666c17e2cd3.aspx"><img title="image" style="border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; padding-top: 0px; padding-left: 0px; margin: 0px; display: inline; padding-right: 0px; border-top-width: 0px" border="0" alt="image" src="/link/accbd83f4c8047d8a1e83bc0f7b42e63.aspx" width="170" height="107" /></a></p> <p>Give it a name and you should have an empty campaign:</p> <p><a href="/link/43f1364534664e6a9a6aa213d5c57ea1.aspx"><img title="image" style="border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-top-width: 0px" border="0" alt="image" src="/link/bc1bb506dc2c4fb1a823fd0a1e39f1a0.aspx" width="704" height="600" /></a></p> <p> </p> <p>Check the active box and enter a start and end date, I feel that the end date could be optional but for now it is mandatory.</p> <p>Next we have the support for Markets, yay!</p> <p><a href="/link/7d96312f454a4c5780297aef67b3257b.aspx"><img title="image" style="border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-top-width: 0px" border="0" alt="image" src="/link/d5b813e50096470c804cd7a460afb001.aspx" width="358" height="236" /></a></p> <p>Selecting a specific market works as expected. However if you select “All” here, we enable a feature for all promotions/discounts we add into the campaign that allows us to define different amounts for different currencies. Hopefully that will reduce the need to create separate promotions for each market.</p> <p>For the optional personalization we can choose to target specific Visitor Groups for all the promotions in the campaign. They are also extendable with custom implementations which will open up for many possible scenarios, the hard part will be deciding on relevant ones.</p> <p>If you select more than one Visitor Group here it implies a logical ‘OR’, for the fans of set theory it will be a union.</p> <p><a href="/link/e243157c2418414ea0a65ee66e5411e3.aspx"><img title="image" style="border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-top-width: 0px" border="0" alt="image" src="/link/1e2ace9da4e5442f9c932151fc30de6d.aspx" width="432" height="125" /></a></p> <p> </p> <h2>First promotion</h2> <p>Now that we have a working campaign we can start filling it with promotions. There are several to choose from, 9 right now, divided into the old groups of Entry, Order and Shipping. Starting off easy we create a free shipping discount with “Discount off Shipping Costs”.</p> <p><a href="/link/067c2168d2fb413fbfba8bbf96b28ea9.aspx"><img title="image" style="border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; padding-top: 0px; padding-left: 0px; margin: 0px; display: inline; padding-right: 0px; border-top-width: 0px" border="0" alt="image" src="/link/39a154f8d16b4160baa53a8d9b5408e8.aspx" width="244" height="131" /></a></p> <p><a href="/link/4386bf91d5ad40f88cd2db26478e409f.aspx"><img title="image" style="border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-top-width: 0px" border="0" alt="image" src="/link/15ed21e034644a5789418d868cb4ba37.aspx" width="705" height="766" /></a></p> <p>Most of the time you will want to keep the dates already set in the campaign but they offer you the opportunity to set them specifically for this promotion, you can select any dates in the date picker but it will only accept dates that are within the date interval of the campaign. Checking active box here too is a given. </p> <p>You can also set a global promotion code here, if set it is needed to trigger the promotion. </p> <p>Since I picked all markets for the campaign we now get the option to set a different amount limit for each currency, note that even currencies from inactive markets are present here. you don’t need to set them all but at least one is a must.</p> <p>The color coding here is a nice touch to really separate the different settings. Next we get to choose which shipping methods we want to give the discount on and how large the discount should be, if you pick “Amount off” here you also get the same list over currencies. Take care here thou - since we have all markets on the campaign we also get shipping methods from all markets, and they don’t necessarily have unique names over different markets.</p> <p><a href="/link/a649a4be3cdd47838d44feb3acb393f7.aspx"><img title="image" style="border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-top-width: 0px" border="0" alt="image" src="/link/10fdc595d82e4ea4b25f149b452ebb1a.aspx" width="706" height="480" /></a></p> <p>At the bottom we get to define the redemption limits as before, as this is a shipping promotion it is built-in an limit of one per order.</p> <p>As we save and close the promotion we get to my surprise a new view instead of coming back to the campaign.</p> <p><a href="/link/3de61f1b9dab4d1f9c04efcd49854bcb.aspx"><img title="image" style="border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-top-width: 0px" border="0" alt="image" src="/link/eb3e825d7fe8429096d66b819dce2cdd.aspx" width="707" height="139" /></a></p> <p>This is the global list over promotion priorities over all campaigns, we will return to this in a bit but for now just close it and we will return to the campaign.</p> <p> </p> <h2>Second promotion</h2> <p>We will quickly create a second promotion for an order discount by using the “Discount off Total Order Value”.</p> <p><a href="/link/38a2341d0fe64c42b0e1a56f9f5de435.aspx"><img title="image" style="border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; padding-top: 0px; padding-left: 0px; margin: 0px; display: inline; padding-right: 0px; border-top-width: 0px" border="0" alt="image" src="/link/233c212d3b384d77b3d04bd19782e3ee.aspx" width="244" height="124" /></a></p> <p><a href="/link/79ab75448bc44827863bd81da2a5ac08.aspx"><img title="image" style="border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-top-width: 0px" border="0" alt="image" src="/link/338b6fcc39b2469eaf9919b8b4129d48.aspx" width="707" height="789" /></a></p> <p>I simply gave 5% off all orders for the sake of reasoning. As we save and close this promotion we come back to the priority list over all promotions.</p> <p><a href="/link/55160a605ae04d26b743a1625c4931e1.aspx"><img title="image" style="border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-top-width: 0px" border="0" alt="image" src="/link/9b50613a6a614b1dab73ffadb9063466.aspx" width="709" height="169" /></a></p> <p> </p> <h2>Priority</h2> <p>Here is a very important pitfall to notice, as the order promotion was added last it is being added at the bottom with the lowest priority. This differ from the promotion priority we are used to from the old system, in which entry promotions were always processed first and then order and last shipping. In the new promotion engine you are free to set priority however you want it. The recommendation is to still maintain a Entry>Order>Shipping priority, but now it is up to you when you create promotions to do so. </p> <p>If we don’t change it in my example we will give free shipping to orders that doesn’t reach the limit after the 5% discount have been applied, which isn’t the expected behavior so we need to change the order before closing.</p> <p><a href="/link/2c418767653342648371414ae04a6903.aspx"><img title="image" style="border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-top-width: 0px" border="0" alt="image" src="/link/5b471f94c749420aa32f42cdeb3af1f5.aspx" width="707" height="171" /></a></p> <p>To get to the priority list directly you press on the button at the top right of the campaign list page.</p> <p><a href="/link/432936f28c894441937c2ef09f65865e.aspx"><img title="image" style="border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-top-width: 0px" border="0" alt="image" src="/link/738c81e697054f57a6f7fc9d959e77e3.aspx" width="707" height="139" /></a></p> <p> </p> <p>That should cover the basics. I hope it will be of some help to you as you upgrade Episerver and start experimenting with all the different promotions included. For a first post this sure has been a long one. </p>