I try to do it... Work only for languageID=0 (default language)
After save product or subcategory, auto generated SEO name that contains full path to product. If product has several categories, SEO name generated by using categories with minimal display Order.
\Presentation\Nop.Web\Infrastructure\GenericUrlRouteProvider.cs add to begin of the function public void RegisterRoutes(RouteCollection routes) {
......... next source code //generic URLs routes.MapGenericPathRoute("GenericUrl", "{generic_se_name}", new {controller = "Common", action = "GenericUrl"}, new[] {"Nop.Web.Controllers"}); .....
\Libraries\Nop.Services\Seo\UrlRecordService.cs edit function ValidateSeName public static string ValidateSeName<T>(this T entity, string seName, string name, bool ensureNotEmpty) where T : BaseEntity, ISlugSupported { if (entity == null) throw new ArgumentNullException("entity");
//use name if sename is not specified if (String.IsNullOrWhiteSpace(seName) && !String.IsNullOrWhiteSpace(name)) { seName = name;
//get last part - it is seoName Product seName = seName.Split(new char[] { '/' })[seName.Split(new char[] { '/' }).Length - 1];
var catServiceaa = EngineContext.Current.Resolve<Nop.Services.Catalog.ICategoryService>(); var urlRecordService1 = EngineContext.Current.Resolve<IUrlRecordService>(); Category category=null;
if (entityName1 == "Product") { //((Product)entity).ProductCategories.Count>0
if (((Product)((BaseEntity)entity)).ProductCategories.Count > 0) { ICollection<ProductCategory> prodCat = ((Product)((BaseEntity)entity)).ProductCategories; int firstCatId = ((Product)((BaseEntity)entity)).ProductCategories.ElementAt(0).CategoryId; int minDisplyaOrder = ((Product)((BaseEntity)entity)).ProductCategories.ElementAt(0).DisplayOrder;
foreach (ProductCategory pc in prodCat) { if (pc.DisplayOrder < minDisplyaOrder) { firstCatId = pc.CategoryId; minDisplyaOrder = pc.DisplayOrder; } } //var catServiceaa = EngineContext.Current.Resolve<Nop.Services.Catalog.ICategoryService>(); //var urlRecordService1 = EngineContext.Current.Resolve<IUrlRecordService>(); //var lService = EngineContext.Current.Resolve<ILanguageService>(); //var workContext = EngineContext.Current.Resolve<IWorkContext>(); category = catServiceaa.GetCategoryById(firstCatId); } } else if (entityName1 == "Category") { //var lService = EngineContext.Current.Resolve<ILanguageService>(); //var workContext = EngineContext.Current.Resolve<IWorkContext>(); int parentCatId = ((Category)((BaseEntity)entity)).ParentCategoryId; category = catServiceaa.GetCategoryById(parentCatId); } var categList = new List<Category>();
//used to prevent circular references var alreadyProcessedCategoryIds = new List<int>();
//add category path to SeoName Product or category if (seoNamesList.Count > 0) { seName = System.String.Join("/", seoNamesList) + "/" + seName; }
......... next sourse code
//max length //For long URLs we can get the following error: //"the specified path, file name, or both are too long. The fully qualified file name must be less than 260 characters, and the directory name must be less than 248 characters" //that's why we limit it to 200 here (consider a store URL + probably added {0}-{1} below) seName = CommonHelper.EnsureMaximumLength(seName, 200);
if (String.IsNullOrWhiteSpace(seName)) { if (ensureNotEmpty) { //use entity identifier as sename if empty seName = entity.Id.ToString(); }
please try it and if it doesn't follow your exact requirements I can add what you need...
So just how do you go about enabling hierarchical URL:s with this plugin?? Like the OP I'm interested in having URL:s like domain.com/category-name/product-name.
So just how do you go about enabling hierarchical URL:s with this plugin?? Like the OP I'm interested in having URL:s like domain.com/category-name/product-name.
Well, on a default installation with the sample data installed http://localhost/electronics/camera-photo/nikon-d5500-dslr takes you to the product.
during the test I did note that electronics/camera-photo didn't take me to the sub category so I'll look at that. but please do download and try it out, it works automagically.
This topic was automatically closed 365 days after the last reply. New replies are no longer allowed.