Unleash the power of Sitecore – Experiences from customers diving into advanced marketing features for the very first time (Part 2)

In the last blog post I have started to tell you about the journey customer take, when they start using advanced marketing features. I tried to point out, from which status quo they started, what knowledge they had and if the technical base was designed and implemented in a way, advanced marketing features could be used. In the end it was quiet clear, that most of the customers use Sitecore just as a CMS and not as an Experience Platform. And based on these information the journey now started, how to help customers to understand, what advanced marketing features are in Sitecore and how easy it can be to use them.

Prepare and hold a workshop

Of course to reach a bigger number of responsibles from the various teams at the customer side it totally makes sense to make a workshop with all involved employees like, analysts, editors, stakeholder, marketeers, devs and so on. The main question now for me was:

What do you demonstrate in a workshop, so that on the one hand side customers get interested to start using these features, and on the other side they understand what could possibly be reached, when using such feature.

The answer was as clear as obvious. I did not want to show some generic examples, which you get when you search for examples in the world wide web. Of course such examples are great to learn analytics and personalization feature. But once you start trying to convince customers to use these features, it makes totally sense to give them examples within their own instance and based on their own data, so that the customer can directly see, the benefit of using advanced analytics and personalization features of Sitecore instead of having the need to abstract the demo to apply that on their use cases.

So, how did the workshop now exactly looked like?

  1. Some facts from real world projects and official surveys
  2. Introduction to advanced marketing features with a how to set it up
    1. Goals
    2. Campaigns
    3. Profiles
    4. Personalization of modules
  3. General approach to introduce advanced marketing features (Based on approach shown in a marketing presentation)
  4. Tools within Sitecore 
    1. Experience Optimization (Mostly A/B and multivariate testing)
    2. Path Analyzer
    3. Marketing Automations
    4. Experience Profile
  5. DEMO

The goal of that approach was now to first show the customer, that personalization is in deed important and is not something the end users refuse, but really want.  Then they should see, how easy it is within Sitecore to start with advanced marketing features and that they get a step by step guide to later on read through to be able to set these things up on their own. After they now knew, where and how things can be setup within Sitecore, I thought it might sense to give them an approach how to start.

The biggest mistake at that point, would now be, that the customer just starts to e.g. create some random goals or profile cards without having first a look at their concept, like persona or their data or their own content.

Therefore I wanted to show a general approach of how to start using such advanced marketing features. While preparing myself for the workshop, I watched a marketing video “Rules-Based Personalization for Web Experience Management” by Michelle White. Within that presentation an approach was presented, which generally consisted of the following steps

  1. Identity the WHO and WHY
  2. Configure Profiles
  3. Configure Profile Cards and Persona
  4. Profile Content
  5. Configure predefined visitor patterns
  6. Create Personalization based patterns
  7. Adjust and optimize

If you follow such an approach and write down the outcome of all that e.g. in a structured csv file and then start creating all the goals, profiles and rules within sitecore, you will the very quick, if all these things you start doing have an effect; either way positive or negative. And you can then adjust, extend or remove whatever you want in later review cycles. Otherwise it would be quiet hard to keep track of all the things. And then you would most probably end up in the situation, where you do not know, if things have an effect, why you do what and worst case you are disappointed in a way, that you stop using advanced marketing features.

Of course after I showed, how things are maintained in Sitecore and showed a general appraoch of starting with those features, I thought it also make sense, to show all the applications, the customer can use. From the survey I already knew, that they just using Conent and Experience Editor. But Sitecore XP is much more. So in the next part of the workshop I showed them all these applications.

Lastly after all the theory part, to have a look at all features and applications I previously described, I made a DEMO. And of course this demo was prepared in one of the customer testing instances with their modules, pages and content. So the use case of the demo was, that I created 2 landing pages, one with a contest form, one with special content about a topic they are already presenting in a special way e.g. in searches or detail pages. I added some basic goals and applied them on the landing pages and of course on the target page after submitting the contest form to be able to track usage of the contest form. I also added some campaigns, like “Social Media”, “Newsletter” and “Flyer” to showcase, that we are able to track the traffic from various channels online AND offline to see, which channels perform best for our landing pages. Lastly I also tagged some content with proper profile cards to be able to later on classify our end users to a specific type of user. So in the end, I just showed, some prepared customer journey and afterwards showed, what data were collected before applying all the advanced marketing features and what data were collected after applying advanced marketing features. This of course lead to the “aha” moment I wanted to get on customer side. So at this point they starting to realize two tings

  1. Sitecore is capable of collection various data apart of the OOTB ones (visits, clicks etc.)
  2. Advanced marketing features of Sitecore XP are no sorcery and can be added and edited by nearly everyone working in Sitecore

One interesting first outcome of using Sitecore XP marketing feature was a bit funny and eye opeing at the same time. When we had a look at the existing analyitcs data and wanted to see top entry and exit pages, one results was really not expected.

So based in the data, which can be seen in the images above one of the most used entry & exist page is the 404 page. This is a clear indicator, that on the one hand site some indexing of search engines like google might have old incorrect urls, which directly lead to 404 page. And on the other site, that there are customer journey, which end on the 404 page, so most likely clicked on invalid and broken links. So from that point on, the customer should now definitely have a closer look e.g. with path analyzer to see the whole customer journeys, which start or end with 404 page to find out, what might be the reason for that to fix it. But in my opinion already a great outcome if you just have a look at the collected analytics data of sitecore xp

Survey after workshop

As you might remember from Part 1 of that blog post, I created a small survey to find out, where the customer is right now regarding use of Sitecore and marketing features. What was now interesting for me is, to see, if some of the answers have changed after the workshop. And most interesting for me were the last two questions. And in deed they really changed.

If you compare now the answers from before and after the workshop you can see, that more people now thing, that it really is important to use personalization to customize customer journey.

And here you can see, that now the results, if personalization is a complex task in Sitecore stabilized at about 5 out of 10. Which means, even after they had deep insight into everything, they do not think its a complex task and doable for them, which is really great.

Next steps

Of course after such a workshop, the question is, what are the next steps? The answer is quiet clear. Get an idea, what you want to achieve with personalization and what targets and goals you would like to reach. To do so, you definitely need time and some people to discuss about that topic and to maintain all that within Sitecore.

My recommendation at that point was, to really start with small pieces. So e.g. take the use case of newsletter registration. Start grabbing information, if the newsletter registration small or big (rendering variants used for different cases) is more successful. Then start replacing the newsletter registration module with some other content module via personalization, in case the current user already registered to the newsletter. Then take more and more use cases and more and more features of Sitecore into mind and get more complex over time. So do not start using directly everything just randomly. And I am glad to accompany the customer on that journey in the future.

Conclusion

Within this blog post I tried to demonstrate an approach of how a customer can start using advanced marketing features. I tried to first get an idea of where the customer is from the information and development point of view. Then I prepared a customer specific workshop to demonstrate all the functionalities the customer is not using at the moment and how easy it is to use all of them. Of course together with a technically introduction, I tried to give the customer also a guideline of how personalization can be introduced in theory. Finally I prepared and showed a demo with really customer specific content, pages and modules, so that the customer really gets an idea, what might be possible with his / her data.

Unleash the power of Sitecore – Experiences from customers diving into advanced marketing features for the very first time

Today I would like to talk about a topic, which is not that common for me. Normally I share my knowledge and experiences in issues, problems, challenges and how to overcome those from real world projects in implementation and development stuff.

But this time I would like to talk about something else. In the last 2 years I am working now for quiet a few customers. Of course working for different customers is always different with varying requirements. But sadly one fact is most of the time the same. Customers working with Sitecore just using it more or less as pure CMS. Most of the time all the marketing features Sitecore overs OOTB are not even touched by the customer. And in the end in my opinion it is a complete waste of potential marketing power.

So I decided that now I wanted to stop that; At least for customers I am responsible for. Of course there are duzend of great articles, videos and demonstrations, of how marketing features in Sitecore work. But to be honest, introducing such piece of functionality to a customer, needs more than just the hard facts. Because every customer thinks, behaves and acts quiet differently and has a different thinking of the value of data or how to deal correctly with those data, the introduction of marketing feature needs a bit sensitivity than usual when developing some new modules.

This article should demonstrate and illustrate the concrete experiences I gained in guiding customers to use advanced marketing features. What was the status quo of both, the technical solution, but also knowledge and experiences on customer side regarding the usage of marketing features? What were the first steps to convince customers of the benefits of advanced marketing features? Up to the point how to start using advanced marketing features of Sitecore and the first results of that.

Status Quo

In my opinion to know the status quo is quiet important. Depending on the the underlying solution and / or the understanding of marketing features, the approach of how to introduce such features to a customer can be completely different. Therefore we should definitely have a closer look on that.

Technical

Let’s start with the overall technical base of the Sitecore solution. The solution of the example customers I were based on Sitecore XP together with XC on version 9.X. Additionally it is planned to actively use Sitecore Forms in the future, which should be definitely kept in mind, regarding marketing features. Beside that, no other modules are involved into the solution. The so called Phase 1 (Go Live ^^) was now done a while ago and they were ready to start with Phase 2 (Fancy stuff).

So from my personal point of view, the best starting point to start using advanced marketing features of Sitecore.

Knowledge and experience of customers

All the customers I am trying to support atm. have a longer history with Sitecore. Most of them started already with version 6.X, upgraded a few times, made some relaunches, up to the point, where they have reached now 9.X. So you could imagine, that all the customers really know, what Sitecore is capable of, because they are already using that CMS for some years now.

But after a few talks, I rapidly noticed, that unfortunately this might not be the case, not at developer side, but not at editor or marketeer side as well. So to better understand, how customers are working with Sitecore and which experiences they really made and have, I decided to create a small non-representative survey to be 100% sure.

Survey Questions

  1. Which role do you have working with Sitecore?
  2. How long are you already working with Sitecore?
  3. How long do you work with Sitecore per day?
  4. Which Sitecore applications did you already use?
  5. What is the weighting of your work between content and page editor?
  6. Which analytics / personalization features do you know from Sitecore?
  7. Did you already personalize content in Sitecore?
  8. Did you already create a campaign in Sitecore?
  9. What do you think, how important is it to personalize content for the user? (1 Unimportant – 10 Important)
  10. What do you think, how complex is it to personalize content in Sitecore? (1 Trivial – 10 Complex)

Leading Questions, which should be answered by survey

  • How much experience do the customers have with Sitecore at all?
  • How are they using Sitecore in their daily work?
  • Did they every touched marketing features in Sitecore?
  • Are they aware, that there is a huge hidden potential?
  • Are they willing to try out such features?

Survey answers

After I evaluated all the answers of the customers, I got a really clear picture of the status quo, how the customers are working with Sitecore.

Which role do you have working with Sitecore?

From that question, we can see, that not only authors were asked, but also developer, marketeers and some stakeholders as well, who are not directly working with Sitecore, but should also have a clear understanding about, what Sitecore can do for them, regarding advanced marketing features. One result from that question really surprised me. From all the people, who participated in the survey, there was not one in the analyst role. So it might be the case, that the analyst did not want to participate, or, which might be a bit concerning, there is no analyst in the team, who might push topics like using advanced marketing features.

How long are you already working with Sitecore?
How long do you work with Sitecore per day?

From these answers we get the information, that customers are using Sitecore already for a longer time, most likely already in former versions. So Sitecore is not completely new for them. They are also mostly working all the day or most of the day within Sitecore doing their daily job. From evaluating single answers, I also found out, that developer as well as authors are working much more with and within Sitecore, where marketeers are only touching the system from time to time.

Which Sitecore applications did you already use?

To be honest I already assumed, that the answers of the following question are similar to what you can see. But it clearly points out one big thing:

Sitecore is mostly used as CMS

From evaluation of single answers, I was able to see, that just developers had a first look into other applications like Content or Experience editor.

What is the weighting of your work between content and page editor?

The result of this question is also quiet common for many customers, who are already working longer time with Sitecore. In older versions like 6 or 7 it was quiet common to mostly work in Content Editor. But nowadays you mostly work in Experience Editor to edit content with all the benefits you get of the WYSIWYG Editors. One important thing, which has to be done by the implementation partner is, that all the module are 100% or nearly 100% Experience Editor editable. In case the implementation has not been done properly, editors are forced to all the time switch between content and experience editor. At least in projects, where I am responsible for I highly focus on the fact, that each module is editable via experience editor as much as possible.

Which analytics / personalization features do you know from Sitecore?

Of course there were also correct answers like, campaigns or module-personalization, but also answers, like seen above, which just shows, that people, who are working with Sitecore all the day, are not aware of some core features, Sitecore offers OOTB. So with such a knowledge base, it is quiet clear, that customers are not using advanced marketing features.

Did you already personalize content in Sitecore?
Did you already create a campaign in Sitecore?

And of course based on the answers of the previous questions, it is als obvious, that most of the people never ever personalized content or created a campaign in Sitecore as well, when they not even know about the applications.

What do you think, how important is it to personalize content for the user? (1 Unimportant – 10 Important)
What do you think, how complex is it to personalize content in Sitecore? (1 Trivial – 10 Complex)

These two last questions are quiet interesting for me as well. The answers show, that all the people at customer side know about the importance of using analytics data to personalize content to achieve a better customer experience. And most of the asked people believe, it has a medium complexity to start using personalization in Sitecore. And of course I will show them, that it is really not that complex, as they might think, to do so.

So lets sum up, which overall information we got from that survey and try to answer my leading questions.

Answers to leading questions

  • How much experience do the customers have with Sitecore at all?
    • At least my customer have a lot of general experience with Sitecore
  • How are they using Sitecore in their daily work?
    • They are mostly using Sitecore as CMS
  • Did they every touched marketing features in Sitecore?
    • No, which explains, that they not really know, what Sitecore offers
  • Are they aware, that there is a huge hidden potential?
    • Yes, they are aware of some unknown set of features for personalization
    • No, they are not really aware, of all the other features Sitecore offers (Advanced Marketing Features)
  • Are they willing to try out such features?
    • Yes, they know about the importance of marketing features and personalization and willing to try them out

And in my opinion these results are quiet common, not only for customers I asked, but for many many customers, who are using Sitecore.

Preparation to be able to use advanced marketing features

So, after we found out, where we come from and where we are from knowledge and technical point of view, we now can start having a look, what has to be done now to really be able to use advanced marketing features.

The very first step was maybe a bit unusual, but it was to gain some basic and additional knowledge on marketing features of Sitecore. This was necessary, cause till now I was more or less mostly Sitecore Developer / Consultant. I decided to extend my portfolio with deeper knowledge about advanced marketing features in my free time. And not only, what theoretically can be done, but also with practical experiences.

While doing that, I encountered a really great guide published by Sitecore SBOS team to check the instance, if it is ready to use advanced marketing features.

Optimization Readiness Checklist

This checklist was a really great initial solution checkup. I went through all of the mentioned points and aspects of the solution and was able to mark everything as “green”, which we expected to work. As an example, the point D currently cannot work within our solution, cause Geo IP service is not activated by now, like mentioned within this article of Sitecore Documentation, where the activation(subscription) process is being described in detail. But it will be definitely discussed, if it would not make sense to also activate that feature of Sitecore for future tracking reason. Another special point from the SBOS checklist was K. In standard implementation of our registration and login process, till now, we never focused on xDB and enriching data to be reused in xDB. This means, that we had exactly the same issue within our instance, than Sitecore had in its own instance, like described here under Sitecore.com discovery and workshop.

(1) Individual contacts records in the Experience Profile tool were all anonymous and could not be opened;

But based on these information, it will be quiet easy extension of registration process to enrich customer data with some xDB facets, so that registered contacts are correctly classified as non-anonymous, e.g. like mentioned in article like this one.

Finally and luckily all the other points of the checklist were working totally fine as expected, so that we were and are able to go on.

First steps forward

After we now prepared our solution to be ready to use advanced personalization features in general, we can now finally start to tackle the real introduction and the first steps to do that.

General possibilities in Sitecore

Let’s have a first look, what Sitecore offers us and therefore, which features we would like to introduce to the customer. And of course before I started working on that topic, I had to do some own, deeper research. From my investigations I decided initially to cover the following basic topics. Cause from my point of view, the following features would be a great starting point to get in touch with advanced marketing features of Sitecore.

I will also not describe all these feature in depth, cause there are already a lot of great articles by Sitecore or other people or agencies, showing, what all these features are able to do. Therefore I will just cover them really roughly with one or two sentences, what the feature is about, and will provide some other references for detailed information.

What does Sitecore track OOTB 

If you have a closer look, at what Sitecore already tracks Out-of-the-box, you are able to understand, how you can improve the quality of these collected data. And of course I did that.

This slideshow requires JavaScript.

As you can see, Sitecore is able to track a lot of general data about visits, like number of visits, duration of visits, language of visited page and many many more. You can have a look on your on, if you just open the Experience Analytics Application. From that it also calculates fully automatically some metrics like, best entry page, best exit page and so on and can visualize click paths e.g. via Path Analyzer to find good and bad performing pages. And all that OOTB without doing anything in addition. 

From the slideshow you can also see, that Sitecore is able to visualize even single sessions and show, what this session did within it’s visit on the page. Note: To visualize data from anonymous visits you have to follow this article. But be careful and read the warnings about doing that. But once you did that, you can also see all these kind of data on single session level.

But lastly you can also see some slides, where more or less no information are visualized. This is the case e.g. under the Campaigns and Conversions tabs. And exactly that’s because these data are data, Sitecore can collect, if we start using advanced marketing features. Once we do that, Sitecore also starts tracking data about events, goals, campaigns and so on to give us even more and even better data to analyze.

Goals

In general, goals in Sitecore help to give users’ interactions a semantic weighting in the form of points. For example, Submitting a contact form or participating in a competition earns more points than just visiting the website. With this information, it can now be analyzed in a much more granular way how good a website visit was.

Campaigns

A campaign is a promotion or advertising initiative designed to encourage people to visit your website. Campaigns run for a defined period. You can use campaigns to raise brand awareness or to get contacts to perform certain actions on your website. (Source: “Sitecore Doc”)

Profiles / Pattern Cards

With Profile cards you can easily classify content of your website. A Profile card contains one or several profile keys, representing different aspects of the given profile, with different numeric values. Once a user enters a page with a profile card, Sitecore uses the information to assign a user the pattern card, which matches best.

Pattern cards on the other hand are used to evaluate all the information collected by a user while visiting content with profile cards and finally classify, which pattern card, which user gets assigned. The more the user uses the website, the better Sitecore can classify the user.

Marketing Automation

A marketing automation campaign is a plan that lets you determine how your brand interacts with your contacts depending on their activities. You can use marketing automation campaigns to nurture the relationships with your contacts by adapting your communication according to the content, channels, and media that are relevant and appropriate for each individual interaction. (Source: “Sitecore Doc”)

A/B testing

One type of A/B test is the basic content test, which compares the effectiveness of two versions of a page. Another type of A/B test is a component test in which you compare different variants of a single component. If there are more than two variants, it is an A/B/N test. Page tests are also either A/B or A/B/N tests, depending on how many pages you test. (Source: “Sitecore Doc”)

Personalization

Personalization is the method for displaying targeted, relevant content to your contacts based on their characteristics and behavior, such as location, gender, or previous visits. With personalization, you can ensure that the right content reaches the right contacts, for example, by showing, hiding, or adjusting content. (Source: “Sitecore Doc”)

Conclusion

In this article, I tried to find out, what kind of hidden potentials many, many Sitecore projects have. To do that, I started with a small survey with all of my clients to find out, how they are working with the system and how they estimate the importance of personalization and the effort to use it in Sitecore. Based on these information I started to deep dive into personalization on my own to find out, what Sitecore really offers regarding advanced marketing features, followed by a small check of the current solutions. And of course the next steps will be to introduce all that to the customer in a proper way, that they understand the importance of marketing features in modern websites. Stay tuned to get part two of this blog post, where I will report how this went with all the learning and hopefully first successes.

Accelerate the power of Sitecore XC policies – Custom plugin to let content authors change settings in BizFx tools on runtime

Accelerate the power of Sitecore XC policies – Custom plugin to let content authors change settings in BizFx tools on runtime

For some time now, while working with Sitecore XC, I am struggling with the concept of policies. In general I really like that concept, how new policies are added to an environment and how things work. But more more I got requirements from customers, who wanted to be able to change those policies on their own. And of course you all now, that this is not possible. Policies are added, edited and maintained purely by developers. So either way you would have to exactly do that. Just change the setting all the time the customer wishes, or provide a smarter solution for that. And exactly that I tried to fulfill. Within this blog post I will first describe shortly the mechanism of policies and how they are maintained, will come back to he customer requirements, which are appearing more and more in all my projects and what that really means for us developers, till I finally present some extension for Sitecore XC OOTB logic to generically fulfill such requirements in an easy way.

Introduction to policies

If you are not familiar with the terms environments, policies and roles I strongly recommend you to read first one of my previous articles, which can be found here. But let me also try to sum up the essence of that article here a bit.

As you all might now, the normal way of storing any kind of configuration for Sitecore XC, is, to store it in a custom policy. A policy is nothing more than a piece of json file like seen below.

2020-03-18 20_07_55-esrvath02 - Remotedesktopverbindung

As you can see such a policy consists of 1 to n different properties, which can be set and maintained within that specific json file. These values are then mapped to custom .cs policy file to be then used ion runtime

2020-03-18 20_09_50-esrvath02 - Remotedesktopverbindung

Multiple of such policies are then combined together to one big environment Sitecore XC uses to execute pipelines, blocks commands and more for specific storefronts.

So in the end to speak in Sitecore XP terminology these polices are very similar to .config files or patches under the App Config/Include folder. As good as that works the trouble starts now in the way, of how such configs are maintained and deployed to other environments.

Process of how to bring changes of policies live

Boths types of configurations .config files and .json policies have the same weakness or better restrictions. They can normally not be maintained by content authors. The normal process of changing a value there and bringing it e.g. to production is in simple words the following

  • Change the value locally 
  • Commit and push these changes
  • Deploy this to the target environment 
  • Bootstrap environment so that json values are stored in DB to be used on runtime

So you can already imagine, that this is nothing an editor can do, and nothing, which can be done very quick. Because of that normally, in Sitecore XP you create global setting items, which can be maintained on runtime by content authors. Unfortunately nothing similar is existing in Sitecore XC – till now. ^^

Custom Settings plugin

So because I recognized, that there is definitely a lack in OOTB implementations, which make the life of content editors and developers more difficult, I thought, it makes sense to provide some new plugin to fill that gab.

What does it do?

With the newly created settings plugin you are now able to set previously defined policies values within a new BizFx application on runtime.

How does it look like?

In the screenshot below you can see the new application after integrating the setting plugin into a customer solution.

2020-03-16 10_05_19-esrvath02 - Remotedesktopverbindung

If you click on the settings application an overview of all existing settings is displayed. If no setting exists a default one is created automatically, which can be used.2020-03-16 10_06_14-esrvath02 - Remotedesktopverbindung

In the standard implementation of settings plugin you have 4 actions available to interact with settings, which can also be seen in the screenshot below

  • Add
  • Remove
  • Activate
  • Deactivate

Add: On click a new forms opens, where you can enter a Name and Display Name to create a new setting entity.

Remove: Removes the currently selected settings entity

Activate: Activates the currently selected settings entity. In addition it iterates through all other existing setting entities to disable them automatically, so there can be only one setting be active.

Deactivate: Deactivates currently selected settings entity

2020-03-16 10_06_39-esrvath02 - Remotedesktopverbindung

If you now click e.g. on the Default Setting entity, the corresponding entity view opens. After initially integrating the plugin, the settings entity will just have one single property is Active, like you can see below.

2020-03-18 20_27_51-esrvath02 - Remotedesktopverbindung

From this point on, you can now start filling the settings entity with all kind of policies you would like to edit on runtime.

How to integrate it into custom plugins?

So let’s start of how to integrate a custom plugin policy into the settings functionality.

Basically you need 4 different blocks to be able to display information in an accordion in an entity view, to provide an editor action on that accordion, to display a form to be able to edit properties and to be able to apply these changes to the current entity.

  • EntityViewXXX (Used to display data in accordion view)
  • FormEditXXX (Used in dialog to edit properties)
  • DoActionXXX (Used to apply edited properties from FormEdit to entity)
  • EnsureActionXXX (Used to provide edit button on new accordion view)

For all of you, who already extended entity views with new accordion views, know, that this needs some time to be fully implemented. Therefore the first thing I did for the settings plugin was, to make that process much easier for developer.

Base blocks

The settings plugin provides you with 3 different base blocks, which can also be seen below.

2020-03-16 10_11_28-esrvath02 - Remotedesktopverbindung

What you now just have to do to integrate your plugin into settings is, to create 4 different blocks and do the following steps

  • Inherit from the corresponding base blocks of settings plugin
  • Execute Base.Run method and provide policy as generic parameter and view  or action name in function parameter
  • Add all the new blocks to the specific pipelines in ConfigureSitecore.cs

2020-03-16 10_12_55-esrvath02 - Remotedesktopverbindung

Now let’s have a look at the whole code of the 4 blocks, where we use inheritance to use some basic functionality.

2020-03-16 10_13_05-esrvath02 - Remotedesktopverbindung2020-03-16 10_13_13-esrvath02 - Remotedesktopverbindung2020-03-16 10_13_21-esrvath02 - Remotedesktopverbindung2020-03-18 21_03_46-esrvath02 - Remotedesktopverbindung

As you can see, the whole implementation of all these 4 blocks consists of just one single line of code, where you just have to tell the function, which policy and which view name (Entity View) or which action name (DoAction and Form Edit) to use.

Last but not least add all the 4 blocks now to corresponding pipelines, like seen below

2020-03-18 20_52_50-esrvath02 - Remotedesktopverbindung

Policy Property Attribute

In addition to the base blocks, which can be used in custom plugin, you now just have to use the newly provided EditorSetting attribute on already existing plugin policies. In the screenshot below you can see an example, where I added the new attribute to all properties of the PimImporterPolicy you already know from the beginning.

2020-03-16 10_08_18-esrvath02 - Remotedesktopverbindung

After you added these attributes to the policy and reload the settings entity again, you will now see, that a new accordion has been loaded with all the properties you previously added via setting the editor setting attribute.

2020-03-16 10_07_14-esrvath02 - Remotedesktopverbindung

And of course also the edit functionality is directly fully working like seen below.

2020-03-16 10_12_02-esrvath02 - Remotedesktopverbindung

And lastly, of course if you confirm changes, the piece of code is also already working, which applies these changes automatically to the current settings entity.

Note: As you might see, there are of course currently some limitations, like list handling, which will be covered in more detail as improvement in the future. Right now you can also edit lists, which are treated as pipe separated strings.

In case you do not want to use every property of the policy, you can easily remove all the attributes from the properties you would like to exclude from settings functionality.

2020-03-17 09_47_41-esrvath02 - Remotedesktopverbindung2020-03-17 09_50_21-esrvath02 - Remotedesktopverbindung

In this example I removed the setting for start hour, end hour, pim endpoint because I do not want editors to edit such properties ^^. But in the end it is completely up to you, what you would like to be editable in settings entity.

Extensions

Now, after we added our policy to the settings entity, we also want to use it in our code. To do that, I also created some piece of code to do that. The same way you retrieve policy from commerce context, you can now also retrieve settings policy.

  • context.GetPolicy<T>() -> Grab policy from environment
  • context.GetSettingPolicy<T>(CommerceCommander commander) -> Grab policy from active setting entity with fallback logic to grab policy from environment

Below you can the whole and simple implementation of GetSettingPolicy with integrated fallback logic.

2020-03-16 10_10_50-esrvath02 - Remotedesktopverbindung

If we now think of possibilities how we could use the new settings in custom code.

Different ways to use setting policies together with OOTB environment policies

  • Overwrite whole policy
    • In such case just use the new extension method context.GetSettingPolicy<T>(…) and continue working with the returning policy
  • Overwrite just specific properties
    • Use Standard context.GetPolicy<T>() AND context.GetSettingPolicy<T>(…) to retrieve environment and setting policy to decide later on, which property to be used when and which fallback logic shall be applied
  • Completely standalone setting
    • Note that such policies are not stored in environment and cannot be retrieved via OOTB context.GetPolicy<T>() call
    • Use context.GetSettingPolicy<T>(…) to retrieve the setting policy

Because in our example, we removed some of the properties from the possibility to be edited in settings, we would have to apply approach number 2 from above. To do that, we first grab settings policy, beside with environment policy.

2020-03-16 10_09_36-esrvath02 - Remotedesktopverbindung

And then we can easily and individually apply our custom fallback logic for each property, like seen for mailsubject below.

2020-03-18 21_29_40-esrvath02 - Remotedesktopverbindung

Conclusion

Within this blog post I presented a newly created plugin called Plugin.Sample.Settings, with which you are now able to edit policy properties not only in json on development time, but also within BizFx tools in a new application on runtime.

This way it is much easier to edit specific settings per environment as developer or editor.

The whole code can be found in the following github repository

And as always, the code is not production ready and is not extensively tested. Therefore use this code as a starting point for your own implementation.

Sitecore XC – Deleting sellable items programmatically might lead to SQL deadlock exceptions

Lastly while working with Sitecore XC I had the task to clear a whole catalog. This means I wanted to delete all sellable item and all categories. If you are interested in the overall situation, you can just read one of my previous blog posts, where I described the scenario in more detail.

While implementing some custom piece of functionality, I encountered a very nasty issue. As you might imagine, a catalog can contain a massive number of sellable items. In my case the catalog had over 12k products. So when I decided to delete all of them at once, I knew it would take some time. But unfortunately it does not only take some time, it is also highly possible that the process will run in some SQL server deadlock exceptions.

Below you can see a very simple code to grab all sellable items from commerce list, which belong to the target catalog I wanted to clear. Once I got all the sellable items, I just have to iterate through all of them and call DeleteSellableItemCommand from commerce engine. This way, the entity is not only deleted, but also all possible associations are removed as well.

2020-02-11 19_19_44-esrvath02 - Remotedesktopverbindung

So when I now let the code run, I recognized, that the log size increased massively after some time. After short investigation I saw the following error

00034 18:52:22 ERROR SQL:block:deleteentity.Error: Message=Transaction (Process ID 91) was deadlocked on lock resources with another process and has been chosen as the deadlock victim. Rerun the transaction.|Trace= bei System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)

After some more investigations I also found out, that this happens, all the time I try to delete all the sellable items. In the image below you can see, that e.g. the process started with 11206 items left and the errors started when 10870 items were left. So the process ran through for around 1000 items till SQL server error started for all further tries to delete a sellable items.

Note: If you have a look at the DeleteSellableItemCommand while the errors appear in log, you can see, that the command returns successful and says the sellable item is deleted. Therefore you just see, that it was not successful, when you first have a look at the log and second let the process run again and see, that there are a lot of items left, which should already be deleted.

2020-02-11 19_19_13-esrvath02 - Remotedesktopverbindung

Because I had no idea, why this happens all the time, I decided to report that to Sitecore Support. The good news after a long Investigation was, that this behavior is not normal and is registered as bug under the ref number #394412. Also Sitecore told be, what exactly leads to that error.

Issue: Within Minion instance there are two minions PurgeCatalog and PurgeCategories minion, which run in standard setting every 5 minutes. These minions check for catalogs and categories to be deleted. While doing that, they access the same tables with the same underlying procedure, than DeleteSellableItemComman to remove entities from tables and cause the Deadlock exception in the database.

Current Solution: The only workaround currently is, that you should disable both minions, when you try to delete a massive number of sellable items.

Sitecore XC – How to delete a massive number of categories / sellable items?

Lastly while working with Sitecore XC I had the task to clear a whole catalog. This means I wanted to delete all sellable items together with all categories. But the scenario, which is also possible could be, that you just want to delete all sellable item from a catalog, or you just want to clear a single category, without deleting it. So there could be many different use cases, which should be covered somehow.

Because I did not find anything useful within BizFx tools to delete them all at once, and no API Call within Postman, I decided to ask some Sitecore Architect directly.

The response unfortunately was, that such a case is not covered by OOTB commerce engine functionality. Either way I could use Clear Environment, but the really everything within my environment would be deleted, and not just categories and sellable items, or I could go directly into SQL server and delete entries from the entities table.

There is also a third way to achieve a cleared catalog. Of course you can use standard BizFX delete functionalities on categories. The trick is, that you go to a first level category of your catalog and click Delete.2020-02-29 14_44_31-Test Catalog

You are then asked if you would like to delete or just disassociate the current catalog.

2020-02-29 14_44_40-Test Catalog

In case you really want to delete everything, you can just choose Delete category. 

How deletion of categories works behind the scenes: Once you delete a category via BizFx tools, you should know, that the category is not really deleted immediately. What the authoring system does, if you click delete category is pretty simple. It just marks the category to be deleted and add it to a special commerce list. The trick now is, that the minion instances has a minion, which crawls the list in standard every 5 minutes, grabs the categories, checks if they really should be deleted and in the end delete the category. But it does even more. You know, that a category can be associated to other categories and / or sellable items. And that the number of such associations can be really massive in a complex catalog. Depending on the chosen Delete Option the process now either way grabs all associations for the current categories and just deletes the these, but keeps the entities behind them. Or grabs all the associations deletes them and iterates through every associated category recursively till it reaches the level of sellable items and starts to recursively deletes all the entities. So if you e.g. delete a first level category it does not just delete that category, but also all sub categories and all associated sellable items to this and all sub categories. Now you also should understand, why the BizFx click in the authoring engine does not directly execute the deletion process, but delegates the job to the minion instance. If you now do that on every first level category, the result is a cleared catalog. But of course that trick is only applicable , if you do not have duzend or hundreds of first level categories.

Because both proposed ways and the manual workaround were not really applicable in my situation, I decided to write some custom functionality, which achieves exactly this.

The outcome of a few hours of programming and testing were three new functionalities, which might also be useful for you at some point

  • Clear Catalog
  • Delete all Sellable items
  • Clear Category 

In the following small chapters I will describe all of the functionalities and what they do for you.

Clear catalog

First let’s have a look at a functionality, which is able to clear a catalog with one click.

Note: I would recommend to use such piece of functionality just in development or testing environments and only very wisely in production environments.

In the screenshot below you can see the very simple command.

2020-02-29 14_10_55-Alnatura.Experience.Commerce - Microsoft Visual Studio (Administrator)

This command uses a catalog name to do the following

  • While categories exist
    • grabs all categories of the current environment
    • filters all categories out, which are not belonging to the current catalog
    • Deletes the category
    • Again grabs all the categories 
    • Filters again for categories of the current catalog

Deletion of categories: We use here the PurgeCategoryCommand. This command is normally used by minion to delete marked categories. Because I want categories to be deleted immediately, I skip the mark operation and wait 5 minutes, and just call the delete operation behind the scenes directly. In the commented code above you can the the piece of code to mark a category to be deleted, so that a minion can grab it afterwards. Of course you can decide on your own the way, of how you would like to delete categories.

Iteration: If we directly delete a category, like shown above, we have to be careful, that after delete operation, not only this category, but all subcategories are now deleted, like described in the beginning. This means, that the list from earlier of all categories, now is not valid anymore. Because of that we have to grab a fresh list of categories of the catalog each time we delete a category. If we still would use that list and continue iteration, we would most likely hit a lot of categories, which are already deleted and would throw various errors on processing.

Delete all Sellable items

Because you could also have the use case, that you want to delete all sellable items, but would like to keep the whole category structure with all categories and associations, I also created a piece of code to just delete all sellable items from current catalog.

2020-02-29 14_11_36-Alnatura.Experience.Commerce - Microsoft Visual Studio (Administrator)

The code from the screenshot above is quiet similar to the previous code. We first grab all sellable items within the environment and filter for those belonging to the current catalog. Then we really can just iterate through all of them and use standard DeleteDellsbleItemCommand to delete one after another. This works really well for a small amount of items to be deleted. But for massive number of items to be deleted, I encountered some serious issues, which lead to a newly reported bug at Sitecore support. Read more about this here and how to work around that issue.

Clear Category

Last but not least, I also created a small helper to clear just a single category, which means to delete all sellable items associated to a specific category.

This time the code is a bit more complex. Not only because, we have to grab the associated sellable items but also, because I added here some piece of logic,which avoids accidential deletion of entities, even though they are still associated somewhere else.

But just let’s have a look at the code

2020-02-29 14_15_58-Alnatura.Experience.Commerce - Microsoft Visual Studio (Administrator)

At first we grab our category to be cleared. Then we use standard functionality FindEntitiesInListCommand with special parameter to grab all associated sellable items. Then of course again we can iterate through all items.

2020-02-29 14_16_30-Alnatura.Experience.Commerce - Microsoft Visual Studio (Administrator)

But this time, we do not just delete the sellable item, which we of course could do. This time the deletion operation is a bit more intelligent. First we just use standard IDeleteRelationshipPipeline to delete association between category and sellable item. Then before we simple delete the sellable item, we check if the item can be deleted.

2020-02-29 14_16_43-Alnatura.Experience.Commerce - Microsoft Visual Studio (Administrator)

Above you can see the check if an item can be deleted. In case the current sellable item is not linked to any catalog or any other category anymore we can safely delete the sellable item. In all other cases the deletion of the sellable item would mean, that it would also disappear at various other linked places, which we might do not want.

Conclusion: So within this article we discussed some operations developer would like to execute on their local / testing catalogs to clear corrupt or broken entities to get a clean greenfield situation back. We learned how deletion of catalogs / categories and sellable items work and how to use that knowledge to extend OOTB functionality of commerce engine in a simple way.

Sitecore XC – Everything you have to know to work with media items

This time I would like to share some insights on the topic, of how to use Stecore XP media library items within commerce engine entities. Maybe most of you, who already used Sitecore XC, have already seen the Images component of sellable items and variants.2020-01-18 20_49_56-Alnatura - Microsoft Visual Studio (Administrator)

Of course I already played around with that and used images of example habitat and adventure works. But recently I was faced the customer requirement, that customer wanted to map own images from Sitecore XP media library to previously imported products. And here the story begins…

As mentioned above I already around a bit with images on demo products. Below you can see the steps to map an image to a sellable item in demo environment

2020-01-18 20_53_33-Alnatura - Microsoft Visual Studio (Administrator)

2020-01-18 20_54_16-Studio X Over-the-Ear Wireless Headphones

As you can see, you can just use some kind of search to find the proper image, chose it and easily set it.

So my first step was to go into a custom product, within a custom environment and just try to add my images from media library there, as I did with habitat or adventure works products.

2020-01-18 21_09_31-Winterschokolade

One thing I realized very quick was, that I in deed find images, but not my ones.

2020-01-18 21_13_31-Winterschokolade

As you can see above, on my sellable item within my own environment, I just saw e.g. backpack stuff instead of all my food images I wanted to see.

2020-01-18 21_15_16-Winterschokolade

And once I entered the exact media item name I was searching for, I just got “No results” screen.  But I know my image was added correctly to the media item

2020-01-18 21_14_55-Desktop

What I did on XP side, was, that I just added a folder common, beside the folder adventure works and habitat and added all the product images I wanted to use later on there.

2020-01-18 20_51_19-Desktop

But obviously that was not enough. For some reasons my own new images were not found. So let’s start looking, what really happens on search call to understand, where the problem my be.

2020-01-18 21_17_03-Winterschokolade

As you can see, I started to have a look at the call, which was executed on search click. You can see, that a DoUIAction() call is triggered with some special parameters. One parameter is exactly, what we were looking for, the “Action: SearchMediaItems”. So we know now, that there must be some action called SearchMediaItems within commerce engine call.

So next step was a familiar one. I used dot peek to have a look at commerce engine dlls to find that function. To be sure I really find something, I just added all commerce engine dlls to dot peek and just searched for SearchMediaItems.

2020-01-18 21_22_09-JetBrains dotPeek

The results can be seen above. Very successful I would say. After looking into some of these classes, I finally found the interesting one, SearchMediaItemsBlock.cs. In the end this class is being used for searching media items in XP from XC side.2020-01-18 21_23_48-JetBrains dotPeek

The decompiled code of that class now tells us even more. Sitecore uses some basic SitecoreConnectionManager class to handle all kind of search and retrieving functionality for items from XP. And within that manager class we have also a function called SearchMediaItemsAsync, which is in the end used.2020-01-18 21_25_06-JetBrains dotPeek

Having a look now into that class into our function, we finally get the information we needed. Sitecore uses predefined item API call with some parameters to access XP. To do that, it also uses an API Key ODataItemServiceApiKey, which is stored within a policy. So let’s have a look into that policy. 2020-01-18 21_31_06-Alnatura.Experience.Commerce - Microsoft Visual Studio (Administrator)

Of course now we can have a look into our environments to maybe find that property. And et voilà there really is a setting as you can see above. You can see some ItemID there. Now next step was to use that ItemID to find the corresponding item.

2020-01-18 21_33_15-Desktop

 And there was a Item. Within Sitecore XP in /system/settings/services/API keys there is an item which handles basic settings for searching. It tells e.g. which database should be used and defines some basic filters.

AND FINALLY the highlighted area shows us, why we did not retrieve any of our own images. There is a filter, that limits image retrieval to “images/habitat” and “images/adventure works”.2020-01-18 21_34_24-Desktop

So now we also know the steps how to fix it. And of course I don’t want to fix it with manipulating OOTB Items from Sitecore. So I just created a new API Key Item with some custom Search Filter setting. As highlighted above I just want to include the folder “images/common”. Everything else is more or less the same for now.2020-01-18 21_36_43-Alnatura.Experience.Commerce - Microsoft Visual Studio (Administrator)

Next step after creating the new Api Key item, we also have to add it to our environment file. Above you can see, the comparisons of the OOTB and my custom environment. The nice thing about that approach of adding a new api key for my new environment is, that both environments now can search for media items completely decoupled from each others.2020-01-18 22_33_18-Winterschokolade.png

So, if we now execute the search again from the beginning, we finally also get the result, we wanted to have.

Of course it is nice, that we can now link our own images to our own products, but the initial requirement is not really fulfilled. The customer does not want to manually link all the images after an image import. So there has to be some kind of automatism.

I decided to integrate image linking to my standard product importer pipeline, which you already know from earlier blog posts. I hust added a new function called EditImageData.

2020-01-18 21_42_50-Alnatura.Experience.Commerce - Microsoft Visual Studio (Administrator)

The code for that small function can be seen above. We just use the information we got from dot peek and use the SitecoreConnectionManager also within our code. One special thing on our images is, that the image name is exactly the so called ean (gtin).

Once we got the proper image, we just retrieve the standard ImagesComponent and add the Image Sitecore ID to the Images list. And that’s it. After doing that and re importing all our products, all our products finally now got an image fully automatically.

Sitecore XC – Finally price card snapshots also have an end date

Sitecore XC – Finally price card snapshots also have an end date

In this blog post I would like to present you an implementation for an issue we all might have suffered from. But let us start in the beginning and shortly discuss how pricing works in Sitecore XC in general.

How does pricing work in Sitecore XC?

The most basic way to set a price in Sitecore XC is, that we just set a price on the sellable item directly as List Price. This price can be of course set per currency like seen in the example below.

2019-11-13 07_54_17-ALNATURA-DEV - 51.141.30.11_3389 - Remotedesktopverbindung

Because such a price setting is quiet inflexible Sitecore has build some piece of logic on top of that. The core principle of that mechanism is so define a price based on currency, date, and quantity, which is far more flexible, than just set one single price per sellable item.

This can be edited by an editor under the Pricing Application in the Business Tools of Sitecore XC.

2019-11-13 09_41_17-ALNATURA-DEV - 51.141.30.11_3389 - Remotedesktopverbindung.png

Once you entered this application you are able to define a so called Pricebook.

2019-11-13 07_55_15-ALNATURA-DEV - 51.141.30.11_3389 - Remotedesktopverbindung

Such a Pricebook can be linked to one or more catalogs and is itself just a container for more specific price settings, the so called Pricecards.

2019-11-13 09_05_38-ALNATURA-DEV - 51.141.30.11_3389 - Remotedesktopverbindung

Such a Pricecard then be directly applied on a sellable item to a sellable item via the Pricing field.

2019-11-13 10_18_36-ALNATURA-DEV - 51.141.30.11_3389 - Remotedesktopverbindung

Now the interesting part starts, where real price settings come into play. Pricecards themselves are again just containers for so called Snapshots.

2019-11-13 09_09_08-ALNATURA-DEV - 51.141.30.11_3389 - Remotedesktopverbindung

A snapshot itself then contains the information of a start date, when this specific snapshot should be applied, a tiered price per currency, which means you can define how much one single sellable item costs, in case a customer has X items in cart. And last but not least, you are able to tag the snapshot to define to which sellable items this specific snapshot should be applied.

2019-11-13 09_09_44-ALNATURA-DEV - 51.141.30.11_3389 - Remotedesktopverbindung

Therefore you see, that this pricing mechanism is far more flexible and powerful, than just adding a simple list price to a sellable item directly.

2019-11-13 09_10_05-ALNATURA-DEV - 51.141.30.11_3389 - Remotedesktopverbindung

Known limitations of snapshots

This overall pricing mechanism is really great and powerful. But when talking to clients and collecting all their wishes and requirements, one feature was wished very often, which is currently not possible to fulfill with the OOTB capabilities. The client always asks exactly the following question

How can I set an end date for the snapshots?

Right now the behavior of snapshots is very rough described like this:

  • Once a Pricecard is linked correctly to a product, Sitecore grabs all the snapshots and checks if the start dates of the snapshots are greater than the current date time.
  • Then Sitecore sorts all the snapshots descending
  • Finally Sitecore just grabs the first element from that list and evaluates its pricing information

This means, than if the start date of multiple snapshots have been reached and therefore multiple snapshots would be valid, Sitecore takes the latest one to ensure, that at a specific time just one single snapshot is valid.

So for a content author this means, he has to create a snapshot to determine a specific pricing. Once he wants to change that pricing for a specific period of time, e.g. to offer a special price on a special day or a special time span, he would have to create a new snapshot with the new pricing information and and the proper start date. So now the issue starts. Because the author cannot set a specific end date, this price would be valid “forever”. And because we do not want to have that price forever, the author now has to create another snapshot with the old pricing again and the proper start date. This start date has then to be the date, when the special pricing should end. So instead of just creating two snapshots with proper start and end date, the author has to workaround that and create a third helper snapshot to restore old pricing again.

Of course this works, but to be honest is quiet unwieldy. We also asked Sitecore about the possiblity to set an end date on snapshots. The answer was, that they know about that missing feature, and that they are working on implementing that for a later version. But when exactly that feature is implemented by Sitecore themselves is not officially known.

The recommendation of Sitecore then was to implement such a feature on our own.

tenor

How to get rid of this limitation?

The solution is as simple as it might sound. We just implement the possibility to set and end date on snapshots, save that properly and then extend the snapshot evaluation while retrieving pricing information. Sounds easy, right? And yes it is, if you know where to hook in. Let’s have a rough overview of all todos:

  1. Extend the form to enter an end date in addition to the start date
  2. Extend the snapshot to also hold information about end date
  3. Extend the action, which saves the start date to the snapshot to also save the end date to the snapshot
  4. Extend the view to display also the end date in addition to the start date
  5. Extend sellable item and variation sell price calculation to respect the new end date field

Let us start with the task to extend to input form, where an editor can specify the Begin Date. Of course now we would like the user also to be able to specify an End Date the same way.

How do we achieve that?

Quiet simple! I knew this piece of code I need should be in the Pricing Plugin provided by Sitecore. Therefore I simply reflectored that dll to find something close to edit / show snapshot details. After searching a while, I also found the right class GetPriceSnapshotDetailsViewBlock, which you can see below.

2019-11-14 09_43_34-JetBrains dotPeek

So I just took that piece of code and added the new field End Date in the same way Start Date was added. You will see, that I slightly modified the OOTB code a bit also for the standard fields. The reasons for that were, that I wanted to change the date time format a bit when displaying the fields and that I wanted to include another field just in edit mode. But more details later on.

After adding all the stuff properly the new output of the dialog was the following.

2019-11-13 07_40_57-ALNATURA-DEV - 51.141.30.11_3389 - Remotedesktopverbindung

So next step is of course, that once an editor sets a proper End Date, we also want this date to be stored somehow on the Snapshot.

To do this, we have to implement a custom DoAction block, which is responsible for taking the properties entered in edit mode and saving them to the entities or components. Again I crawled in the dll and found the proper class DoActionAddPriceSnapshotBlock.

2019-11-14 09_56_12-JetBrains dotPeek.png

So again, I created my own version of that class and added piece of logic to also extract the End Date. The only problem, which now came up was, the issue, how the values were stored on the price card snapshot. Sitecore used a custom command for that. Unfortunately the parameter of that command did not really fit to the new situation of having now also an end date. As you can see, it just accepted a begin date. Of course there were also other overloads of that call, but more or less, they did not fit as well or would lead to a long rat tail I would have to handle. Therefore I decided to just create my own command, based on the given one, and extend also this piece of code to handle End Date properly. The basic implementation can be seen below.

2019-11-14 10_00_09-JetBrains dotPeek.png

My custom implementation is really nothing more, than a command with another endpoint also accepting the parameter End Date and a piece of logic to include the End Date into the snapshot.

2019-11-14 10_02_03-ALNATURA-DEV - 51.141.30.11_3389 - Remotedesktopverbindung.png

Because we are in a an environment, where we prefer composition over inheritance, I had to create a new component, which in the end holds the End Date property.

2019-11-14 10_08_46-ALNATURA-DEV - 51.141.30.11_3389 - Remotedesktopverbindung

If Sitecore implements that feature on their own, I am pretty sure, they will just add another property directly in the Snapshot component, like it was done with Start Date. But in the end it does not matter if the End Date property is located directly in the Snapshot component or in another child component. You just have to know where it is for later usage. But that’s already all the magic to set the End Date Property from the point the editor enters it to the point it is part of the Snapshot. Below you can now the the result, after saving.

Note: Here you can already see, that I changed the output date format also a bit to also display time and not only date, which makes it much easier for editors to set Start and End Date minute-by-minute.

2019-11-13 07_43_46-ALNATURA-DEV - 51.141.30.11_3389 - Remotedesktopverbindung

Now let’s come to the more interesting part of the implementation. After we have successfully set the End Date we of course also have to evaluate it properly. To do that, I had to find out, where the Snapshots are evaluated at all to also hook in there.

After some time crawling through the dll, I found exactly, what I needed. CalculateSellableItemSellPriceBlock for sellable items sell price calculation and CalculateVariationsSellPriceBlock for variants of sellable items sell price calculation. Within these classes you can see, that the calculation included functions like ResolveSnapshotByCard and ResolveSnapshotByTags, which in the end use functions like FilterPriceSnapshotsByDate and FilterPriceSnapshotsByTags.

2019-11-14 10_16_22-JetBrains dotPeek

2019-11-14 10_16_41-JetBrains dotPeek

In the screenshots above I highlighted exact the location in code, where the snapshot is evaluated. The only thing now we have to do is, that we have to also include the new End Date in that calculation. For demonstration reason I chose the approach to create new classes, one for sellable item sell price calculation and one for variations, the inherited from the existing once and just overwrite the virtual functions to include our new evaluation.

In the End the functions in the new class look like this.

2019-11-14 10_20_56-ALNATURA-DEV - 51.141.30.11_3389 - Remotedesktopverbindung

2019-11-14 10_22_41-ALNATURA-DEV - 51.141.30.11_3389 - Remotedesktopverbindung

Just a simple evaluation if the End Date has not been reached.

Note: You can see here already an extension I made for End Date evaluation, which I describe in the end in more Detail

Now let’s see all that in action. I created a Pricecard called Demo and attached it to my demo product.

2019-11-13 11_16_20-Rechner

Then I created two snapshots on it. One snapshot should be valid from now to some date far in the future (or has no End Date). And one snapshot should only be valid for just a small time span, in this case just a few minutes. After that, the price of the snapshot before, should automatically take over again, without the need to create a third snapshot. The two snapshots can be seen below.

2019-11-13 11_21_48-ALNATURA-DEV - 51.141.30.11_3389 - Remotedesktopverbindung

2019-11-13 11_25_07-Rechner

2019-11-13 11_25_13-Rechner

Now let’s put that sellable item into the cart and see what happens over the time.

We start with a time after the start date of the “normal” price and before the start date of the “special” price.

2019-11-13 11_24_26-ALNATURA-DEV - 51.141.30.11_3389 - Remotedesktopverbindung.png

The result is exactly, what we wanted to have. Because the first snapshot is valid and the second not, Sitecore uses the price from the first snapshot to calculate sell price.

Now let’s call the cart a bit later. The time now falls into the start date of the first AND the second snapshot and also is located within the first and second snapshot end date. From Sitecore OOTB logic, it now should take the snapshot, which start date is closer to the current date time.

2019-11-13 11_41_34-ALNATURA-DEV - 51.141.30.11_3389 - Remotedesktopverbindung.png

And this is also the case, like seen in the screen above. Sitecore uses now our special price instead of the normal price, when we call the cart again.

Last but not least we now want to test the really interesting case. What happens now if we call the cart at a time, where both snapshot start dates are matching, but the end date has expired. We would expect now, that because the end date of the special price snapshot has expired, Sitecore automatically chooses the normal price snapshot again according to the new implementation.

2019-11-13 12_05_58-ALNATURA-DEV - 51.141.30.11_3389 - Remotedesktopverbindung.png

I know the sceeen above looks a bit wild, but displays exactly what happens. When we call the cart again at a time after the end time of the special price, Sitecore really takes the normal price again. As you can see the start and end date of the normal price match. And the start date of the special price matches. But because the end date, displayed in red, does not match, Sitecore does not use that snapshot, like it would do in standard implementation, but uses the first snapshot and uses its price as a valid sell price.

Note: Of course we could come into the situation, where no snapshot is valid, because all the end dates would be reached. But that is also no problem. In such scenarios, Sitecore’s own fallback takes over and uses as fallback to the price card logic simply the list price directly set on sellable item. But of course, if this price would not exist you are screwed and the sellable item would not be sellable anymore and would lead to an error, if trying to add to cart.

Now let me finally show you one little extension I already made, while implementing End Date handling. I believe, that there are scenarios, where some basic price really should have just a start date and no end date. Because the OOTB Date Time field always needs a value to be set, I worked around that and created in addition a small checkbox to let the editor decide, whether the really wants to set an end date. In case he want, he just checks the checkbox and everything is like described above.

2019-11-13 12_16_15-ALNATURA-DEV - 51.141.30.11_3389 - Remotedesktopverbindung

In case he does not check the checkbox, the DoAction block I created just ignores, what was transmitted in End Date field and simply writes DatetimeOffset.MinValue into the End Date property. This then can later on be checked and treated e.g. like an non existing value in display, like seen below.

2019-11-13 12_16_59-ALNATURA-DEV - 51.141.30.11_3389 - Remotedesktopverbindung

And as seen before in the sell price calculation we can also react on that specific value to avoid End Date evaluation. This way, in case you do not set an End Date for a snapshot it acts exactly as it did OOTB before.

Conclusion

Within this blog post I showed you easy it can be in general to implemented some missing feature in Sitecore XC. I showed how to start, where to look any how to hook in correctly at the specific locations, which need to be changed.

Within this special change we created a feature, which allows the editor to set additionally to the start date also an end date for price card snapshots to be even more flexible in creating complex pricing scenarios.

As always the full demo code can be found in a repository on my github and as always this code is not production ready and should be used used as an entry point or for demonstration reason.

https://github.com/Chris1415/Plugin.Sample.Pricing.Pricecards

Sitecore XC – Usage of Composer Templates vs. Entity Components

Sitecore XC – Usage of Composer Templates vs. Entity Components

This time I would like to share some thoughts on the topic of how to extend your commerce entites.

If you are already working with Sitecore XC you will most probably know, that commerce entities in general are extended via components. So if e.g. your sellable item entity needs more properties, like nutrients or allergies for food products you would just create a new component and “attach” it to the sellable item.

From version 9 on Sitecore introduced a new application Composer, with which it should be very easy to extend all kind of OOTB commerce entities. If you would like to know more about Composer in general, I would recommend you to read one of my articles about Composer. In general with this Composer application you can create new custom views with all kind of custom properties. You can then link that new view to any of OOTB entities like sellable item, customer, catalog, category etc. And if you now e.g. use Merchandise tool to see the sellable item and edit it, you will directly also recognize all the new custom views and properties created via Composer and linked to that entity. So without writing a single line of code you are able to completely customize and individualize all you entities and maintain them directly.

So the question at this point would be:

Why should you not use that fancy feature?

The answer of course is not so easy. Let us have a closer look at Composer and how to really work with it in a real world scenario.

Composer in real world

In one of my Sitecore XC projects, we were faced the task to extend standard sellable item with quiet a lot new properties. The version we started was at this time was 9.1.  And because of that, the first approach which came into my mind was to use Composer. I already knew about one disadvantage of using Composer, which I directly wanted to work around. If you create a new composer template within e.g. your local instance, it might work perfectly fine. But the trouble already starts, when you try, to bring that newly created composer template to other DEV instances, testing or production. There is currently no OOTB way of deploying such templates to other environments. You can just create these templates and link them to other entities. This would later on lead to massively different instances, which is not track- or maintainable anymore. Because of that, the community already thought about some workarounds to overcome that issue, so that compser templates are deployable again.

For my solution I was building, I decided to use Code First Approach. Once you created a new template, you would, as usual, check in this file into your repository, where it is getting versioned and shared among other DEVs instances and later on in release management also on other environments like TEST or PROD fully automated.

And at first everything went well so far. I was able to programmatically create all of my new custom views and link them correctly to my sellable item entities. I was also able see and edit these new views and properties in entity view. OK, to be 100% honest, I was able to create and maintain all of my custom views for sellable item entity. But what about variants of sellable items? You might now, that variants of sellable items are no entities. Variants themselves are handled as components, which extend standard sellable items. If your now try to extend properties of sellable item variants, instead of sellable item, you will quickly find out, that this is right now not possible at all. At the moment, you just can link your composer templates to entities.

2019-09-08 14_20_33-Test.png

This means, that you cannot use composer to extend sellable item variants. To extend sellable item variants, you have to use plain, “old” components and do it on your own.

Next step was now to import product data from some web service to Sitecore. And here the odyssey started. I struggled a lot with adding data to composer generated custom views, but because if some reasons. For some of my issues I also created Sitecore support ticket. And one of the ticket also pointed out to be a bug in the system. But let me explain in detail, so you don’t have to go through all of that on your own.

It all started with the question of, how to access programmatically composer generated custom views. Of course Sitecore XC offers calls for creating, editing and retrieving sellable items in general. Now, based on the assumption, we correctly created or retrieved our sellable item entity, where do we find our custom views, so we can edit them? unfortunately the answer is not that easy, so I just provide you some code, which I wrote for my case, which does the job.

2019-09-07 19_36_14-_new 5 - Notepad++

  1. Grab the sellable item
  2. Use GetEntityViewCommand to grab sellable items entity view
  3. Find the view you would like to edit
  4. Grab the EditView of that specific view
  5. Iterate through all the properties you want to edit and edit them
  6. Use DoActionCommand to save all the changes

As you can already see, such an approach is more complicated than you would usually edit a sellable item with components. In addition with more and more custom views you edit, the performance of the overall import process is getting worse and worse. And not only that. I encountered the strange behavior, that from time to time the properties were not correctly added or edited for the custom views. Some times it worked and some times it just did nothing.  But OK. For now I accepted that, and created a support ticket to be sure, it is not a bug or something like that.

And after implementing the basic code for importing everything, I started testing various scenarios like, edit existing item, create item and add data, delete the item and recreate it, and also delete composer template and recreate that, to be sure, that all these scenarios work in other environments without any problems. But while testing around, I encountered another strange behavior. The situation was, that I created a sellable item with custom views. I added some data to that item and filled the custom view. Now I wanted to delete the composer template, recreate it and import the data again to the sellable item. The problem now was, even after deleting the composer template, the filled custom views were still present on the sellable item. And even worse, after recreating the composer template again, the custom view was present on the sellable item twice. One time filled from earlier test and one time new fresh empty one. I was not able to remove the custom view, until I completely deleted the current sellable item and recreate it. After doing that, it again just had all the custom views just one time. Because that really was a strange issue, I also created a support ticket for that behavior.

Support Tickets with topic Compser

  • Out of support scope – Properly fill composer properties programmatically
  • 278078 – Sitecore XC: Composer generated views are displayed multiple times on sellable items

2019-07-21 16_40_32-.png

 

To be completely honest, I created some more support tickets, than these two. But all the other tickets had some other issues while implementing an importer. And of course in future blog post I will keep you informed about newly found and registered bugs. For now we just have a look at these two tickets about composer. The first one, was unfortunately out of scope as part of Sitecore support. The problem was, that basically the code works, but just did not add values from time to time. To resolve that issue, I was asked to directly contact  regional Sitecore representative to get help from the Professional Services team.

Let’s have a look in the meantime at the other issue. After some discussions the issue was registered as bug under the reference number 278078. So right now, you might get trouble when you use composer templates on your entities, fill them, delete the templates and recreate them. And right now there is no easy way of overcoming that issue, other than rewriting some really basic composer code.

So while struggling with all these kinds of issues, I was able to talk also with an architect from Sitecore. You remember, that this was the advice of Sitecore support I followed now. After a short discussion it pointed out, that composer might not be the best choice considering the current situation and how I use it.

And I have to admit, that I fully share that opinion after I really tried to integrate that new feature into the development workflow. It is still a quiet new feature with a few weaknesses, which have to be overcome first to unleash it’s full potential. But if we do not use Composer to extend all our sellable items, the question now is:

What can we use instead of using Composer?

Back to the roots – Why not using just components directly?

You really don’t have to use Composer to extend any kind of commerce entity. Before Composer was introduced, there was a pretty standard way, of how you can extend all kind of commerce entities on your own. You just created a new component, with all your properties you wanted the entity to have.

2019-09-08 14_27_39-Alnatura.Experience.Commerce - Microsoft Visual Studio (Administrator)

Sitecore also has some helper functionality OOTB, with which you can easily get, create and set custom components on entities to maintain your custom components.

2019-09-08 14_28_38-Alnatura.Experience.Commerce - Microsoft Visual Studio  (Administrator).png

2019-09-08 14_29_40-Alnatura.Experience.Commerce - Microsoft Visual Studio (Administrator)

In the end, after getting the component and setting your properties, you just have to persist the entity again to the database, and that’s it.

2019-09-08 14_30_20-Alnatura.Experience.Commerce - Microsoft Visual Studio (Administrator)

So for an importer process, it’s also nothing more, than this. Instead of finding custom, edit views, adding properties there and calling a magic DoActionCommand in the background for each view you changed, you just grab the sellable item, grab the component with the OOTB helper, set the properties and in the end, as usual, persist entity. And I guess this might be the plainest, easiest and most performant way of editing custom properties of your entities.

I already tested this approach with 8 custom components with more than 80 custom properties, which extended the standard sellable item entity, and the importer was definitely not that slowly, than it was, when using the composer based approach.

2019-09-08 13_12_51-Support.pptx - PowerPoint.png

2019-09-08 14_39_30-Alnatura.Experience.Commerce - Microsoft Visual Studio (Administrator)

But I would say, we have one big disadvantage of using this approach. When using Composer to create templates, these templates and respective the custom views, which can be seen in the screenshot above, are directly visible and editable on the linked entities. This benefit, we do not have, when creating and adding components directly to our entities. To see and edit the new properties of our entities, we have to implement some further logic, which extends the standard entity view, in our case the sellable item entity view, with all our new components. And with exact this way we also can extend our sellable item variants. If you would like to know more, about how to extend Business Tools, and in this case entity views to see and edit custom properties, I would strongly recommend you, to read this article of me, where I describe in detail the process with the example of creating and extending the cart entity view.

So of course this produces a bit more work to get everything working, but I guess at the moment, for this scenario, I was faced to, it is still the better approach, because in the end, if something does not work as expected, you can completely customize or work around everything.

You might now remember the code from the beginning, where I showed, how to edit custom view of sellable item. I will now show you, how the code changed now in importer.

2019-09-08 14_33_34-Alnatura.Experience.Commerce - Microsoft Visual Studio  (Administrator).png

So you see, that this piece of code definitely became much easier, than before. Instead of duzend of lines of code for preparation and retrieval it is more or less just one line of code for retrieval and X lines for X properties to change.

Conclusion

Within this article you learned, that there are various ways of extending Sitecore XC entities with custom properties. You saw, that the newly introduced Composer application might look cool and in general has a lot of potential to make the life of authors and developers much easier. But right at the moment you clearly have to weigh well, if Composer is the right tool for your business needs and requirements. If not, don’t be afraid of using plain, old components directly. It might lead to more work in the beginning, but in the end it might safe you a lot more time.

Sitecore XC 9.1 – Working programmatically with SellableItems might lead to some exceptions on saving changes

This time I would like to share some nasty bug, which is currently present in the newest version of Sitecore XC with which I wasted a lot of time.

The issue appears, when you start working programmatically  with SellableItems. In my scenario I wrote some Pipeline block, which was response for taking some product information, and import these to Sitecore. For that I did in general the following things.

  1. Try to create sellable item with CreateSellableItemCommand
  2. If the result was null (Most likely the sellable item already exists)
    1. Try to grab the existing sellable item with GetSellableItemCommand
  3. If the result was NOT null
    1. Just use that newly created sellable item
  4. Make some changes e.g. edit list price via ListPricingPolicy
  5. In the end save the changes by using EditSellableItemCommand

So what happened now was the following:

  • On the first run, when the item was created, everything worked perfectly fine and was saved
  • BUT on the second and any further run, I got some strange error back, like seen below and nothing was saved 2019-07-15 08_26_15-Postman.png

Initially I had not idea, why this happens, because at this place I did not understand, why EditSellableItem would try to insert a new sellableitem to Database.

Because of that, I decided to as Sitecore Support about that. The result was, that this behavior was recognized as Bug with the reference number 280784.

The root cause of the issue is, that once you use GetSellableItemCommand (Or more directly usage of GetSellableItemPipeline) the result sellable item contains the property “isPersisted = false”, which means, once you try to use EditSellableItem with such an instance of a sellable item, Sitecore tries to persist / create that sellable item in Database.

The hotfix for now is quiet simple. To grab a sellable item correctly with the correct property set, we now just have to use basic GetEntityPipeline, which is much more generic and designed to grab any kind of entity. But of course after the usage of that Pipeline we can just cast the result CommerceEntity to SellableItem and everything works now as expected with EditSellableItem in the end.

Also here thanks to Sitecore Support, which helped me to find a quick solution.

Sitecore XC 9.1 – Edit decimal values in Business Tools might lead to inconsistent values in non-English environments

While working with the newest version of Sitecore XC, I now encountered some strange behavior, while using Business Tools, which I would like to share with you.

The behavior was the following.

  1. I navigated to my Inventory set
  2. I chose a random sellable item
  3. I entered the Edit View to change some values
  4. I entered 1.69 USD

But after the screen reloaded, I saw that Sitecore did not save 1.69 USD, but 169 USD.

2019-07-17 12_38_16-C__Users_Chris_Downloads_DecimalErrorBusinessTools.swf - Internet Explorer2019-07-17 12_38_26-C__Users_Chris_Downloads_DecimalErrorBusinessTools.swf - Internet Explorer

So it was obvious, that there is something wrong with parsing decimal values. Because I knew a similiar behavior already on older versions of Sitecore XC, I decided to ask Sitecore Support about the issue.

The response was, that the Issue was registered as Bug under the reference number 276950.

The reason, why this happened in my instance was, that the used IIS Apppool User, which is  a Windows user, just had all his regional Windows settings set to German instead of English.

20190716_095150

The solution for me now was the following

  1. Log in with the Windows user, used by Sitecore XC APP Pool
  2. Open Control Panel
  3. Navigate to Regional Settings “Control Panel -> Clock Language and Region -> Region”
  4. Set the Format to English (USA)2019-07-17 12_47_33-Zeit und Region
  5. Opened the Administration Tab at the top and and ensured that the Format setting is now English instead of German20190716_095315

After I did that, I resetted IIS and now everything wokred perfectly fine as expected

Note: This behavior is present in ALL decimal fields of Business Tools.

A big thanks to Sitecore Support for the quick fix.