Copied to clipboard

Flag this post as spam?

This post will be reported to the moderators as potential spam to be looked at


  • Pedro Tavares 10 posts 90 karma points c-trib
    Jan 05, 2016 @ 16:43
    Pedro Tavares
    0

    Path to product URL

    Hi,

    I have a section on the website for listing categories and subcategories of products.

    The subcategories have a merchello product list view and at this point the products are listed with the url "mywebsite.com/products/category/subcategory".

    When I click on a product the url points to "mywebsite.com/product".

    Is there any way to change this?

  • Rusty Swayne 1655 posts 4993 karma points c-trib
    Jan 05, 2016 @ 17:17
    Rusty Swayne
    100

    There are a few ways -

    In the merchello.config you can define the route by culture:

    <contentFinderCulture>
    <!-- You can set slug prefixes for products for each culture if you need to.
    e.g. with the following settings, en-US product URLs will be /en/[slug]
    <route cultureName="en-US" productSlugPrefix="en" />
    -->
    </contentFinderCulture>
    

    Or in the back office per product you can change the slug...

    Change the slug to something like products/avacodobar

    If you need something more sophisticated, you could write your own content finder based on the slug and not use the one that ships with Merchello.

    Merchello's content finder of reference:

    https://github.com/Merchello/Merchello/blob/merchello-dev/src/Merchello.Web/Routing/ContentFinderProductBySlug.cs

    Umbraco docs for IContentFinder:

    https://our.umbraco.org/documentation/Reference/Routing/Request-Pipeline/IContentFinder

  • Pedro Tavares 10 posts 90 karma points c-trib
    Jan 05, 2016 @ 17:55
    Pedro Tavares
    2

    Great.

    I was able to create a custom content finder and now the URL looks like "mywebsite.com/products/category/subcategory/product".

    Thanks!

  • Markus Johansson 1936 posts 5864 karma points MVP 2x c-trib
    Apr 22, 2016 @ 12:51
    Markus Johansson
    0

    After adding a new contentFinderCulture i get a 404 when going to the page.

    The url to the product is changed from /product

    /products/product

    but that page returns a 404... :/

  • Markus Johansson 1936 posts 5864 karma points MVP 2x c-trib
    Apr 22, 2016 @ 12:55
    Markus Johansson
    0

    Never mind!

    Turns out i had a different language selected in "culture and hostnames" which made the slug wrong.

  • Simon 692 posts 1068 karma points
    Aug 18, 2016 @ 13:26
    Simon
    0

    Hi Rusty,

    How can I disable the Merchello content finder, because I have created a new one for products and is throwing the same error

    Parent must be set in order to recurse
    
    Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code. 
    
    Exception Details: System.NotSupportedException: Parent must be set in order to recurse
    
    Source Error: 
    

    I am registering my content finder on OnApplicationStarting

    Appreciate any help.

  • skp 12 posts 80 karma points
    Dec 19, 2018 @ 14:52
    skp
    0

    Hi Pedro ,

    Could you please help me, I am also trying to do this but it fails, could you please guide me.

  • Miguel Lopez 15 posts 117 karma points
    Apr 28, 2016 @ 09:48
    Miguel Lopez
    0

    Hi Pedro,

    I am struggling with the same issue as you.

    Would it be possible to get a glance at your custom content finder?

    Many Thanks,

    Miguel L.

  • Remko 118 posts 283 karma points
    Jul 14, 2016 @ 12:05
    Remko
    0

    Could anyone who has made their own ProductFinder with SEO friendly urls, please post their code over here? Would help me, and propably many others in getting the urls for products right.

    Thanks!

  • Matt 91 posts 237 karma points
    Aug 03, 2016 @ 08:01
    Matt
    0

    Bumping this post - could anyone please share their custom content finders for category URLs?

  • Tony 105 posts 163 karma points
    Aug 16, 2016 @ 20:13
    Tony
    0

    Bumpity Bump.

  • Robin Hansen 135 posts 368 karma points
    Sep 14, 2016 @ 09:26
    Robin Hansen
    0

    Plz share--- I need it too... :-)

  • Sam Gooch 24 posts 116 karma points
    Sep 28, 2017 @ 22:05
    Sam Gooch
    0

    Bump

  • Dossie Wossie 7 posts 100 karma points
    Oct 02, 2017 @ 19:29
    Dossie Wossie
    0

    Currently, Ive been building my first merchello site, and i`ve also encountered this problem.

    You need to append logic to an existing class which extends ApplicationEventHandler, or create one if you dont have one yet.

    using Merchello.Core.Models;
    using Merchello.Core.Services;
    using Merchello.Web.Routing;
    using Umbraco.Core;
    using Umbraco.Core.Events;
    using Umbraco.Core.Logging;
    using Umbraco.Web.Routing;
    namespace myNameSpace
    {
    public class CustomApplicationEventHandler : ApplicationEventHandler
        {
            protected override void ApplicationStarting(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext)
            {
                this.RegisterContentFinders();
            }
    
            // contentfinder
            /// <summary>
            /// Registers Custom Merchello content finder.
            /// </summary>
            private void RegisterContentFinders()
            {
                var types = ContentFinderResolver.Current.GetTypes();
                var UmbcontentFinderByIdPathIndex = ContentFinderResolver.Current.GetTypes().IndexOf(typeof(ContentFinderByIdPath));
                ContentFinderResolver.Current.RemoveType<ContentFinderProductBySlug>();
                UmbcontentFinderByIdPathIndex = ContentFinderResolver.Current.GetTypes().IndexOf(typeof(ContentFinderByIdPath));
                ContentFinderResolver.Current.InsertType<MYCUSTOMCONTENTFINDER>(UmbcontentFinderByIdPathIndex + 1);
            }           
    
        }
    }
    
  • Brendan Rokebrand 7 posts 131 karma points
    Oct 25, 2017 @ 08:31
    Brendan Rokebrand
    1

    HI Guys

    I thought I'd share my content finders with you as you're asking, there are 3, one for brands, one for products (with categories) and one for members, this code never went into production, but was working before we went with a different approach. Some of the member content finder was code found through this forum.

    I would not say that this is the correct way to do this, but I managed to get it to work.

    I hope this helps someone

    using System;
    using System.Linq;
    using System.Web;
    using umbraco.cms.businesslogic.member;
    using umbraco.cms.businesslogic.web;
    using Umbraco.Core;
    using Umbraco.Core.Logging;
    using Umbraco.Web;
    using Umbraco.Web.Routing;
    using WG2K.Classes;
    
    namespace MySite.BusinessLogic
    {
    
        public class MyContentFinder : IContentFinder
        {
            public bool TryFindContent(PublishedContentRequest request)
            {
    
                var path = request.Uri.GetAbsolutePathDecoded();
                var urlParts = path.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
    
                if (urlParts.Length > 3 && urlParts[1].ToLower() == "brands")
                {
                    var language = urlParts[0];
                    var categoryName = urlParts[2];
                    var brandName = urlParts[3];
                    var contentCache = UmbracoContext.Current.ContentCache;
                    //var brandParent = contentCache.GetById(4385);
                    string currentDomain = HttpContext.Current.Request.ServerVariables["SERVER_NAME"];
                    int rootNodeID = Domain.GetRootFromDomain(currentDomain);
                    if (rootNodeID == -1) return false;
                    var siteName = Utils.FriendlyName(contentCache.GetById(rootNodeID).Name);
                    var siteProductsNode = UmbracoContext.Current.ContentCache.GetByRoute("/" + siteName + "/" + language + "/brands/brand-builder", true);
                    var brandParent = siteProductsNode.AncestorOrSelf(1).Children.Where(x => x.DocumentTypeAlias == "WG2K_Starter_Data").FirstOrDefault().Children.Where(x => x.DocumentTypeAlias == "ProductBrandList").FirstOrDefault();
    
                    var brand = brandParent.Children.SingleOrDefault(x => Utils.FriendlyName(x.Name) == brandName && x.HasProperty("brandCategory") && Utils.FriendlyName(contentCache.GetById(Int32.Parse(x.GetProperty("brandCategory").Value.ToString())).Name) == categoryName);
                    if (brandParent == null) return false; // not found
                    HttpContext.Current.Items["currentBrand"] = brand;
                    HttpContext.Current.Items["brandName"] = brand.Name;
                    request.PublishedContent = siteProductsNode;
                    return true;
                }
    
                if (urlParts.Length > 3 && urlParts[1].ToLower() == "products")
                {
                    var language = urlParts[0];
                    var categoryName = urlParts[2];
                    var productName = urlParts[3];
                    var contentCache = UmbracoContext.Current.ContentCache;
                    //var productParent = contentCache.GetById(4385);
                    string currentDomain = HttpContext.Current.Request.ServerVariables["SERVER_NAME"];
                    int rootNodeID = Domain.GetRootFromDomain(currentDomain);
                    if (rootNodeID == -1) return false;
                    var siteName = Utils.FriendlyName(contentCache.GetById(rootNodeID).Name);
                    var siteProductsNode = UmbracoContext.Current.ContentCache.GetByRoute("/" + siteName + "/" + language + "/products/product-builder", true);
                    var productParent = siteProductsNode.AncestorOrSelf(1).Children.Where(x => x.DocumentTypeAlias == "WG2K_Starter_Data").FirstOrDefault().Children.Where(x => x.DocumentTypeAlias == "sharedProductList").FirstOrDefault();
    
                    var product = productParent.Children.SingleOrDefault(x => Utils.FriendlyName(x.Name) == productName && x.HasProperty("productCategory") && Utils.FriendlyName(contentCache.GetById(Int32.Parse(x.GetProperty("productCategory").Value.ToString())).Name) == categoryName);
                    if (productParent == null) return false; // not found
                    HttpContext.Current.Items["currentProduct"] = product;
                    HttpContext.Current.Items["productName"] = product.Name;
                    request.PublishedContent = siteProductsNode;
                    return true;
                }
    
                return false;
            }
        }
    
        public class MemberProfileContentFinder : IContentFinder
        {
            public bool TryFindContent(PublishedContentRequest contentRequest)
            {
                var urlParts = contentRequest.Uri.GetAbsolutePathDecoded().Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
    
                //Check if the Url Parts
                // Starts with /member/*
                if (urlParts.Length > 1 && urlParts[1].ToLower() == "member")
                {
                    //Lets try & find the member
                    var categoryName = urlParts[2];
                    var productName = urlParts[3];
                    var memberName = urlParts[1];
                    LogHelper.Info(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType, "this is the host " + urlParts[1]);
                    //Try and find a member where the property matches the memberName
                    var tryFindMember = Member.GetAll.SingleOrDefault(x => Utils.FriendlyName(x.getProperty("_firstName").Value.ToString()) + "-" + Utils.FriendlyName(x.getProperty("_surname").Value.ToString()) == memberName);
    
                    //var tryFindContent = Content.GetAll
    
                    //Need to set the member ID or pass member object to published content
                    //Will pass a null to view if not found & can display not found member message
                    HttpContext.Current.Items["memberProfile"] = tryFindMember;
    
                    //Add in string to items - for profile name user was looking for
                    HttpContext.Current.Items["memberName"] = memberName;
    
                    //Set the Published Content Node to be the /Profile node - can get properties off it & my member profile in the view
                    contentRequest.PublishedContent = contentRequest.RoutingContext.UmbracoContext.ContentCache.GetByRoute("/contributors/newcontibutorpage/");
    
                    //Return true to say found something & stop pipeline & other contentFinder's from running
                    return true;
                }
    
                //Not found any content node to display/match - so run next ContentFinder in Pipeline
                return false;
            }
        }
    }
    

    Also used a utility to format the url, that is used in here

    public static string FriendlyName(string phrase)
            {
                string str = phrase.ToLower();
    
                // invalid chars, make into spaces
                str = Regex.Replace(str, @"[^a-z0-9\s-]", "");
                // convert multiple spaces/hyphens into one space
                str = Regex.Replace(str, @"[\s-]+", " ").Trim();
                // hyphens
                str = Regex.Replace(str, @"\s", "-");
    
                return str;
            }
    
  • Dhanesh Kumar MJ 165 posts 521 karma points MVP c-trib
    Dec 27, 2018 @ 05:05
    Dhanesh Kumar MJ
    1

    Hey Guys,

    We can Achieve this simply ,please go through this

    1. Create a Class file with any name ExampleFinder.cs

    2. Paste the code

    
        public class ExampleFinder: IContentFinder
            {
                public bool TryFindContent(PublishedContentRequest request)
                {
                    var merchelloHelper = new MerchelloHelper();
                    //  var slug = request.Uri.AbsolutePath.TrimStart('/');// EnsureNotStartsOrEndsWith('/');
                    var currentCulture=Thread.CurrentThread.CurrentCulture.Name;
                    var path = request.Uri.GetAbsolutePathDecoded();
                    var urlParts = path.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
                   var productSlug= urlParts[urlParts.Length - 1];
                    var productContent = merchelloHelper.TypedProductContentBySlug(productSlug);
                    if (productContent == null) return false;
                   var urlList= urlParts.Where(x => x != productSlug).Select(x => x).ToList();
                   var url= "/"+  String.Join("/", urlList);
                    var content = umbraco.uQuery.GetNodeByUrl(url);
                    // var content = UmbracoContext.Current.ContentCache.GetByRoute(url);
                    if (content != null)
                    {
                        request.PublishedContent = productContent;
                        return true;
                    }
                    return false; 
                } 
     }
    

    3.) Add the missing references to your project.

    4.) Create a Event handler by Inheriting the Umbraco Event Handler

    5.) Paste the code.

    public class CustomApplicationEventHandler : ApplicationEventHandler
        {
            protected override void ApplicationStarting(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext)
            {
                this.RegisterContentFinders();
    
            }
            private void RegisterContentFinders()
            {
                var types = ContentFinderResolver.Current.GetTypes();
                var UmbcontentFinderByIdPathIndex = ContentFinderResolver.Current.GetTypes().IndexOf(typeof(ContentFinderByIdPath));
              ContentFinderResolver.Current.RemoveType <ContentFinderProductBySlug>();
                UmbcontentFinderByIdPathIndex = ContentFinderResolver.Current.GetTypes().IndexOf(typeof(ContentFinderByIdPath));
    //Register our content finder class here 
                ContentFinderResolver.Current.InsertType<ExampleFinder>(UmbcontentFinderByIdPathIndex + 1);
            } }
    

    6.) Add missing references.

    7.) Buid and Run.

    This is Work's fine for me ,thank you !

  • Bhanu 2 posts 72 karma points
    Jun 14, 2024 @ 09:14
    Bhanu
    0

    Hello Guys,

    I want my product open using my custom URL. The current product URL name is for example "Test", and the URL is like that https://website/test/ but I want the product to open my custom URL, like https://website/products/test/ and https://website/products/categoryname/test/

    as I created a text string in document type products URL alias, and I add "/products/test/" and "/products/categoryname/test/"

    Please check the screenshot and Please guide me step by step enter image description here

Please Sign in or register to post replies

Write your reply to:

Draft