How your SXA site gets resolved?

I have been looking at the Sitecore SXA for quite a long time now. If you are not aware of Sitecore SXA – Visit here. Having worked on full software development life cycle and on different technologies, It always interests me to look something which connects Front-End technologies and Back-End technologies. SXA provides a great platform for the developers to be able to build site robustly, Manage the Themes, Manage the Media library assets etc.

If you are working/playing with SXA, you will be aware of SXA Site Manager. It displays all the sites created using the SXA and the default (website) site as well. When i checked the <sites> section of the Sitecore.config, i couldn’t find the entries for the sites created using SXA. And it is obvious as doing such will restart your IIS application pool. I was curious how site gets resolved as i have already used Multiple Site Manager module in past which follows the similar kind of approach. Let’s find it out.

How your SXA site gets resolved?

  • SXA follows the Helix principles, i was sure that Sitecore.XA.Foundation.Multisite is the first place to look after. You can find all the dlls and configs in respective folders, starting with Sitecore.XA.*.
  • Open Sitecore.XA.Foundation.Multisite.config. You will find the processor specific to SXA for resolving site which is replacing the default site resolver using patch. See below:

    00
    Sitecore.XA.Foundation.Multisite.config
  • I took a look at the Sitecore.XA.Foundation.Multisite.Pipelines.HttpRequest.SiteResolver but could not found much difference. It is using the same SiteContextFactory.GetSiteContext to resolve the site.

    01
    SXA Site Resolver
  • As i didn’t found much from SXA SiteResolver, We can assume it may be the SiteContextFactory which is responsible for this.
  • Thing i noticed from Sitecore.XA.Foundation.Multisite.config is that, It is using the SxaSiteProvider instead of default SiteProvider.
    05
    Default Site Provider

    06
    SXA Site Provider
  • I further tracked the SXA Site Provider. It is responsible to fetch all the sites created using a specific templates using SXA and adds it to SiteCollection.
    07
    Sxa Site Provider
    08
    InitializeSites Method

    09
    ParseSiteItem Method
  • Answer: When SiteContextFactory.GetSiteContext method is called from SxaSiteResolver, a SxaSiteProvider gets resolved in SiteManager and GetSites() method returns all the SXA sites by parsing the items located at /sitecore/content/[Tenant]/[Site]/Settings/Site Grouping/* based on template /sitecore/templates/Foundation/Experience Accelerator/Multisite/Site
    10

Conclusion

So, If you are using SXA and implementing the custom functionality/hook (For ex: Html Cache clearer hook) than make sure to check the Sitecore.XA related configs. It might be replacing the default functionality already.

Advertisements

Sitecore SPEAK 2.0 CRUD operation part 2 – List component & Query Datasource

In this part we will see the operations like Listing & Delete in a Speak application. What i am doing here? I first wanted to create a form to save the data. If so, visit the first part here https://pratiksatikunvar.wordpress.com/2017/08/30/sitecore-speak-2-0-crud-operation-part-1-form-component. We will walk through ListControl & QueryDataSource in detail to complete the exercise along with binding complex (DropLink) field.

Create a blank SPEAK application

We already seen how to create a speak page using the branch template DashboardPage for 2.0 version in previous blog post. Let’s follow the same steps and create a page under /sitecore/client/Your Apps/DemoApp We will call it Departments for our exercise.

Let’s quickly move towards working with ListControl & QueryDataSource to list all the departments created.

Add a ListControl component

  1. From the design layout, add new rendering. Search with ListControl and you will be able to see it as:
    00
  2. Set the Id property to ListDepartment for this example.
  3. In our example, we wanted to bind the department items created in repository in master database. For ex: /sitecore/content/Home/Repository/Departments. All items having Department Name field set to respective department name.
  4. Let’s use QueryDataSource to read all these departments. Open design layout of FormPage and add QueryDataSource component.
    10
  5. Properties which are most important in QueryDataSource are Database and Query. Database – Specifies the name of the database. You can use $context_database, $context_contentdatabase, or a literal name. Query – Specifies a Sitecore Query or a Sitecore Fast Query.
    11
    Specify master in Database and /sitecore/content/Home/Repository/Departments/* in Query as shown above.
  6. Now bind this data to the ListDepartment added above in DynamicData property
    01
  7. Now let’s visit the Departments speak page in browser and see how it looks like
    02
    No data? Let’s confirm by checking the Network tab. As QueryDataSource will call the item API to fetch the data03
    We are getting 3 items. Than why ListControl not showing anything. Let’s first define what we wanted to display in list. I wanted to display Id & Department Name. Let’s create the columns for each and let ListControl know.
  8. Create a folder under /DemoApp/Departments/PageSettings/ named Columns where we will add two columns. From Design Layout add new item and search with ColumnField and you will have a list of templates based on which you can create columns.
    05
  9. We will add columns of type ColumnFieldText.
    04
  10. Specify ColumnTitle & DataFieldName for both the columns.
    For Id column, set the DataFieldName to Id and
    For Name column, set the DataFieldName to Department Name.
    And specify the item Ids of both the columns in ColumnDefinitionItems property of ListControl separated by pipe(|).
    06
  11. I think we have done all the things to list the data in ListControl. Let’s just revisit the page to see if it’s working or not.
    07
    It’s not working. We can only see the header but no data. I checked browser console and found the below error.
    08
    I couldn’t get clear idea what is the real issue here. I tried to remove column Id and it started showing the Department Name. Than i realized that for standard fields like Id, Name, DisplayName we have to specify it in special manner.

    1. itemId (the item ID)
    2. itemName (the item name)
    3. $displayName (the display name)
    4. $database (name of the database the item belongs to)
    5. $language (the language of the item)
    6. $version (the version of the item)
    7. $templateName (the name of the template the item is based on)
    8. $templateId(the item ID of this template)
    9. $hasChildren (shows whether the item has child items or not)
    10. $path (the Sitecore path of the item)
    11. $url (the Sitecore URL of the item)
    12. $mediaurl (the Sitecore URL of the icon asset of the item)
    13. $icon (the Sitecore path of the icon of the item)

     

  12. So, i specified $itemId into the DataFieldName for Id column and everything worked fine.
    09
  13. As we know now that QueryDataSource uses item API to get the data, It returns all the data of the item. Which is sometime huge call if number of item we are getting is large. In this case Fields property of QueryDataSource comes handy. You can specify the name of fields you wanted to retrieve separated by pipe (|).
    10

Important: Showing complex fields

We got to see the departments listed (Yay). But consider a scenario if Department item what we are retrieving has a ComplexType field say SubDepartment of type DropLink which points to another Department item. When we get the data using QueryDataSource than we gets the ItemId (which is raw value) in SubDepartment field value but we want Name of that SubDepartment.

How to display information from that referenced item based on item id?

  1. Well that is really complex. I spent a good amount of time. But there isn’t a simpler way around ListControl & QueryDataSource/SearchDataSource. One option is to implement the EntityDataSource. Where you creates the controller based on ServiceApiController. Implement Action method. Retrieve the data in a way you want and return the EntityDataModel back. But that’s sounds like a lots of work.
  2. For a simple solution, we do have another option. Mostly we may like to show the Name of that referenced item into the list. So, if that is the requirement than we can easily get the DisplayName of the item referred based on ItemId. QueryDataSource has the property named Formatting. Where you can specify predefined rules. For ex: $convert_date_to_friendly_format: convert internal date format to localized format $send_localized_dates: send localized versions of all dates
    $convert_id_to_display_name: convert item IDs to the display names of the items
    You can enter multiple formats as a pipe-separated (“|”) list.
  3. $convert_id_to_display_name is what we needed. Specify this to the Formatting property. And now when we access the SubDepartment property in ColumnField, It will display DisplayName of that item instead of ItemId.
    11
    12

If we could also have more control over methods/events than we could achieve such solutions very easily. But unfortunately we do not have that luxury in Speak.

Delete a record

  1. We will required to add a Delete button to the ListControl in order to delete the record. From Design Layout, add the item of type FormFieldTemplate to the Columns folder we created. We will call it Action for this example.
  2. FormFieldTemplate is used when you wanted to specify the html yourself for the column. It has an important property called HtmlTemplate. Where we can specify the custom html for the column. In our case we will specify the anchor tag. We will specify onclick event of the anchor. We will also required to pass the Item Id to the javascript function. So, that we could delete that item. Note: Do not forget to specify item id of the Action item to ColumnDefinitionItems property of ListControl to make that visible in listing. So, our Action column’s HtmlTemplate will look something like
    13
    Where, deleteDepartment will be a JavaScript function in PageCode (Don’t know about PageCode? See previous blog post). You can freely use any fields from the retrieved items using QueryDataSource in HTML template.
  3. Final View
    14

I hope the tutorials were helpful and by referring these posts one can able to achieve Listing & Form page in Speak without any trouble.

Keep SPEAKing Sitecore!

Sitecore SPEAK 2.0 CRUD operation part 1 – Form component

I have worked on several Speak application through out different projects. But all used to be simple having date range and a submit button which upon clicking exports the data to excel format. But this time i had to create a little complex form having many form fields. There are many good blogs available. For ex: Speak for newbies by @mhwelander https://mhwelander.net/2014/06/27/speak-for-newbies-part-1-creating-a-new-application, Google map speak component by @gorhal https://visionsincode.wordpress.com/2015/08/06/make-a-google-map-speak-component-in-sitecore, and many more.

In Sitecore SPEAK 2.0 we do have a guidance dashboard at /sitecore/client/Business Component Library/version 2/Content/Guidance/Dashboard which lists all the Speak components and minimum useful properties (Yes, only minimum, not all). I was about to start with the normal approach as i followed earlier and mentioned in blog https://mhwelander.net/2014/07/03/speak-for-newbies-part-5-building-a-custom-form-3/ by generating layout using row/column and adding required components like textbox, datetime to the speak layout. But from guidance dashboard, I saw Forms section and thought to give it a try. In my surprise, I found it lot more aligned and proper way to implement a form in speak application. So, we will be seeing how to create a simple/complex form in Speak application using Form component.

Create a blank SPEAK application

  1. Create a folder under /sitecore/client/Your Apps with your application name (Of course not to forget in Core database). All the pages and resources related to your app will reside inside that folder. You can use Sitecore Rocks for this purpose. For this example we will call it DemoApp.
  2. Create a page for building a form. You can choose from default provided branch templates for v1 version.
    01
    For Speak 2.0, there isn’t any default branch template available. But one of community member LukasSkowronski has created such and you can get it from https://marketplace.sitecore.net/Modules/S/SPEAK_20_Branches.aspx. After installing the above module, you will find a DashboardPage branch template for v2 as well. Go ahead and create a page using that branch template in our DemoApp folder. In our case we will call it FormPage.
    02
  3. When you see the design layout (right click on page -> commandy -> Design Layout), It will look something like this
    03
  4. Let’s view our application’s form page into browser from http://{Host}/sitecore/client/Your Apps/DemoApp/FormPage
    04
    Select UseFullWidth checkbox from FormPage item to view it in full width. Set the required property/field like Browser Title etc.
  5. We are ready to move to something complex (Yes. Form). We are not getting in detail for basics like PageCode, Navigation, Breadcrumb etc.

Add a Form component

  1. From the design layout, add new rendering. Search with form and you will be able to see Form component as:
    05
  2. Set the Id property to DemoForm for this example. CellAttributes, LayoutType and UseCellBottomPadding these are the properties to make change in layout of the form. See {Host}/sitecore/client/Business Component Library/version 2/Content/Guidance/Dashboard?componentId={59E2A66D-11D2-488D-A3BC-6C1C81326645}&menuItemId={83C20D87-4958-4A29-89FD-1D6BF41D6BFB} for more information.
  3. Create a folder under /FormPage/PageSettings/ called FormElements. We will be adding all the form elements inside the folder. Select the Item Id of that folder and specify it to StaticData property of Form component as shown
    06
    With this, Form component will able to know from where to pick form elements.
  4. Now, lets start adding fields to form. For demo purpose we will be adding one Simple (Textbox) another Complex(Dropdown with Dynamic Data).
  5. Right click on the FormElements folder, add new item, search with Form. You can add all that item having Form Parameters. For ex: FormImage Parameters, FormTextbox Parameters etc.
    07
    We will first select the FormTextBox Parameters. We will name it SimpleType for this example.
  6. Open newly created form element. You will find few properties useful. Set those properties and visit the FormPage again so you will have the idea of which property is being used where.
    08
    09
  7. Now add the another form element of type FormDropList Parameters (Complex). Lets name it Department. What’s complex here? You can provide either static data or dynamic data to the DropList. In static data, you creates the items based on specific parameters in Core database and select root item in StaticData property. While in DynamicData, you’ll have lots of option. For ex: SearchDataSource, QueryDatasource, EntityDataSource etc. Where all these DataSource gets the required data for you and you’ll bind those data to DropList. We will see DynamicData in this example. Select the HelpText and FormLabel properties and leave all data related properties blank for now.
  8. In our example, we wanted to bind the department items created in repository in master database. For ex: /sitecore/content/Home/Repository/Departments. All items having Department Name field set to respective department name.
  9. Let’s use QueryDataSource to read all these departments. Open design layout of FormPage and add QueryDataSource component.
    10
  10. Properties which are most important in QueryDataSource are Database and Query. Database – Specifies the name of the database. You can use $context_database, $context_contentdatabase, or a literal name. Query – Specifies a Sitecore Query or a Sitecore Fast Query.
    11
    Specify master in Database and /sitecore/content/Home/Repository/Departments/* in Query as shown above.
  11. Now we have data available to bind to DropList through QueryDataSource. To bind this data to DropList, specify properties like DynamicData, ValueFieldName, and DisplayFieldName to the DropList element we created.
    12
    DynamicData –  will ensure from where to pic data. In our case it is the items of the QueryDataSource. DisplayFieldName – Name of the field you wanted to display as DropList option text from the Department item. ValueFieldName – Name of the field you wanted to display as DropList option value ($itemId –  what is that? We will see in next blog post). Once done, visit the formpage and you will find the DropList is now filled with the Departments.
    13
  12. As we have added both Simple and Complex form elements into form, let’s add a button to save the data. Add item of type Button Parameters of 2.0 version into FormElements folder where we have added rest of the two elements above.
    14
    Specify the Id and the relevant Text. Specify the name of the JavaScript function you wanted to call on click of the button to save the data in Click property. We will see about that below.
    We are now done with the configuration. Now we need to write some code to save the data. Let’s do that.

Add a PageCode

Easiest way to write the custom code in the Speak application is to create a PageCode (JavaScript) file and refer it to the speak page (in our case FormPage). Let’s perform this step by step.

  1. First thing first. Create a stand alone MVC project as we do not directly work with Sitecore website folder as per standards. You can create empty projects based on Helix structure in VS using the extension https://marketplace.visualstudio.com/items?itemName=AndersLaublaubplusco.SitecoreHelixVisualStudioTemplates by @AndersLaub
  2. Create a folder structure to add JavaScript file inside /sitecore/shell/client as shown
    15
  3. Right click DemoApp, Add new item of type PageCode as shown
    16
    Note: Please ignore that all options showing two times.
  4. Publish the JavaScript file to website folder.
  5. Now, file is present there in the website folder but we will require to map it to the Speak Page. You can do that by specifying path of the JavaScript file in PageCodeScriptFileName property of PageCode component as shown
    17
  6. Now, add a JavaScript function which we have specified in Click property of Submit button form element.
    define(["sitecore"], function (Sitecore) {
      var SaveDepartment = Sitecore.Definitions.App.extend({
          initialized: function () {
              var id = this.getID("departmentId");
              if (id != null) {
                  this.getFormValue(id);
              }
          },
          getID: function (param) {
              var id = Sitecore.Helpers.url.getQueryParameters(window.location.href)[param];
              if (Sitecore.Helpers.id.isId(id)) {
                  return id;
              }
          },
          getFormValue: function (id) {
              var app = this;
    
              jQuery.ajax({
                  type: "GET",
                  dataType: "json",
                  url: "/api/sitecore/Controller/Action",
                  data: { 'departmentId': id },
                  cache: false,
                  success: function (data) {
                      if (data != null) {
                          app.DemoForm.Email.Value = data.Email;
                          app.DemoForm.Department.Value = data.DepartmentId;
                      }
                  },
                  error: function () {
                      console.log("There was an error. Try again please!");
                  }
              });
          },
          saveFormValue: function () {
              var app = this;
              var id = app.getID("departmentId");
    
              var formData = {
                  Email: app.DemoForm.Email.Value,
                  Department: app.DemoForm.Department.Value,
                  DepartmentId: id
              };
    
              jQuery.ajax({
                  type: "POST",
                  url: "/api/sitecore/Controller/Action",
                  data: { "formData": JSON.stringify(formData) },
                  success: function (success) {
                      //Do something
                  },
                  error: function () {
                      console.log("There was an error. Try again please!");
                  }
              });
    
          }
      });
    
      return SaveDepartment;
    });
    
  7. Important thing to note is how you can access the form elements. You can access it using app.{FormElementId}.{ElementId}.value. In our case if we wanted to access the Email element of form DemoForm than we can do it as app.DemoForm.Email.value. Make sure that you specify the Id field of each element and you can access the element using that Id not by name of the element item. Also there are other methods related to form specified in guidance dashboard mentioned in the beginning. Those are getFormData() & setFormData(). Howevwer, I couldn’t make it working. Feel free to play around that.

Finally. We have been able to create a complex form and able to perform operations like Insert/Update. In the coming post, we will be seeing the List & Delete operations.

SPEAK Sitecore until.

Different way of controller rendering in Sitecore. Differences & Doubts

I recently downloaded the latest version of Sitecore which is 8.2.X. And when i was playing with default vanilla instance, i met few things related to controller rendering new which led me dig into it. So, here i am sharing my experience with controller rendering in Sitecore. I am not sure if that is the case with everyone or i interpreted few things wrong. Intention for writing this is to spread my view as well have opinion of community experts stating what’s true and what’s not.

Doubts

After installing Sitecore 8.2 vanilla version, i found that there is a folder inside /sitecore/layout/ named Controllers just like we had models.

000It was present there since some previous versions. Not exactly sure from which version and why. So, i tried to figured out how to use it.

  1. As we can see there are only two fields which is Controller Name and Action Name which we generally comes with Controller Rendering. So, first thought comes in mid if there is some separation of these two fields from controller rendering. But that isn’t a case. We can see both fields present in the Controller Rendering.
  2. For models we creates a model in /sitecore/layout/models folder and link it to view rendering with the help of model field present in view rendering Similar way i tried to check if controller rendering has such field or not (No sense to have it in View rendering at all, neither to have it in controller rendering. But checked if there is some mystery) but couldn’t find.
  3. I than tried to find such thing in layout (again doesn’t make sense, but checked once) but couldn’t found any link.
  4. I also tried to add it to presentation details (taught if can be used in similar way of controller rendering) but couldn’t add any item rather than renderings.

So, it’s still doubtful thing for me, as i couldn’t use it anyway. Anyone got any more idea on this? come forward and share the secret.

Another thing which i specifically found in sitecore version 8.2.X is that sitecore helper also have a new method called ControllerRendering similar to ViewRendering which was there along with Rendering method. In prior than 8.2.X versions, we already had Controller method. So, now in 8.2 onward, we have two methods specifically related to controller. I tried to figure out difference between these two and below is my conclusion.

Differences

I setup one MVC project for my POC website. than i added two areas into that one called SiteA and another SiteB. Both area were having same structure, having one controller named Home, one action inside controller named Index, and a view called Index.

001

I also created one MVC layout and two renderings to load the index action from home controllers. one for SiteA area and another for SiteB area.

002003

All set with the configuration and prep work. let’s use each methods one by one and note the findings.

Controller
I added below markup in the layout.
004
Output was expected. With area and controllers with same name exists, it was going to raise an error saying found two controller for the request.
005
Without area and having unique controller will work fine with this method.
Note that this can be resolved by adding the custom routes to the route table. but we intent to check default behavior here.

Using Controller method and without writing custom pipeline to add custom routes, It won’t be able to resolve Area.

Using Controller method, you are not calling any renderings. It directly instantiate the controller and invokes it. It won’t obey neither mvc.renderRendering nor mvc.getRenderer pipelines. So, you can’t use benefit of caching the html output either.

Rendering
Now, i replaced layout with below markup.
006

Using this method, you can render any type of rendering, be it View Rendering or Controller Rendering. You just require to pass the path or id of the rendering item. We are dealing with the rendering items and with having specified Area name in both the controller rendering, expected output is that it should resolve the area. And it does.
007
It will run the mvc.renderRendering pipeline. Where Area will be resolved by RenderingDefinitionAreaResolveStrategy. Also, as we are directly refering rendering items, we do have specifications for caching and Html caching feature will also work properly.
008.png

009
Only thing is that it will call mvc.getRenderer pipeline but won’t be able to resolve the type of rendering which is RenderingType. And will end up being resolved by GetDefaultRenderer. Unless you are using RenderingType property to determine which type of rendering it is, It is likely to solve the purpose.

Controller Rendering
Sitecore 8.2+ introduces this additional helper method. In the release note, you will find that this is included for better handling controller rendering.  I replaced layout with below markup
010
with the expectation that both the method should resolve correctly. But i ended up with similar error as Controller method for Controller Rendering.
005
As Controller Rendering won’t instantiate controller directly, It will resolve the renderer and likely to run mvc.getRenderer and mvc.renderRendering pipelines. I was expecting it to work as Rendering method. But as we are not referring rendering items directly and we aren’t specifying anything related to area so it also make sense that it couldn’t resolve area. I than tried to specify the area in the layout itself.
011
With the hope that now, it should resolve the area with the help of RenderingLayoutAreaResolveStrategy. But it didn’t. If you dig into this strategy than it checks if RenderingType is Layout than get layout and read value from area field. In our case using Controller Rendering method and mvc.getRenderer pipeline, GetControllerRenderer will resolve it as RenderingType Controller. Adding custom area resolve strategy may solve the issue. So, that’s one possibility to resolve area where it’s even not possible in Controller method.

I was hoping that Html Caching should work but by not referring rendering item directly, we do not have values of renderingargs. So, i really wonder why we would use this method against Rendering method? Anyone have answer, Let’s share.
giphy (1).gif

Basically, i do not have any conclusion at the end of this post. But i wanted to share what i ended up experiencing. And wanted to know the experience of community experts on this topic. so that we could have better understanding of the difference between above methods.

Simple. Not Easy.

giphy

 

Simple. Not easy – Copy/Move Children – Content Editor

Today i thought to write the first blog in “Simple. Not easy” series. It may seem very basic for the Sitecore experts but i personally found it so much helpful so the Content Editors will be.

Why Copy/Move Children is  really helpful?

Generally Content Editor comes up with full loaded utility commands like Copy, Move, Delete, Delete Sub Items, Duplicate etc. But while working with one of the migration task in a project, I ran into a situation where i was required to copy all child items of particular item into another location. For ex: /sitecore/content/home1 has 50 child items and i need to move it to something /sitecore/content/global/pages. Now only option i find is to copy individual items from /home1 to /pages.

That is a very tedious task. For developers, there might be good options to do it Programmatically or by using Powershell script. But if content editor needs to perform these steps than it is a good idea to create a custom command CopyChildrenTo/MoveChildrenTo similar of Delete Sub Items. What you need to do is extract the code for copyto and moveto and apply the simple logic to copy children instead of selected item.

Create a command

Copy Children

using Sitecore.Data.Items;
using Sitecore.Diagnostics;
using Sitecore.Shell.Framework.Commands;
using System;
using System.Collections.Generic;

namespace Demo.POC.Extension
{
    [Serializable]
    public class CopyChildrenTo : Command
    {
        ///
<summary>Executes the command in the specified context.</summary>

        /// <param name="context">The context.</param>
        public override void Execute(CommandContext context)
        {
            CopyChildren(context.Items);
        }

        ///
<summary>Queries the state of the command.</summary>

        /// <param name="context">The context.</param>
        /// <returns>The state of the command.</returns>
        public override CommandState QueryState(CommandContext context)
        {
            Error.AssertObject((object)context, "context");
            if (context.Items.Length != 1)
                return CommandState.Disabled;
            Item obj = context.Items[0];
            if (obj.Appearance.ReadOnly || !obj.Access.CanRead() || !context.Items[0].Access.CanWriteLanguage())
                return CommandState.Disabled;
            return base.QueryState(context);
        }

        ///
<summary>Copy children.</summary>

        /// <param name="items">The items.</param>
        /// <param name="message">The message.</param>
        public static void CopyChildren(Item[] items)
        {
            Assert.ArgumentNotNull((object)items, "items");
            if (items.Length == 0)
                return;
            List<Item> objList = new List<Item>();
            foreach (Item obj in items)
            {
                objList.AddRange((IEnumerable<Item>)obj.Children.ToArray());
            }
            Sitecore.Shell.Framework.Items.CopyTo(objList.ToArray());
        }
    }
}

Move Children

using Sitecore.Data.Items;
using Sitecore.Diagnostics;
using Sitecore.Shell.Framework.Commands;
using System;
using System.Collections.Generic;

namespace Demo.POC.Extension
{
    [Serializable]
    public class MoveChildrenTo : Command
    {
        ///
<summary>Executes the command in the specified context.</summary>

        /// <param name="context">The context.</param>
        public override void Execute(CommandContext context)
        {
            MoveChildren(context.Items);
        }

        ///
<summary>Queries the state of the command.</summary>

        /// <param name="context">The context.</param>
        /// <returns>The state of the command.</returns>
        public override CommandState QueryState(CommandContext context)
        {
            Error.AssertObject((object)context, "context");
            if (context.Items.Length != 1)
                return CommandState.Disabled;
            Item obj = context.Items[0];
            if (obj.Appearance.ReadOnly || !obj.Access.CanRead() || !context.Items[0].Access.CanWriteLanguage())
                return CommandState.Disabled;
            return base.QueryState(context);
        }

        ///
<summary>Move children.</summary>

        /// <param name="items">The items.</param>
        public static void MoveChildren(Item[] items)
        {
            Assert.ArgumentNotNull((object)items, "items");
            if (items.Length == 0)
                return;
            List<Item> objList = new List<Item>();
            foreach (Item obj in items)
            {
                objList.AddRange((IEnumerable<Item>)obj.Children.ToArray());
            }
            Sitecore.Shell.Framework.Items.MoveTo(objList.ToArray());
        }
    }
}

Config patch
Create a custom config patch file to include these new commands as shown below. Copy this config to anywhere in the website/App_Config/Include folder.

<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
  <sitecore>
    <commands>
      <command  patch:after="*[@name=copyto]" name="item:copychildrento" type="Demo.POC.Extension.CopyChildrenTo,Demo.POC.Extension" />
      <command  patch:after="*[@name=moveto]" name="item:movechildrento" type="Demo.POC.Extension.MoveChildrenTo,Demo.POC.Extension" />
    </commands>
  </sitecore>
</configuration>

Context Menu Item
Create a Context Menu items for both the commands as shown in below image in Core database under /sitecore/content/Applications/Content Editor/Context Menues/Default/Copying.

Copychildren-1

Copychildren-2

In Action

Copychildren-5

Copychildren-6

Any content editor there, Did you find this helpful? Or share other such issues you face in day to day activity.

Sitecore Helix – Converting existing Sitecore solution into Helix standards

Helix is a set of overall design principles and conventions for Sitecore development. With the evolution of Sitecore itself and large enterprise solutions growing as per company’s business, there is a requirement to define a standard which simplifies the Sitecore development as well maintenance.

Helix is most buzzed word you will hear nowadays. Most of the Sitecore solutions provider has adopted this standard principle while delivering new and all upcoming Sitecore Web Applications. It is little hard to move from the traditional development (vary by person to person) to Helix standards. But once you are familiar with the terms/Standards, Believe me – You will likely love it. There is a well written documentation on  Helix, Habitat – An example solution based on Helix standards which you can refer as example of Helix, And there are many courses/presentation going on Helix.

We talked about how Helix is changing the whole way we develop the Sitecore web application. What about websites already build on Sitecore before we even heard about Helix? I recently got a chance to work on an existing website build on sitecore to make required changes so that solution become more maintainable and as per new standards for future development. I considered one of the thing to reach our goal is to convert it to Helix standards. Based on my experience doing this, We will be talking about

  • Should we convert existing websites to Helix standards?
    • No, What are the reasons for not doing?
    • Yes, How we can do that?

Should we convert existing websites to Helix Standards?

No, Unless you are willing to convert whole application into Helix standards. which generally does not seems to be possible. You will ask why?, Let’s see what are the reasons of not converting existing websites to Helix standards

What are the reasons for not doing?

Although, Helix gives many benefits, I found below points which were stopping me to perform this conversion into Helix standards:

  • Limited Business Context:
    instead-of-i-dont-know
    In a large organization, where an application gets growing over several years of span time, It is very difficult to find out the person who has the complete business context. It is very difficult to understand the business context from application from mid way, we might not know the actual reasons for some of the implementations. The biggest risk of the limited business context is, while conversion we may break the functionalities unknowingly. For ex: Miss some of the code while conversion, Miss some of the references, Miss some of the hard coded IDs & Paths, Miss some Datasource related changes in Sitecore Items due to new Structure/Items, We cleanup some of the unwanted things which is there for future development etc.
  • Limited Time:
    your-time-is-limited-so-dont-waste-it-living-someones-life-steve-jobs-1-728
    As website is already developed and serving business need, we might not get the time as much as we develop a new website. Converting existing web application to Helix standards requires huge amount of time as much as new development from scratch we can say. So, with the limited time duration, we might end up doing mix of traditional and Helix standards. Which is not a good solution from the eye of a good solution architect.
  • Limited Knowledge of Helix:
    quote-integrity-without-knowledge-is-weak-and-useless-and-knowledge-without-integrity-is-dangerous-and-samuel-johnson-95971While working along with different set of people in different teams (In house team, Consultant team etc.), It is very difficult to set the rules and expectations. Although, there are set of rules and recommendations mentioned in Helix standards, One may act differently. For ex: One developer created Foundation for few set of feature, few will create Feature for same, others may argue that it should be in Project and rest just doesn’t follow Helix standards and place everything except Feature/Foundation/Project. This will again end up in duplicate, inconsistent, difficult to understand code/structure.
  • Not adding business value:
    cartoon-why_vision_is_imp
    Spending so much time, money, and efforts and at the end not getting direct business value might not impress to many business people. And i think it is right too at some point of time. Q: What business value it will add? Ans: More development in standard way, Less efforts and time  going forward, and maintainability. Q: What business value it will add right now? Ans: can’t think off.

These are the several factors to keep in mind before jumping in converting everything into Helix standards. But if knowing all these points, we really wanted to convert the existing Sitecore website eventually into Helix standards, we can do in below way.

How we can do that?

Considering fact that we can not start developing existing websites in Helix standards along side existing website. It will than become a development from scratch which is going to take many months, and with this separate development to convert existing website to Helix standard, there will also be some modification and new feature in existing website. Merging these new feature along way with new development is not going to be an easy job.

The approach we can take:

  • Create a blank structure as per Helix standards. https://www.npmjs.com/package/generator-helix. It is now also available as Visual Studio template https://github.com/LaubPlusCo/LaubPlusCo.Helix.VsTemplates
  • Add one empty project application which can act as a heart. No need to jump to Feature and Foundation at this stage.
  • Create a Foundation project named Legacy. Why Foundation and not Feature/Project layer for this purpose?

    Ans: The reason why I’ve put it into Foundation layer is because we can also start implementing new features etc. but we need to make sure that the “old” project still works. So basically we have the Vanila Sitecore instance at the bottom, on top there is the old project and on top of that we can implement new stuff and/or move stuff out of the old project Also one point why it’s not in the Project layer is because, of the references. If you convert part of it into Feature Layer, you cannot have a reference to the Project Layer. But you can have one to the Foundation Layer. Thanks to @nadinelendzian for discussion on this.

  • Put everything from old solution under this Legacy Foundation project.
  • Make sure at this point everything is working fine as it was.
  • Eventually start separating out functionality into different Feature/Foundation/Project layer.

Please find below images as an example:

Before Helix

Sitecore Content Tree

old-1
Content
old-2.1
Layouts
old-2
Renderings
old-3
Templates

Visual Studio Solution
NonHelixVS

After Helix

Sitecore Content Tree

new-1
Renderings
new-2
Layouts
new-3
Templates

Visual Studio Solution
HelixVS

These are some of the example of how an existing solution can be converted to Helix standards gradually.

Again it is my personal view, If you have some other thoughts on converting existing Sitecore websites to Helix standards, I would love to hear that.

I love Helix 🙂

 

Sitecore xDB Cloud 2.0 – Using RestAPI for xDB Cloud Service to solve many purpose

In previous posts, we discussed what is xDB Cloud, Advantages/Disadvantages, Useful Terminologies, How to configure etc. In disadvantages, we seen that we could not connect xDB Cloud directly using tool like Robomongo and MongoVUE. Limiting the action we can perform on MongoDB over On-Premise setup. To overcome this, Sitecore has come up with xDB Cloud RestAPI, not strong enough but maturing steadily. Using which you can perform different operations.

Let’s understand each methods with an example. I use Postman for such purpose. It is a tool build on top of Chrome with lots of cool feature.

You must use a valid authentication token whenever you make a call to the xDB Cloud API. Which can be generated by using a valid Sitecore license file to call the SSO Encode Sitecore License endpoint. You must include the generated token as a HTTP header in all other requests called X-ScS-Nexus-Auth

https://gateway-sso-scs.cloud.sitecore.net/api/License/Encode/

E2k5QvJ

This is the first step you need to perform as all other endpoint requires X-ScS-Nexus-Auth for authentication.

Once you have obtained the token, first thing you wish want to get is list of xDB sets. In response you will get all xDB set listed and DeploymentId for each. Once you have noted LicenseId and DeploymentId, you will be able to make API calls to get information specific to xDB set (DeploymentId). This endpoint becomes very handy when you haven’t received DeploymentId(s) from Sitecore Support.

https://gateway-xdb-scs.cloud.sitecore.net/api/xdb/{licenseId}

uXEw7IJ

Once you have obtained list of xDB sets, you will wish to get the Connection Strings for one of the xDB set (DeploymentId) as it is a vital part in configuring the xDB Cloud. This endpoint becomes very useful when you haven’t received any information about xDB Cloud like Connection Strings, ReportingService from Sitecore Support. With this method in place, you will be able to get all the information required for your setup.

https://gateway-xdb-scs.cloud.sitecore.net/api/xdb/connectionstrings/{licenseId}/{deploymentId}

FXVAO8G

This is also one of the important thing to successfully complete the xDB Cloud setup. Even though you have done all configuration right, but your infrastructure not configured properly, it won’t allow application to connect to MongoDB. Hence, no data will be written to xDB Cloud. Use this endpoint to get all URLs and ports specific to URL. And you have to enable the outbound connections over given ports in Firewall.

https://gateway-xdb-scs.cloud.sitecore.net/api/xdb/firewallsettings/{licenseId}/{deploymentId}?v=2

BUjwk2w

You can utilize this endpoint as a tool to verify weather data is getting stored in xDB Cloud or not. By providing year and month in endpoint URL, you will get informations like Total Interactions, Interactions Added, Total Contacts, Contacts Added etc. per day basis.

https://gateway-xdb-scs.cloud.sitecore.net/api/xdb/Consumption/{licenseId}/{deploymentId}/{year}/{month}

WFn5eJ8

This endpoint also helps like above one to verify weather data is getting stored to xDB Cloud or not by retrieving collections. Collections includes Interactions as well Contacts.

https://gateway-xdb-scs.cloud.sitecore.net/api/xdb/collection/{licenseId}/{deploymentId}

J3p47VZ

This endpoint is useful to get information about xDB set (DeploymentId) such as Sitecore Version (Not sure why it is there), xDB Cloud Version (1.0/2.0), And Deployment Type (Prod/Non Prod).

https://gateway-xdb-scs.cloud.sitecore.net/api/xdb/version/{licenseId}/{deploymentId}

5hVNcsw

This endpoint will be used to ensure xDB Set (DeploymentId) working well or not. This will return Status, Message, and IssueIdOnError. You will find the message if there is any issue with xDB Set. Make a note of IssueIdOnError if you get that in response because you need to provide it to Sitecore Support team when you contact them about the issue with your xDB Set.

https://gateway-xdb-scs.cloud.sitecore.net/api/xdb/{licenseId}/{deploymentId}/status

cVGxtqE

This is a very useful endpoint which will be used to rebuild the Reporting database. Make note that you won’t be able to rebuild the reporting database using admin page in case of xDB Cloud. This is the method which will do the work for you. When calling this method, it should return “In Process” as response. That means rebuild of reporting database for that specific xDB Set has been started.

https://gateway-xdb-scs.cloud.sitecore.net/api/xdb/historyProcessing/{licenseId}/{deploymentId}

DP1Z09E

Get history processing status

Once you have triggered the rebuild Reporting database with help of above method and received response as “In Progress”, you will want to know the status of that task to determine weather it got completed successfully or encountered with an error. By triggering this same API as above again, you will get status of that operation in response. Possible values are Done, In Process, Error, and None.

https://gateway-xdb-scs.cloud.sitecore.net/api/xdb/historyProcessing/{licenseId}/{deploymentId}

L94HZxR

So, that’s it from the xDB Cloud 2.0 series. Aim was to provide everything at a single point from understanding to Configuration, troubleshooting etc. so that it can save a couple of days for someone.

Enjoy xDB Cloud.