FIXED Breadcrumb and Left Navigation for product in multiple categories

This topic was automatically closed 365 days after the last reply. New replies are no longer allowed.
11 years ago
I've looked through the forums for a solution to the problem where the category breadcrumb and category navigation will display the first assigned category for every category and haven't found a solution yet. I also understand the point of a.m. saying that many programs operate in the same manner and for most use cases of course the 80/20 (or 90/10 even) rule would apply. So I went ahead and wrote a solution my edge case.

The way I solved it was to add a method to the Catalog Controller (Presentation\Nop.Web\Controllers\CatalogController.cs) called GetReferringCategory which takes in the current Request object and a List<ProductCategory> and returns the referring Category.


private Category GetReferringCategory(string referringUrl, IList<ProductCategory> categories)
        {
            string[] referringUrlSplit = referringUrl.Split('/');
            if (referringUrlSplit.Length > 0)
            {
                for (int i = 0; i < referringUrlSplit.Length; i++)
                {
                    if (referringUrlSplit[i] == "c")
                    {
                        var referringCategoryId = Convert.ToInt32(referringUrlSplit[i + 1]);
                        var referringCategory = (from c in categories where c.CategoryId == referringCategoryId select c).ToList().First();
                        return referringCategory.Category;
                    }
                }
            }
            return categories[0].Category;
        }


In the two places in CategoryController.cs where the zero indexed category is referenced (CategoryNavigation and ProductBreadcrumb action), I passed the method value to the category variable.

var currentCategory = GetReferringCategory(Request.UrlReferrer.AbsolutePath, productCategories);

or
var category = GetReferringCategory(Request.UrlReferrer.AbsolutePath, productCategories);


One thing to note when doing this is the default cache value of 60 seconds. In order to see the changes immediately you would need to set the cache value to 0 for both of the child actions mentioned above (or wait a minute).

Something like this (it's the same change in both places):

var cacheModel = _cacheManager.Get(cacheKey, 0, () =>
                {
                  ...
                }

One last thing, I made this modification on version 2.3. I don't know how much if any adjustment will be needed for later versions.

Enjoy.
11 years ago
Worked perfectly for me in 2.65
11 years ago
That's great! I'm glad I could help you out.
11 years ago
Just noticed this does not work in scenarios where you come to product details page from other sources than category. e.g. If I am in product compare view and click on product details button. In such scenarios referringUrl does not contain category ID and hence referringUrl Split does on work due to missing 'c'.
10 years ago
Thanks for this. it is working in 2.8
9 years ago
Thanks for the solution. I do have one question though.

I am trying to implement this in Version 3.40 and when you make a reference to "In the two places in CategoryController.cs where the zero indexed category is referenced (CategoryNavigation and ProductBreadcrumb action), I passed the method value to the category variable."

Where exactly is the CategoryController.cs file? Does anyone have the solution for this to work in version 3.40?

Thanks in advance,

Lee
9 years ago
Just wanted to share my solution for version 3.40. I am only really concerned about the product page breadcrumbs linking back to whatever category the user came from and passing the querystring value that is used for paging, but only if necessary. Thanks jhollan3 for helping me get started with this.

Nop.Web\Controllers\ProductController.cs
========================================

Replaced the #region Breadcrumb with the following. Needed to disable caching...


#region Breadcrumb

            //do not prepare this model for the associated products. any it's not used
            if (_catalogSettings.CategoryBreadcrumbEnabled && !isAssociatedProduct)
            {
                var breadcrumbModel = new ProductDetailsModel.ProductBreadcrumbModel()
                {
                    Enabled = _catalogSettings.CategoryBreadcrumbEnabled,
                    ProductId = product.Id,
                    ProductName = product.GetLocalized(x => x.Name),
                    ProductSeName = product.GetSeName()
                };

                var productCategories = _categoryService.GetProductCategoriesByProductId(product.Id);
                if (productCategories.Count > 0)
                {
                    var category = productCategories[0].Category;
                    if (Request.ServerVariables["HTTP_REFERER"] != null) {category = GetReferringCategory(Request.UrlReferrer.AbsolutePath, productCategories);}
                    if (category != null)
                    {
                        foreach (var catBr in category.GetCategoryBreadCrumb(_categoryService, _aclService, _storeMappingService))
                        {
                            breadcrumbModel.CategoryBreadcrumb.Add(new CategorySimpleModel()
                            {
                                Id = catBr.Id,
                                Name = catBr.GetLocalized(x => x.Name),
                                SeName = catBr.GetSeName()
                            });
                        }
                    }
                }
                model.Breadcrumb = breadcrumbModel;

            }
            
#endregion


... Added this function to the same class file. Note this uses URLRecord table instead of parsing for URL for "c"...

#region Custom

        private Category GetReferringCategory(string referringUrl, IList<ProductCategory> categories)
        {
            string[] referringUrlSplit = referringUrl.Split('/');
            if (referringUrlSplit.Length > 0)
            {
                for (int i = 0; i < referringUrlSplit.Length; i++)
                {
                    if (referringUrlSplit[i].Length > 0)
                    {
                        var referringCategoryURL = referringUrlSplit[i];
                        var urlRecordService = Nop.Core.Infrastructure.EngineContext.Current.Resolve<IUrlRecordService>();
                        UrlRecord url = urlRecordService.GetBySlug(referringCategoryURL);
                        if (url != null)
                        {
                            if (url.EntityName.ToLower() == "category")
                            {
                                var referringCategory = (from c in categories where c.CategoryId == url.EntityId select c).ToList().First();
                                return referringCategory.Category;
                            }
                        }
                   }
                }
            }
            return categories[0].Category;
        }

#endregion


... Then modified the product breadcrumb view to attach referring querystring to url only when necessary.. following is the relevent code to replace on that file...

Nop.Web\Views\Product\_ProductBreadcrumb.cshtml
===============================================

@foreach (var category in Model.CategoryBreadcrumb)
{
    var modUrl = Url.RouteUrl("Category", new { SeName = category.SeName });
    if (Model.CategoryBreadcrumb.IndexOf(category) == Model.CategoryBreadcrumb.Count - 1)
    {
        if (Request.ServerVariables["HTTP_REFERER"] != null && Request.ServerVariables["HTTP_REFERER"].Contains("?"))
        {
            var querystring = Request.ServerVariables["HTTP_REFERER"].Substring(Request.ServerVariables["HTTP_REFERER"].IndexOf('?') + 1);
            modUrl += "?" + querystring;
        }
    }
    <li>
        <span itemscope itemtype="http://data-vocabulary.org/Breadcrumb">
            <a href="@modUrl" itemprop="url">
                <span itemprop="title">@category.Name</span>
            </a>
        </span>
        <span class="delimiter">@breadcrumbDelimiter</span>
    </li>
}


... that's it... Hope someone finds this userful :)
8 years ago
jholland3 wrote this fix for 2.x NC.  Then Izoumas posted his take on the issue for version 3.4.  The original code does not work with 3.5 and Izoumas' code addressed the breadcrumb issue, but not the navigation menu issue.  Has anyone resolved this issue to include the left navigation and breadcrumb links?

Your thoughts and insight are greatly appreciated.

JohnJ
8 years ago
For anyone's future reference, I resolved this issue in 3.5 by applying part of Izoumas' BreadCrumb fix to the CatalogController.  I wanted the highlighted category item in the left nav to match the last category displayed in the BreadCrumb.  This was accomplished by adding the #Custom region from Izoumas to the CatalogController and adding a reference to Nop.Core.Domain.Seo.  Then modify part of the [ChildActionOnly] section of the #Categories region as included below.  I'm certain there are more efficient methods to accomplish this, but this one works for me.  If anyone has another method, please let me know.

            if (currentCategoryId > 0)
            {
                //category details page
                activeCategoryId = currentCategoryId;
            }
            else if (currentProductId > 0)
            {
                //product details page
                var productCategories = _categoryService.GetProductCategoriesByProductId(currentProductId);
                if (productCategories.Count > 0)
                {
                    var category = productCategories[0].Category;
                    if (Request.ServerVariables["HTTP_REFERER"] != null) { category = GetReferringCategory(Request.UrlReferrer.AbsolutePath, productCategories); }
                    if (category != null)
                    {
                        foreach (var catBr in category.GetCategoryBreadCrumb(_categoryService, _aclService, _storeMappingService))
                        {
                            activeCategoryId = catBr.Id;
                        };
                    }
                }
            }
7 years ago
Does anyone know if the above code will also work with 3.7?

I'm having the same issue with our webstore, wherein if we have a product that is tied to multiple vehicle categories (for example, a universal product that fits every vehicle), then Nop will change the category from the current category to the first category listed in that products profile.

I tried adding the code suggested in previous posts but it still reverts to the first category listed.


Thanks!
This topic was automatically closed 365 days after the last reply. New replies are no longer allowed.