Authorsandeeppote

Different approaches of creating Sitecore SXA themes

Themes define the look and feel of a site and makes it flexible to change the layout and design of the website.

Themes help to customize the appearance of the site which includes layout, typography, color and other design elements.

SXA come with two types of themes- Site and Base themes. To add own/custom classes and assets, such as styles, scripts, images and fonts use Site theme.

There are multiple ways site theme cane be created-

Option 1 – Add custom theme when creating a Site

Check out this blog post for adding a theme when creating a site

Option 2 – Add theme to existing Site (create theme manually)

Right click on your site- click Scripts and click New Site Theme option

Provide the theme name and location.

Click OK and a theme should be created on specified location

Option 3 – Add a theme using SXA CLI

Will add the details shortly.

Hope this helps!

Sitecore 10 SXA Site Structure

Previous blog shows how to create Tenant and SXA Site.

In this blog lets see what does the installation script adds to the SXA site.

Following is the site content structure-

1. Site

SXA site is a container to the content that will be used as a output of the site. Site contains the settings to select the Site Media Library, Theme Folder and Modules.

2. Home Page

This is the home page of the site. All other pages in the site must be stored under the Home item.

3. Media Folder

Media Folder helps scope the part of media library is available to content editors on the images selection dialog.

You can change the scope by adding or removing the folder in “Virtual” section “Additional Children” field.

Media Folder “Additional Children” field
Scoped item in media folder from Media Library
Scoped to the selected folders configured in “Additional Children” field

Best Practice – Do not put media items directly under the Media folder. Form SXA 1.7 and higher uploading items to media folder in the Site is not allowed.

4. Data Folder

Data Folder is the repository for storing all the data sources. These data sources can be reused across many pages scoped inside the Site. Data folder had component type folder and can be created manually or when the module is installed.

Data for each component can be created manually from the content tree or from experience editor by using the “Associated Content” option. Data folder is used as a source configured in rendering’s Data Source field in a form of query or directly mapped to the component folder.

Best Practice – Clean up unused data sources

Best Practice – Give Site data sources meaningful names

Best Practice – Organize site data sources in folders

Best Practice –Run source field reports to help set the data source context

5. Presentation

The presentation folder contains all the presentation related details and settings for the components selected while creating the site.

Presentation folder has list of components based on the modules selected while creating the site.

Presentation folder contains Page and Partial Designs, Layout Service , Available Renderings, Rendering Variants and Styles.

Rendering variant contains list of components on the site and can be customized using Variant Definition and Variant Fields. Also can use template based Variant like Scriban and Template

6. Settings

Settings folder contains site specific configuration. Site Grouping contains the Site Settings like site name, host name, database etc.

Settings also contains the Redirects, HTML snippets and Item Queries. Settings Folder contains options to select the Fav icon, error handling and other SEO related settings.

Sitecore 10 SXA-Create a tenant and Site

Tenant Folder

Sitecore supports multitenancy, which means you can have multiple sites running on a single Sitecore instance.

Tenant folder is just a container to hold multiple tenants you may have as a part of site structure. Inherited from _Base Tenant Folder. You may create a tenant folder to hold the multiple tenants of a Company.

A folder with provide tenant folder name is create here – /sitecore/templates/Project/<Tenant Folder Name>

Template Path – /sitecore/templates/Foundation/Experience Accelerator/Multisite/Tenant Folder

Tenant

Tenant is a top-level container for the Sites underneath. Site in same tenant are related, that means they are able to share data and layouts. Creation of tenants comes with optional modules.

Template/sitecore/templates/Project/<<Tenant Folder>>/<<Tenant>>/Tenant

Tenant been created successfully.

Creating Site

Site is a collection of content and output with a common overall business objective sharing a common set of assets

To create site right click on Tenant and select an option to create Site or Site Folder

Site Folder –

Site folder is a container for multiple sites.

Template – /sitecore/templates/Foundation/Experience Accelerator/Multisite/Site Folder

Site

General tab- Provide Site name, host name and Virtual folder. You may keep this as default and change later based on the requirements.

Select the required modules as a part of Site creation.

Create a new theme or select existing. This will e your site theme and can be changed from Page Design –

Template – /sitecore/content/<<tenant folder>>/<<tenant>>/<<site folder>>/<<site>>/Presentation/Page Designs

Select a grid mainly Bootstrap 4

At this point we have SXA site been created-

Remove Site

To remove Site, right click on site, select scripts and Remove Site option.

Sitecore Technology MVP 2021

Voluntarily contributing your time, energy and skills to the community and help customers succeed and be a part of their growth is all that matters. I believe going above and beyond to achieve expertise in whatever you are doing and giving back to community however small it may be is the key to grow together and when these efforts are recognized it inspires the community to continue their good work.

Happy to share that I have been recognized as 2021 Sitecore MVP.

Sitecore recognizes professionals who deliver outstanding customer experiences through shared expertise on Sitecore’s products, the 2021 MVP program draws from a community of 12,000 certified developers and over 20,000 active participants. This year’s 284 MVPs contributed invaluable knowledge to the community in 2020 and demonstrated true mastery of the Sitecore platform to support partners, customers and prospects.

Sitecore Commerce 10 – code breaking changes need to consider while migrating from older version

Sitecore Commerce 10

Sitecore Commerce supports integration to the third-part system and customization and extension to the OOTB entities. This can be achieved by custom plugins.

If you are migrating your code from XC 9.x version to XC 10 you will have to update the code to newest API’s provided with XC. Following is the list of breaking changes if migrating from older versions or good to know if you are starting with the new XC 10 solution.

  1. Wrappers to PipelineBlock

Commerce Engine uses pipeline framework to support extensibility. Pipelines act as a containers for business logic. Commerce pipeline consists of a block which has a detailed business logic.

With Sitecore 10 PipelineBlock are now wrapped with AsyncPipeline and SyncPipeline. So if you have your code using PipelineBlock it should be using Run method to execute the block you may have injected to pipeline.

AsyncPipelineBlock

If block needs to be executed Asynchronously use AsyncPipelineBlock. Also the method name changes to RunAsync()

SyncPipelineBlock

If block needs to be executed Synchronously use SyncPipelineBlock. The method name used to execute block is Run()

ConfigureServiceApiBlock also now uses SyncPipelineBlock

2. IPipeline RunAsync() method

IPipeline interface method is changed from Run to RunAsync() which now makes sense as the method is asynchronous operation.

So where are the changes you might need to make, some of the pipelines that is used frequently and need change are listed below-

  1. IFindEntityPipeline
  2. IFindEntitiesInListPipeline
  3. IFindEntitiesPipeline
  4. IPersistEntityPipeline
  5. Any custom pipeline and list goes on…

These are few of the breaking changes. There are more and I shall keep updating.

Install Sitecore 10 Update 1 using Install Assistant

Sitecore On Premise deployment with Sitecore Install Assistant user interface guides through the Sitecore XP Developer Workstation(XP Single).

Download the Graphical setup package for XP Single

Download and Install Sql Server 2019 express edition.

Download and Install Sql Server Management Studio-

Restart Machine

Extract Sitecore 10.0.1 rev. 004842 (Setup XP0 Developer Workstation rev. 1.2.1-r1).zip file

Start the setup

Install Sitecore Install Framework (SIF) and Windows pre-requisites

Restart computer. Start the installation again this time you can skip the pre-requisites if already installed

Install SOLR. Provide Solr port and path prefix

After SOLR is installed successfully. Provide the Sitecore solution prefix and license path.

Sitecore settings

Provide SQL Server Settings

Provide Solr installed path and service name.

You may check the service name and the status of the service. Run services.msc.

Optional SXA module to install

Confirm the provided details

Installation Complete

Sitecore Commerce 10 Business Tools- Part 2 – Create custom vertical view component

This is a Part-2 of customizing Sitecore Commerce Business Tools. To see how to setup the environment for customization before you could start creating a custom component see Part-1

Often you have seen entity details are shown in Flat view i.e. horizontally, fields and there values are displayed. If you have too many fields to display flat view doesn’t seem to be user friendly. In this case the best way to display such details will a vertical view.

This post assumes Instance of Commerce Engine deployed in development environment and a custom entity is created. This is just a example on how to extend Business Tools using Angular which shows the flexibility of Business Tools in terms of cusotmization.

I have a entity named Organization and captures details for same which has quite a few properties as seen in below screen-

There are around 10 fields in the details section of the entity. These fields are squeezed and also doesn’t look user friendly. This would go more ugly if there are more fields added in the entity.

Sitecore Entity View default UIHint is Flat where a single row is displayed in a form of table.

This would look better if it is displayed in Vertical View or Form View i.e. each field in a different row.

Lets see how this can be done using BizFx SDK and the development environment we have created in this post – <<ENTER SETUP DEV BUSINESS TOOL ENVIRONMENT LINK HERE>>

Sitecore business tools already have Flat and Table View. Flat been default. Lets create a new view called as Vertical View.

Open the folder where the SDK zip file was extracted and navigate to src/app/components/views folder

View folder should look like this-

Copy paste and rename following files-

  1. Copy and Rename sc-bizfx-flatview.component.css to sc-bizfx-verticalview.component.css
  2. Copy and Rename sc-bizfx-flatview.component.html to sc-bizfx-verticalview.component.html
  3. Copy and Rename sc-bizfx-flatview.component.ts to sc-bizfx-verticalview.component.ts

Open sc-bizfx-verticalview.component.html. Change the table to display the property name and value-

 <table scTable class="mb-0" *ngIf="view.Properties.length">
      <thead>
        <tr>
		<th>Property Name</th>
		<th>Property Value</th>
	</tr>
      </thead>
      <tbody>
		<tr *ngFor="let property of (view.Properties | isNotHidden)">
          <td>{{property.DisplayName}}</td>
		  <td>
            <div [ngSwitch]="property.OriginalType">
              <div id="property-{{view.Name}}-{{property.Name}}" *ngSwitchCase="'System.DateTimeOffset'" class="property">
                  <div *ngIf="property.UiType === 'FullDateTime'">
                      {{property.Value | date:'short':'':bizFxContext.language}}
                  </div>
                  <div *ngIf="property.UiType !== 'FullDateTime'">
                      {{property.Value | date:'shortDate':'':bizFxContext.language}}
                  </div>
              </div>

              <div id="property-{{view.Name}}-{{property.Name}}" *ngSwitchCase="'System.Decimal'" class="property">
                {{property.Value | number:'':bizFxContext.language}}
              </div>

              <div id="property-{{view.Name}}-{{property.Name}}" *ngSwitchCase="'Sitecore.Commerce.Core.Money'" class="property">
                {{property.Value | scCurrency:'code':'1.2-2':bizFxContext.language}}
              </div>

              <div id="property-{{view.Name}}-{{property.Name}}" *ngSwitchCase="'Html'" class="property">
                <div [innerHTML]="property.Value"></div>
              </div>

              <div id="property-{{view.Name}}-{{property.Name}}" *ngSwitchCase="'List'" class="property">
                <div *ngFor="let item of getList(property)">
                  {{item}}
                </div>
              </div>

              <div id="property-{{view.Name}}-{{property.Name}}" *ngSwitchDefault class="property">
                {{property.Value}}
              </div>
            </div>
          </td>
        </tr>
      </tbody>
    </table>

Add following to div having childViews loop to sc-bizfx-flatview.component.html-

<sc-bizfx-verticalview *ngIf="childView.UiHint === 'Vertical'" id="verticalView-{{childView.Name}}" [view]="childView"></sc-bizfx-verticalview>

Open sc-bizfx-verticalview.component.ts. Change the @Component and export Class name

@Component({
  selector: 'sc-bizfx-verticalview',
  templateUrl: './sc-bizfx-verticalview.component.html',
  styleUrls: ['./sc-bizfx-verticalview.component.css']
})
export class ScBizFxVerticalViewComponent {
  /**
    * Defines the view
    */
  @Input() view: ScBizFxView;

  /**
    * @ignore
    */
  constructor(
    public bizFxContext: ScBizFxContextService) {
  }

  /**
    * Helper method
    *
    * Parse the value of property with `UiType` of `List`.
    */
  getList(property: ScBizFxProperty) {
    return property.Value != null ? JSON.parse(property.Value) : [];
  }
}

Navigate to components folder. Open index.ts

Add- export * from ‘./views/sc-bizfx-verticalview.component’;

Navigate to app folder. Since a new class is registered this needs to be registered in app.module.ts file.

Open app.module.ts file. Add ScBizFxVerticalViewComponent to App Root import and to the @NgModule – declarations section-

import {
  ScBizFxActionComponent,
  ScBizFxActionBarComponent,
  ScBizFxFlatViewComponent,
  ScBizFxItemViewComponent,
  ScBizFxListPoliciesComponent,
  ScBizFxListViewComponent,
  ScBizFxSearchViewComponent,
  ScBizFxTableViewComponent,
  ScBizFxViewPropertyByTypeComponent,
  ScBizFxViewPropertyByUiComponent,
  ScBizFxViewPropertyTagsComponent,
  ScBizFxActionGridComponent,
  ScBizFxActionPropertyDateTimeComponent,
  ScBizFxActionPropertyTagsComponent,
  ScBizFxActionPropertyComponent,
  ScBizFxAutocompleteComponent,
  ScBizFxBraintreeComponent,
  ScBizFxMediaPickerComponent,
  ScBizFxViewComponent,
  ScBizFxVerticalViewComponent
} from './components';
declarations: [
    AppComponent,
    ScBizFxActionComponent,
    ScBizFxActionBarComponent,
    ScBizFxFlatViewComponent,
    ScBizFxItemViewComponent,
    ScBizFxListPoliciesComponent,
    ScBizFxListViewComponent,
    ScBizFxSearchViewComponent,
    ScBizFxTableViewComponent,
    ScBizFxViewPropertyByTypeComponent,
    ScBizFxViewPropertyByUiComponent,
    ScBizFxViewPropertyTagsComponent,

    ScBizFxActionGridComponent,
    ScBizFxActionPropertyDateTimeComponent,
    ScBizFxActionPropertyTagsComponent,
    ScBizFxActionPropertyComponent,
    ScBizFxAutocompleteComponent,
    ScBizFxBraintreeComponent,
    ScBizFxMediaPickerComponent,
    ScBizFxViewComponent,
    ScBizFxVerticalViewComponent
  ],

That’s all changes required to have a custom component in Business Tools.

Next open PowerShell and build the changes made and run the Business Tools site

ng serve

The site should now listen to 4200 port.

Now lets create/update a entity view with a Vertical view UIHint. I already have entity with the Flat view. I will change the UIHint to “Vertical” to display the properties and there values vertically.

Build and deploy engine changes to Authoring site. (Not covered in this blog)

Using Flat view either squeezes the table or a horizontal scroll which is not user friendly. With the Verticalview Organization details are now shown vertical with the Property Names and Values in different rows.

This view is more readable for user specially with the long text in Address.

Easy to implement and test on development environment you can build more complex controls with the same approach

Next post will see how to deploy these changes to production.

Hope you liked this post.

Sitecore Commerce 10 Create a custom plugin project

If you want to get started and create a custom plugin for XC 9.3 here is the post for same First Steps | Sitecore Commerce Development | Create a Custom Plugin

There are few updates on how the plugins are created in XC 10.

Sitecore Commerce 10 SDK does not include Visual Studio Extension (VSIX) package for creating a plugin project.

Let’s get started and look into the steps to create a new plugin in Sitecore Commerce 10. If you have already set up your commerce development environment, please skip to step 2

Step 1 – Setup developer environment

Create a developer environment for Sitecore Commerce to run the engine from Visual Studio, can be either VS 2017 or 2019. Follow this blog post for same Setup development environment for Sitecore Commerce 10 Engine

Step 2: Download Sitecore.Commerce.Plugin.Template from Nuget Feed

  • Navigate to Official Sitecore Commerce Nuget Feed
  • Search for Sitecore.Commerce.Plugin.Template
  • Download the package for Sitecore.Commerce.Plugin.Template 6.0.4. Copy to file Sitecore.Commerce.Plugin.Template.6.0.4.nupkg desired folder.

3. Install Sitecore Commerce Plugin Template Nuget Package

  • Open Powershell in admin mode and navigate to the folder nupkg file is copied and execute following command to install package
dotnet new -i .\Sitecore.Commerce.Plugin.Template.6.0.4.nupkg
  • Run the dotnet new command and should be able to see Sitecore Commerce Sample Plugin template

4. Create a new Sitecore Commerce Plugin Project

As we have a plugin project template we should be able create a new plugin project.

Execute following command in Powershell. Navigate to the solution src folder-

dotnet new pluginsample -o Sitecore.Commerce.Plugin.SampleTest

New plugin project is created with the project name specified in command.

Include the project in Customer.Sample.Solution and compile.

Notice even though the command has project name “Sitecore.Commerce.Plugin.SampleTest” the actual project is created as “Sitecore.Commerce.Plugin.Sample”. You will have to rename this unfortunately as per your requirement.

Sharding Custom Entity in Sitecore Commerce 10

Sharding is horizontal partitioning of data in database. It is the process of breaking up large tables into smaller chunks.

Storing rows of the same table in multiple database nodes

In this blog post will see how to split the Commerce Entities table having same structure but store custom entity data in a separate table that helps to split the load that a CommerceEntities table might take if the horizontal partition is not done.

Why partioning of tables is required?

Sitecore Commerce entity data are store in following tables-

  • CommerceEntities
  • CommerceEntity
  • CommerceLists

Any custom entity been created without sharding will store data by default in tables mentioned above.

What if that data increases, there might be a performance hit once the data start expanding over months and years.

Also it wont be good idea to put the multiple custom entity data into a single table. As this might give a performance hit whilst indexing table. So, if you know data might increase over the time it is better to have it saved in a separate table as it can be a boon to high-volume data.

Partitioning data using sharding policy

I assume you know how extend Sitecore Commerce entities. Consider we have a “Organization” entity. Business Tools helps in capturing details of Organization i.e. CRUD operations. When the entity is been saved it has to be saved in different table.

This driven by the sharding policies in Commerce.

Follow these steps to enable sharding of custom entity-

Sharding Policies

The Commerce Engine implements database sharding for Commerce entity and list tables, and provides 2 types of sharding policies. One is for the operation against Commerce entities i.e. EntityShardingPolicy, and other on the Commerce lists i.e. ListShardingPolicy.

Configuration for sharding policy is kept in PlugIn.SQL.Sharding.PolicySet-1.0.0.json file and can be found in data\Environments folder of the Authoring and Shops instance.

As per Sitecore documentation sharding policies has expressions and multiple expression values can be configured based on this the table of the entity is identified to read and perform write operations. This is a bit contrary statement as the table name defined in policies are passed to the stored procedure based on this the data in table is written and read.

Below sharding policy mentions 2 tables-

OrganizationsLists for managing and reading lists of Organizations

OrganizationsEntities for managing and reading Organization entities

{
"$type": "Sitecore.Commerce.Plugin.SQL.ListShardingPolicy, Sitecore.Commerce.Plugin.SQL",
"Expressions": {
"$type": "System.Collections.Generic.List1[[System.String, mscorlib]], mscorlib",
"$values":
[
"^List-Organization.*?$"
]
},
"TableName": "OrganizationsLists"
},
{ 
"$type": "Sitecore.Commerce.Plugin.SQL.EntityShardingPolicy, Sitecore.Commerce.Plugin.SQL",
"Expressions": {
"$type": "System.Collections.Generic.List1[[System.String, mscorlib]], mscorlib",
"$values":
[
"^Entity-Organization.?$",
"^Organization-.?$"
]
},
"TableName": "OrganizationsEntities"
}

Database

To save data in different tables create Entities, Entity and Lists table prefixed with entity name in SitecoreCommerce_SharedEnvironments database

  1. Right click CommerceEntities table select Script Table as option, Create to and then New Query Editor Window. Create script for CommerceEntities table will be generated.
  2. Change the name of table to e.g.:- OrganizationsEntities. Also change the table name to set Default value to EntityVersion and Published fields
  3. Pasrse and check if you are creating a table in correct Database
  4. Execute the script. New table will be created.

Follow same for CommerceEntity table to create OrganizationsEntity and CommerceLists to create OrganizationsLists

So there are 3 tables created so far-

  • OrganizationsEntities
  • OrganizationsEntity
  • OrganizationsLists

Once you have your plugin to perform CRUD operations on Organizations entity you should be able to see the data been inserted in OrganizationEntities, OrganizationLists and OrganizationsEntity table instead of CommerceEntities and there related tables.

Asp.Net Core – Route Constraints

Routing constraints lets you restrict how the parameters in the route template are matched. It helps to filter out the input parameter and action method can accept.

For example if the URL Parameter is restricted to have int value, the route engine will match the controller action having integer value in the parameter or restrict.

How Route Constraints are applied-

  1. Using constraint parameter in the MapControllerRoute at the application startup where the endpoints are defined i.e. Inline Constraint
  2. Route attribute at the controller or action method
endpoints.MapControllerRoute(
name: "default",
pattern: "controller=Home}/{action=Index}/{id:int?}");

Route engine when matches the incoming url, it invokes the routing constraint to the the values in the url matches the pattern. In this case which is seperated by : in the above example restricts the value should be int or null.

Quick example on how the routing constraints are defined and used-

  • Inline Constraint

Inline constraint are added after the URL parameter and sperated by : (colon) with the primitive type and also defines if the parameter can be nullable. Below code see – {id:int?}

app.UseEndpoints(
endpoints =>
{
 endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id:int?}");
}
);

The int constraints checks if the parameter value sent is integer and allows to execute the action method by passing the parameter value to the matching method.

The other way to define same if to pass the default values and constraint parameter in the MapControllerRoute

 app.UseEndpoints(endpoints =>
{
    endpoints.MapControllerRoute(
name: "default",
pattern: "  {controller}/{action}/{id?}", new {Controller = "Home", action="Index"}, new {id = new IntRouteConstraint()});
}
);
  • Constraints in route attribute

You can also define the constraints in route attribute as follows-

[Route("Home/Index/{id:int?}")]
public IActionResult Index(int? id)
{
     return View();
}

Here are the list of constraints from the Microsoft doc site, try it yourself-

ConstraintDescriptionExample
alphaMatches uppercase or lowercase Latin alphabet characters (a-z, A-Z){x:alpha}
boolMatches a Boolean value.{x:bool}
datetimeMatches a DateTime value.{x:datetime}
decimalMatches a decimal value.{x:decimal}
doubleMatches a 64-bit floating-point value.{x:double}
floatMatches a 32-bit floating-point value.{x:float}
guidMatches a GUID value.{x:guid}
intMatches a 32-bit integer value.{x:int}
lengthMatches a string with the specified length or within a specified range of lengths.{x:length(6)} {x:length(1,20)}
longMatches a 64-bit integer value.{x:long}
maxMatches an integer with a maximum value.{x:max(10)}
maxlengthMatches a string with a maximum length.{x:maxlength(10)}
minMatches an integer with a minimum value.{x:min(10)}
minlengthMatches a string with a minimum length.{x:minlength(10)}
rangeMatches an integer within a range of values.{x:range(10,50)}
regexMatches a regular expression.{x:regex(^\d{3}-\d{3}-\d{4}$)}

© 2021 Sandeep Pote

Theme by Anders NorénUp ↑