To speed up development with Commerce Engine customisations, I have created a library of templates for Visual Studio. This should remove the necessity of referencing the sample commerce engine plugin project or decompiling and cleaning code from certain DLLs just to get to a starting point for your customisations.
Throughout this article we will utilise the categoryComputers and Tablets > Kid’s Tablets and productMinnow Kid’s Tablet—7”, 8GB to review our progress. These examples also contain some non-alphanumeric characters to ensure we take these special characters into consideration.
How Storefront URLs are Generated
Storefront URLs are constructed using the configuration of the site’ s linkManager. The configuration is located at sitecore/linkManager/providers/add[@name=’commerce‘].
An important note about the provider configuration properties is that only 3 properties actually affect the generated URLs – includeFriendlyName, useShopLinks, and encodeNames.
includeFriendlyName: Includes the DisplayName of the category or product in the URL segment. i.e. {category DisplayName}={category FriendlyId}and {product DisplayName}={ProductId/FriendlyId}.
useShopLinks: Constructs URL with shop/{category}/{product} if enabled, otherwise as category/{category} and product/{product}for category and product URLs respectively.
includeCatalog:Not currently supported
addAspxExtension: N/A
alwaysIncludeServerUrl: N/A
encodeNames: Encodes the DisplayName portion of the category and product segments. Only supported when useShopLinks is true.
languageEmbedding: N/A
languageLocation: N/A
lowercaseUrls: Not currently supported
shortenUrls: Not currently supported
useDisplayName: Not currently supported
URLs Generated from Various Configurations
The following decision table shows the available configurations
Rules
Conditions
1
2
3
4
5
useShopLinks
Y
Y
Y
N
N
includeFriendlyName
Y
Y
N
Y
N
encodeNames
Y
N
Y
Actions
1
2
3
4
5
Shop
X
X
X
Product/Category
X
X
Display Name prefix
X
X
X
Display Name encoding
X
X
The following table shows the URLs generated from the rules in the above table.
The URLs generated are looking good. We do have an issue with the URLs still containing encoded spaces. To control character encoding there is a configuration in the content editor at /sitecore/Commerce/Commerce Control Panel/Storefront Settings/Global Configuration > URL Encoding > Catalog Item Encoding.
Unfortunately there is a quirk in which it doesn’t accept space entries, so we will override the EncodeUrlToken and DecodeUrlToken methods instead. As we aren’t allowed to have hyphens in the category names, we won’t have any character conflicts where encoding or decoding.
Now that we have our category URL structure that meets our requirements, our last step is to ensure the URLs are resolving back to their correct Sitecore items.
Updating the CatalogPageItemResolver
Now we have covered the URL generation implementation, we now need to resolve these URLs back to their correct Sitecore items.
public override void Process(PipelineArgs args)
{
if (Context.Item == null || SiteContext.CurrentCatalogItem != null)
{
return;
}
var contextItemType = GetContextItemType();
switch (contextItemType)
{
case ItemTypes.Category:
case ItemTypes.Product:
var isProduct = contextItemType == ItemTypes.Product;
var catalogItemIdFromUrl = GetCatalogItemIdFromUrl(isProduct);
if (string.IsNullOrEmpty(catalogItemIdFromUrl))
{
break;
}
var catalog = StorefrontContext.CurrentStorefront.Catalog;
var catalogItem = ResolveCatalogItem(catalogItemIdFromUrl, catalog, isProduct);
if (catalogItem == null && !isProduct)
{
catalogItemIdFromUrl = GetCatalogItemIdFromUrl(true);
if (string.IsNullOrEmpty(catalogItemIdFromUrl))
{
break;
}
catalogItem = ResolveCatalogItem(catalogItemIdFromUrl, catalog, isProduct);
}
if (catalogItem == null)
{
WebUtil.Redirect("~/");
}
SiteContext.CurrentCatalogItem = catalogItem;
break;
}
}
private string GetCatalogItemIdFromUrl(bool isProduct)
{
var catalogItemId = string.Empty;
var rawUrl = HttpContext.Current.Request.RawUrl;
var urlTokens = rawUrl.Split('/');
if (urlTokens.Any())
{
var item = urlTokens.Last();
var queryStringPosition = item.IndexOf("?", StringComparison.OrdinalIgnoreCase);
if (queryStringPosition > 0)
{
item = item.Substring(0, queryStringPosition);
}
if (isProduct && urlTokens.Length >= 4)
{
var parentCategoryName = urlTokens[urlTokens.Length - 2];
item = $"{parentCategoryName}{item}";
}
catalogItemId = CatalogUrlManager.ExtractItemId(item);
}
return catalogItemId;
}
Summary
We learnt that the construction of the URL can be managed via Sitecore Configuration, the Sitecore Content Editor and via code customisations, depending on the URL requirements.