Product Url with Category name in the URL - NopCommerce 3.7

3 years ago
I need that product url look like

site.com\notebook\apple710
site.com\notebook\small\asus800

site\category1\category2\..\productName

How i can do it?

Thank for any advice.
3 years ago
vlakur1 wrote:
I need that product url look like

site.com\notebook\apple710
site.com\notebook\small\asus800

site\category1\category2\..\productName

How i can do it?

Thank for any advice.


I  think you can't do that in default nop. You will need to source code customize ... write your own route
3 years ago
Why nopCommerce don't do it from box?
Structured URL is a necessary condition for good SEO.

If site don't like Google - the site does not need anyone!

Is anybody who have some solution this problem, or any suggestions how to solve it?

Thank for all.
3 years ago
nopCommerce includes everything you need for search engine optimization: Search engine optimization

Moreover, the product may belong to several categories.
3 years ago
It's all good!

But nopcommerce can not build structured URL using category path in product URL, isn't it?...

it worried me...

Thank...
3 years ago
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)
        {


            routes.MapGenericPathRoute("AllUrls1",
                "{*generic_se_name}",
                new { controller = "Common", action = "GenericUrl" },
                new[] { "Nop.Web.Controllers" });

......... 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;

            }

            //Type typeEntity = System.Data.Objects.ObjectContext.GetObjectType(entity.GetType());
            string entityName1 = typeof(T).Name;

            List<String> seoNamesList = new List<String>();

            if (!String.IsNullOrWhiteSpace(seName) && ((entityName1 == "Category") || (entityName1 == "Product")))
            {
                //if (typeEntity.BaseType.Name == "Product")

                //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>();

                while (category != null && //not null
                    !alreadyProcessedCategoryIds.Contains(category.Id)) //prevent circular references
                {
                    categList.Add(category);
                    String strFullCatSeoName = urlRecordService1.GetActiveSlug(category.Id, "Category", 0);
                    if (!String.IsNullOrWhiteSpace(strFullCatSeoName))
                    {
                        //SEO name category
                        String catSEOName = strFullCatSeoName.Split(new char[] { '/' })[strFullCatSeoName.Split(new char[] { '/' }).Length - 1];
                        seoNamesList.Add(catSEOName);
                    }
                    //categListSeoNames.Add(urlRecordService1.GetActiveSlug(category.Id, "Category", 0));
                    alreadyProcessedCategoryIds.Add(category.Id);
                    category = catServiceaa.GetCategoryById(category.ParentCategoryId);
                }
                //categList.Reverse();
                seoNamesList.Reverse();
            }

            //seName = seName.Remove(0, seName.LastIndexOf('/'));

            //validation
            seName = GetSeName(seName);

            //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();
                }
3 years ago
Content Management Plugin has support for hierarchical urls.

https://www.nopcommerce.com/p/2195/content-management-plugin.aspx

please try it and if it doesn't follow your exact requirements I can add what you need...
3 years ago
vlakur1 wrote:
It's all good!

But nopcommerce can not build structured URL using category path in product URL, isn't it?...

it worried me...

Thank...


Why would you need it anyway. The more complex architecture, the worse apt pagerank will reach your site. So try not to do that.

https://moz.com/community/q/flat-vs-hierarchical-url-structure
3 years ago
marc wrote:
Content Management Plugin has support for hierarchical urls.

https://www.nopcommerce.com/p/2195/content-management-plugin.aspx

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.
3 years ago
ludsjo-c9 wrote:

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.