Developer forum

Forum » Development » Handling different Product Detail pages for products in the same group

Handling different Product Detail pages for products in the same group

Adrian Ursu Dynamicweb Employee
Adrian Ursu
Reply

Hi guys,

The new feature in Swift/DW for handling Detail page for products in various groups was very interesting and very useful.

However, we have situations where products in the same group have to have different ProductDetail pages.

I have used a hack suggested by Nuno by using a custom field on the product but this change involves a lot of changes in all templates that involve product links. Not to mention situations where search engines have indexed the wrong links. 

I was wondering if there can be a wider approach to this, by manipulating the value for PrimaryPageId based on a setting on the product.

Before we dive into investigating it, I would like to know if this approach is even possible. And if it is, where should I start digging?

Thank you,
Adrian


Replies

 
Adrian Ursu Dynamicweb Employee
Adrian Ursu
Reply

Hi guys,

Anybody?

Adrian

 
Nicolai Pedersen Dynamicweb Employee
Nicolai Pedersen
Reply

None that I can find. So the solution you made so far is the best option.

BR Nicolai

 
Adrian Ursu Dynamicweb Employee
Adrian Ursu
Reply

Hi Nicolai,

Thank you.

Adrian

 
Adrian Ursu Dynamicweb Employee
Adrian Ursu
Reply

Hi Nicolai,

We have looked more into this solution and it does not seem to be the best approach since we have a lot of places where the links are handled.

I was wondering if w can manipulate this URL generation closer to the rendering of the page. On a notification or maybe in the URL provider itself.

I imagine that this issue will surface again in the future and there should be a more straight forward approach than heavy customization.

What do you think?

Thank you,

Adrian

 

 

 
Nicolai Pedersen Dynamicweb Employee
Nicolai Pedersen
Reply

Hi Adrian

You can create your own URL provider - not sure it will help you in this case as it does not look into primary group pageid.

This is the version we use - you can modify it. Do NOT get an instance of a product, page or something crazy in it - your system will break.

 

using Dynamicweb.Core;
using Dynamicweb.Data;
using Dynamicweb.Ecommerce.International;
using Dynamicweb.Ecommerce.Products;
using Dynamicweb.Ecommerce.Shops;
using Dynamicweb.Ecommerce.Variants;
using Dynamicweb.Extensibility.AddIns;
using Dynamicweb.Extensibility.Editors;
using Dynamicweb.Extensibility.Notifications;
using Dynamicweb.Frontend.UrlHandling;
using Dynamicweb.SystemTools;
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;

namespace Dynamicweb.Ecommerce.Frontend.UrlHandling
{
    [AddInName("Ecommerce")]
    public class ShopUrlDataProvider : UrlDataProvider, IDropDownOptionActions
    {
        [AddInLabel("Shop")]
        [AddInParameter(nameof(IncludeFrom))]
        [AddInParameterEditor(typeof(RadioParameterEditor), "SortBy=Key")]
        public string IncludeFrom { get; set; } = "ContextShop";

        [AddInLabel("Selected shop")]
        [AddInParameter(nameof(SelectedShopId))]
        [AddInParameterEditor(typeof(DropDownParameterEditor), "")]
        public string SelectedShopId { get; set; }

        [AddInLabel("Language")]
        [AddInParameter(nameof(IncludeLanguage))]
        [AddInParameterEditor(typeof(RadioParameterEditor), "SortBy=Key")]
        public string IncludeLanguage { get; set; } = "ContextLanguage";

        [AddInLabel("Selected language")]
        [AddInParameter(nameof(SelectedLanguageId))]
        [AddInParameterEditor(typeof(DropDownParameterEditor), "")]
        public string SelectedLanguageId { get; set; }

        [AddInLabel("Include")]
        [AddInParameter(nameof(Include))]
        [AddInParameterEditor(typeof(RadioParameterEditor), "SortBy=Key")]
        public string Include { get; set; } = "GroupsProductsVariants";

        [AddInLabel("Groups")]
        [AddInParameter(nameof(GroupPath))]
        [AddInParameterEditor(typeof(RadioParameterEditor), "")]
        public string GroupPath { get; set; } = "Tree";

        [AddInLabel("Products")]
        [AddInParameter(nameof(ProductPath))]
        [AddInParameterEditor(typeof(RadioParameterEditor), "")]
        public string ProductPath { get; set; } = "Tree";

        private static Lazy<ConcurrentDictionary<string, List<string>>> lazyGroupProductRelationIndex = new Lazy<ConcurrentDictionary<string, List<string>>>(InitializeGroupProductRelationIndex);

        private static ConcurrentDictionary<string, List<string>> GroupProductRelationIndex => lazyGroupProductRelationIndex.Value;

        private static Lazy<ConcurrentDictionary<string, Dictionary<string, UrlDataNode>>> lazyProductUrlDataIndex = new Lazy<ConcurrentDictionary<string, Dictionary<string, UrlDataNode>>>(InitializeProductUrlDataIndex);

        private static ConcurrentDictionary<string, Dictionary<string, UrlDataNode>> ProductUrlDataIndex => lazyProductUrlDataIndex.Value;

        public override IEnumerable<UrlDataNode> GetUrlDataNodes(UrlDataNode parent, UrlDataContext dataContext)
        {
            var nodes = new List<UrlDataNode>();
            var shop = GetShop(dataContext);
            if (shop is null)
            {
                return nodes;
            }

            var language = GetLanguage(dataContext);
            if (language is null)
            {
                return nodes;
            }

            var groups = GetTopLevelGroups(shop, language);
            if (groups is null)
            {
                return nodes;
            }

            var settings = GetUrlDataSettings();
            foreach (Group group in groups)
                AddNodesRecursive(nodes, parent, group, settings);
            return nodes;
        }

        private UrlDataSettings GetUrlDataSettings()
        {
            var settings = new UrlDataSettings();
            switch (Include ?? "")
            {
                case "Groups":
                    {
                        settings.IncludeProducts = false;
                        settings.IncludeVariants = false;
                        break;
                    }

                case "GroupsProducts":
                    {
                        settings.IncludeProducts = true;
                        settings.IncludeVariants = false;
                        break;
                    }

                default:
                    {
                        settings.IncludeProducts = true;
                        settings.IncludeVariants = true;
                        break;
                    }
            }

            switch (GroupPath ?? "")
            {
                case "Root":
                    {
                        settings.PlaceGroupsInRoot = true;
                        break;
                    }

                default:
                    {
                        settings.PlaceGroupsInRoot = false;
                        break;
                    }
            }

            switch (ProductPath ?? "")
            {
                case "Root":
                    {
                        settings.PlaceProductsInRoot = true;
                        break;
                    }

                default:
                    {
                        settings.PlaceProductsInRoot = false;
                        break;
                    }
            }

            return settings;
        }

        private static ICollection<Group> GetTopLevelGroups(Shop shop, Language language)
        {
            return shop.GetTopLevelGroups(language.LanguageId);
        }

        private Language GetLanguage(UrlDataContext dataContext)
        {
            string languageId = null;
            if (string.Equals(IncludeLanguage, "ContextLanguage", StringComparison.OrdinalIgnoreCase))
            {
                languageId = dataContext.EcomLanguageId;
            }
            else if (string.Equals(IncludeLanguage, "SelectedLanguage", StringComparison.OrdinalIgnoreCase))
            {
                languageId = SelectedLanguageId;
            }

            Language language = null;
            if (!string.IsNullOrEmpty(languageId))
            {
                language = Services.Languages.GetLanguage(languageId);
            }

            return language;
        }

        private Shop GetShop(UrlDataContext dataContext)
        {
            string shopId = null;
            if (string.Equals(IncludeFrom, "ContextShop", StringComparison.OrdinalIgnoreCase))
            {
                shopId = dataContext.EcomShopId;
            }
            else if (string.Equals(IncludeFrom, "SelectedShop", StringComparison.OrdinalIgnoreCase))
            {
                shopId = SelectedShopId;
            }

            Shop shop = null;
            if (!string.IsNullOrEmpty(shopId))
            {
                shop = Services.Shops.GetShop(shopId);
            }

            return shop;
        }

        private void AddNodesRecursive(IList<UrlDataNode> entries, UrlDataNode parent, Group group, UrlDataSettings settings)
        {
            var groupUrlData = CreateGroupUrlData(parent, group);
            if (settings.PlaceGroupsInRoot)
            {
                groupUrlData.IgnoreParentPath = true;
            }

            entries.Add(groupUrlData);
            IEnumerable<Group> subGroups = GetSubGroups(group);
            foreach (Group subGroup in subGroups)
                AddNodesRecursive(entries, groupUrlData, subGroup, settings);
            if (settings.IncludeProducts)
            {
                List<string> productIds = null;
                if (GroupProductRelationIndex.TryGetValue(group.Id, out productIds))
                {
                    Dictionary<string, UrlDataNode> indexByProductId = null;
                    if (ProductUrlDataIndex.TryGetValue(group.LanguageId, out indexByProductId))
                    {
                        foreach (string productId in productIds)
                        {
                            UrlDataNode indexedProductUrlData = null;
                            if (indexByProductId.TryGetValue(productId, out indexedProductUrlData))
                            {
                                // clone and set unique id
                                var productUrlData = CloneUrlData(indexedProductUrlData);
                                productUrlData.Id = $"{indexedProductUrlData.Id}_{groupUrlData.Id}";
                                productUrlData.ParentId = groupUrlData.Id;
                                if (settings.PlaceProductsInRoot)
                                {
                                    productUrlData.IgnoreParentPath = true;
                                }

                                entries.Add(productUrlData);
                                if (settings.IncludeVariants)
                                {
                                    var variantCombinations = Services.VariantCombinations.GetVariantCombinations(productId);
                                    foreach (var variantCombination in variantCombinations)
                                    {
                                        var variantUrlData = CreateProductVariantUrlData(productUrlData, group.LanguageId, variantCombination);
                                        if (settings.PlaceProductsInRoot)
                                        {
                                            variantUrlData.PathName = productUrlData.PathName + "-" + variantUrlData.PathName;
                                            variantUrlData.IgnoreParentPath = true;
                                        }

                                        entries.Add(variantUrlData);
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }

        private static UrlDataNode CloneUrlData(UrlDataNode urlData)
        {
            var urlDataClone = new UrlDataNode()
            {
                Id = urlData.Id,
                ParentId = urlData.ParentId,
                PathName = urlData.PathName,
                IgnoreInChildPath = urlData.IgnoreInChildPath,
                IgnoreParentPath = urlData.IgnoreParentPath,
                PathExact = urlData.PathExact,
                QueryStringParameter = urlData.QueryStringParameter,
                QueryStringValue = urlData.QueryStringValue,
                QueryStringExact = urlData.QueryStringExact,
                IgnoreParentQuerystring = urlData.IgnoreParentQuerystring
            };
            return urlDataClone;
        }

        private static UrlDataNode CreateGroupUrlData(UrlDataNode parent, Group group)
        {
            var nodeData = new UrlDataNode()
            {
                Id = $"PRODUCTGROUP_{group.Id}_{parent.Id}",
                ParentId = parent.Id,
                PathName = string.IsNullOrEmpty(Converter.ToString(group.Meta.Url)) ? Converter.ToString(group.Name) : Converter.ToString(group.Meta.Url),
                IgnoreInChildPath = false,
                IgnoreParentPath = group.Meta.UrlIgnoreParent,
                PathExact = string.Empty,
                QueryStringParameter = "GroupID",
                QueryStringValue = group.Id,
                QueryStringExact = string.Empty,
                IgnoreParentQuerystring = false
            };
            return nodeData;
        }

        private static UrlDataNode CreateProductVariantUrlData(UrlDataNode parent, string languageId, VariantCombination variantCombination)
        {
            var nodeData = new UrlDataNode()
            {
                Id = $"PRODUCTVARIANT_{variantCombination.VariantId}_{parent.Id}",
                ParentId = parent.Id,
                PathName = variantCombination.GetVariantName(languageId),
                IgnoreInChildPath = false,
                IgnoreParentPath = false,
                PathExact = string.Empty,
                QueryStringParameter = "VariantID",
                QueryStringValue = variantCombination.VariantId,
                QueryStringExact = string.Empty,
                IgnoreParentQuerystring = false
            };
            return nodeData;
        }

        private static ICollection<Group> GetSubGroups(Group group)
        {
            var childRelations = GroupRelation.GetGroupRelationsByParentId(group.Id).OrderBy(relation => relation.Sorting);
            var children = new List<Group>();
            foreach (GroupRelation childRelation in childRelations)
            {
                var theGroup = Services.ProductGroups.GetGroup(childRelation.Id, group.LanguageId);
                if (theGroup is object)
                {
                    children.Add(theGroup);
                }
            }

            return children;
        }

        private static ConcurrentDictionary<string, List<string>> InitializeGroupProductRelationIndex()
        {
            var result = new ConcurrentDictionary<string, List<string>>();
            using (var reader = Database.CreateDataReader("SELECT DISTINCT [GroupProductRelationGroupId],[GroupProductRelationProductId] FROM [EcomGroupProductRelation] WITH (NOLOCK)"))
            {
                while (reader.Read())
                {
                    string groupId = reader.GetString(0);
                    string productId = reader.GetString(1);
                    List<string> list = null;
                    if (!result.TryGetValue(groupId, out list))
                    {
                        list = new List<string>();
                        result.TryAdd(groupId, list);
                    }

                    list.Add(productId);
                }
            }

            return result;
        }

        /// <summary>
        /// UrlData by languageid, productid
        /// </summary>
        private static ConcurrentDictionary<string, Dictionary<string, UrlDataNode>> InitializeProductUrlDataIndex()
        {
            var indexByLanguageId = new ConcurrentDictionary<string, Dictionary<string, UrlDataNode>>();
            using (var reader = Database.CreateDataReader("SELECT [ProductID], [ProductLanguageID], [ProductName], [ProductMetaUrl] FROM [EcomProducts] WITH (NOLOCK) WHERE ([ProductVariantID] IS NULL OR [ProductVariantID] = '') AND [EcomProducts].[ProductExcludeFromCustomizedUrls] = 0 ORDER BY ProductCreated ASC"))
            {
                while (reader.Read())
                {
                    string productId = Convert.ToString(reader.GetString(0));
                    string productLanguageId = Convert.ToString(reader.GetString(1));
                    string productName = Convert.ToString(reader[2]);
                    string productMetaUrl = Convert.ToString(reader[3]);
                    Dictionary<string, UrlDataNode> indexByProductId = null;
                    if (!indexByLanguageId.TryGetValue(productLanguageId, out indexByProductId))
                    {
                        indexByProductId = new Dictionary<string, UrlDataNode>();
                        indexByLanguageId.TryAdd(productLanguageId, indexByProductId);
                    }

                    var nodeData = new UrlDataNode()
                    {
                        Id = $"PRODUCT_{productId}",
                        PathName = string.IsNullOrEmpty(Converter.ToString(productMetaUrl)) ? Converter.ToString(productName) : Converter.ToString(productMetaUrl),
                        IgnoreInChildPath = false,
                        IgnoreParentPath = false,
                        PathExact = string.Empty,
                        QueryStringParameter = "ProductID",
                        QueryStringValue = productId,
                        QueryStringExact = string.Empty,
                        IgnoreParentQuerystring = false
                    };
                    indexByProductId.Add(productId, nodeData);
                }
            }

            return indexByLanguageId;
        }

        #region IDropDownOptionActions

        public Hashtable GetOptions(string dropdownName)
        {
            var options = new Hashtable();
            switch (dropdownName ?? "")
            {
                case nameof(Include):
                    {
                        options.Add("GroupsProductsVariants", Translator.Translate("Groups, products, variants"));
                        options.Add("GroupsProducts", Translator.Translate("Groups, products"));
                        options.Add("Groups", Translator.Translate("Groups"));
                        break;
                    }

                case nameof(IncludeFrom):
                    {
                        options.Add("ContextShop", Translator.Translate("Current website shop"));
                        options.Add("SelectedShop", Translator.Translate("Selected shop"));
                        break;
                    }

                case nameof(SelectedShopId):
                    {
                        foreach (Shop shop in Services.Shops.GetShops())
                            options.Add(shop.Id, shop.Name);
                        break;
                    }

                case nameof(IncludeLanguage):
                    {
                        options.Add("ContextLanguage", Translator.Translate("Current website language"));
                        options.Add("SelectedLanguage", Translator.Translate("Selected language"));
                        break;
                    }

                case nameof(SelectedLanguageId):
                    {
                        foreach (Language language in Services.Languages.GetLanguages())
                            options.Add(language.LanguageId, language.Name);
                        break;
                    }

                case nameof(GroupPath):
                    {
                        options.Add("Tree", Translator.Translate("Tree path"));
                        options.Add("Root", Translator.Translate("Root path"));
                        break;
                    }

                case nameof(ProductPath):
                    {
                        options.Add("Tree", Translator.Translate("Tree path"));
                        options.Add("Root", Translator.Translate("Root path"));
                        break;
                    }
            }

            return options;
        }

        /// <inheritdoc/>
        public List<string> GetParametersToHide(string dropdownName, string optionKey)
        {
            var parameters = new List<string>();
            switch (dropdownName)
            {
                case nameof(IncludeFrom):
                    if (!"SelectedShop".Equals(optionKey, StringComparison.OrdinalIgnoreCase))
                    {
                        parameters.Add(nameof(SelectedShopId));
                    }
                    break;

                case nameof(IncludeLanguage):
                    if (!"SelectedLanguage".Equals(optionKey, StringComparison.OrdinalIgnoreCase))
                    {
                        parameters.Add(nameof(SelectedLanguageId));
                    }
                    break;
            }

            return parameters;
        }

        public List<string> GetSectionsToHide(string dropdownName, string optionKey) => new List<string>();

        #endregion

        public override void RenderAdditionalContent(TextWriter output)
        {
            base.RenderAdditionalContent(output);

            // Generate script to conditionally show/hide parameter controls based on selected options

            output.WriteLine("<script>");

            // shops
            output.WriteLine("  var shopSelector = document.getElementById('SelectedShopId').closest('.form-group');");
            output.WriteLine("  var includeFromOptions = document.getElementsByName('IncludeFrom');");
            output.WriteLine("  handleShowHide(includeFromOptions, showHideShopSelector);");
            output.WriteLine("  function showHideShopSelector() {");
            output.WriteLine("      if (this.value == 'SelectedShop') {");
            output.WriteLine("          shopSelector.style.display = '';");
            output.WriteLine("      } else {");
            output.WriteLine("          shopSelector.style.display = 'none';");
            output.WriteLine("      }");
            output.WriteLine("  }");

            // languages
            output.WriteLine("  var languageSelector = document.getElementById('SelectedLanguageId').closest('.form-group');");
            output.WriteLine("  var includeLanguageOptions = document.getElementsByName('IncludeLanguage');");
            output.WriteLine("  handleShowHide(includeLanguageOptions, showHideLanguageSelector);");
            output.WriteLine("  function showHideLanguageSelector() {");
            output.WriteLine("      if (this.value == 'SelectedLanguage') {");
            output.WriteLine("          languageSelector.style.display = '';");
            output.WriteLine("      } else {");
            output.WriteLine("          languageSelector.style.display = 'none';");
            output.WriteLine("      }");
            output.WriteLine("  }");

            // helper methods
            output.WriteLine("function handleShowHide(options, handler) {");
            output.WriteLine("  for (var i = 0; i < options.length; i++) {");
            output.WriteLine("      options[i].addEventListener('change', handler);");
            output.WriteLine("      if (options[i].checked) {");
            output.WriteLine("          if ('createEvent' in document) {");
            output.WriteLine("              var evt = document.createEvent('HTMLEvents');");
            output.WriteLine("              evt.initEvent('change', false, true);");
            output.WriteLine("              options[i].dispatchEvent(evt);");
            output.WriteLine("          } else {");
            output.WriteLine("              options[i].fireEvent('onchange');");
            output.WriteLine("          }");
            output.WriteLine("      }");
            output.WriteLine("  }");
            output.WriteLine("}");
            output.WriteLine("</script>");
        }

        private class UrlDataSettings
        {
            public bool IncludeProducts { get; set; }
            public bool PlaceProductsInRoot { get; set; }
            public bool IncludeVariants { get; set; }
            public bool PlaceGroupsInRoot { get; set; }
        }

        [Subscribe(Notifications.Ecommerce.Product.ProductGroupRelationAfterSave)]
        [Subscribe(Notifications.Ecommerce.Product.ProductGroupRelationDeleted)]
        public class ProductGroupRelationChangedObserver : NotificationSubscriber
        {
            public override void OnNotify(string notification, NotificationArgs args)
            {
                lazyGroupProductRelationIndex = new Lazy<ConcurrentDictionary<string, List<string>>>(InitializeGroupProductRelationIndex);
                UrlHelper.SetResetNeeded();
            }
        }

        [Subscribe(Notifications.Ecommerce.Product.AfterSave)]
        [Subscribe(Notifications.Ecommerce.Product.AfterDelete)]
        public class ProductChangedObserver : NotificationSubscriber
        {
            public override void OnNotify(string notification, NotificationArgs args)
            {
                var changeAffectUrlIndex = false;
                if (args is Dynamicweb.Ecommerce.Notifications.Ecommerce.Product.AfterSaveArgs)
                {
                    var saveArgs = args as Notifications.Ecommerce.Product.AfterSaveArgs;
                    var beforeSaveProduct = saveArgs.ProductBeforeChanges;
                    var afterSaveProduct = saveArgs.Product;

                    if (beforeSaveProduct != null)
                    {
                        changeAffectUrlIndex |= !beforeSaveProduct.Id.Equals(afterSaveProduct.Id);
                        changeAffectUrlIndex |= !beforeSaveProduct.VariantId.Equals(afterSaveProduct.VariantId);
                        changeAffectUrlIndex |= !beforeSaveProduct.LanguageId.Equals(afterSaveProduct.LanguageId);
                        changeAffectUrlIndex |= !beforeSaveProduct.Name.Equals(afterSaveProduct.Name);
                        changeAffectUrlIndex |= !beforeSaveProduct.Meta.Url.Equals(afterSaveProduct.Meta.Url);
                    }
                    else
                    {
                        changeAffectUrlIndex = true;
                    }
                }

                if (changeAffectUrlIndex)
                {
                    lazyProductUrlDataIndex = new Lazy<ConcurrentDictionary<string, Dictionary<string, UrlDataNode>>>(InitializeProductUrlDataIndex);
                    UrlHelper.SetResetNeeded();
                }
            }
        }

        [Subscribe(Notifications.Ecommerce.Group.AfterSave)]
        [Subscribe(Notifications.Ecommerce.Group.Deleted)]
        public class GroupChangedObserver : NotificationSubscriber
        {
            public override void OnNotify(string notification, NotificationArgs args)
            {
                var changeAffectUrlIndex = false;
                if (args is Dynamicweb.Ecommerce.Notifications.Ecommerce.Group.AfterSaveArgs)
                {
                    var saveArgs = args as Notifications.Ecommerce.Group.AfterSaveArgs;
                    var beforeSaveGroup = saveArgs.GroupBeforeChanges;
                    var afterSaveGroup = saveArgs.Group;

                    if (beforeSaveGroup != null)
                    {
                        changeAffectUrlIndex |= !beforeSaveGroup.Id.Equals(afterSaveGroup.Id);
                        changeAffectUrlIndex |= !beforeSaveGroup.LanguageId.Equals(afterSaveGroup.LanguageId);
                        changeAffectUrlIndex |= !beforeSaveGroup.Name.Equals(afterSaveGroup.Name);
                        changeAffectUrlIndex |= !beforeSaveGroup.Meta.Url.Equals(afterSaveGroup.Meta.Url);
                    }
                    else
                    {
                        changeAffectUrlIndex = true;
                    }
                }

                if (changeAffectUrlIndex)
                {
                    lazyProductUrlDataIndex = new Lazy<ConcurrentDictionary<string, Dictionary<string, UrlDataNode>>>(InitializeProductUrlDataIndex);
                    UrlHelper.SetResetNeeded();
                }
            }
        }

        [Subscribe(Notifications.Ecommerce.Group.RelationUpdated)]
        [Subscribe(Notifications.Ecommerce.Group.RelationDeleted)]
        public class GroupRelationChangedObserver : NotificationSubscriber
        {
            public override void OnNotify(string notification, NotificationArgs args)
            {
                UrlHelper.SetResetNeeded();
            }
        }

        [Subscribe(Dynamicweb.Notifications.Standard.Area.OnAreaSaved)]
        [Subscribe(Dynamicweb.Notifications.Standard.Area.OnAfterAreaDeleted)]
        public class AreaChangedObserver : NotificationSubscriber
        {
            public override void OnNotify(string notification, NotificationArgs args)
            {
                UrlHelper.SetResetNeeded();
            }
        }
    }
}
 
Adrian Ursu Dynamicweb Employee
Adrian Ursu
Reply

Hi Nicolai,

Thank you for the details.

I will have to wrap my head around it to figure out where is the best place to override the PageId :)

I suppose the URL provider handles only the translation/rewrite of the unfriendly URL into a friendly URL.

It may be too late to make any changes here as I don't see anything resembling PageId information.

Thank you,
Adrian

 

You must be logged in to post in the forum