Omit nodes of a specific doctype from URL structure

Umbraco version: 15.3.1

I am trying to amend the URLs generated by Umbraco for content items. My intention is to omit nodes of a specific doctype from the URL structure - for example, if the default URL structure is “listing-page/contents/list-element” and the “contents” segment represents a node of type “List content”, I want the final URL to be “listing-page/list-element”.

I have implemented a custom IUrlSegmentProvider, which looks like the following:

    public class ListingContentUrlSegmentProvider : IUrlSegmentProvider
    {
        private const string ListContentDocumentType = ListContent.ModelTypeAlias;
    
        public string? GetUrlSegment(IContentBase content, string? culture = null)
        {
            if (content.ContentType.Alias.Equals(ListContentDocumentType))
            {
                return "";
            }
    
            return null;
        }
    }

This provider is then registered via a composer, and I can see the provider itself being executed if I place a breakpoint in Visual Studio.

When implemented like this, URLs are completely unaffected - they continue to use the default structure without omitting the “contents” node from the URL.

If I replace the empty string with anothe value, e.g. “xyzzy”, the following occurs:

  • After launching the site with the new URL segment provider, publishing the List content node results in a “The document does not have a URL, possibly due to a naming collision with another document. More details can be found under Info.” notification, and a “This document is published but its URL cannot be routed” message.
  • In addition to the above, the response from the “/umbraco/management/api/v1/document/urls” endpoint does not contain any elements in the “urlInfos” list.
  • Once the List content node is published, its children reflect the new URL structure defined by the segment provider (e.g. “listing-page/xyzzy/list-element”) and can also be reached at that URL, despite the routing error shown on the parent node.

Another thing I have noticedafter doing the above: if I restore the empty string to the segment provider, re-run the solution, then save & publish the “List content” node, the “This document is published but its URL cannot be routed” message disappears but the URL shown contains whatever the segment provider previously specified, i.e. “xyzzy”.

My question is, have I implemented this in the correct way, and if not, how can I achieve the desired behaviour? There is some suggestion that I need to have a custom content finder as well, but I’ve also read that if segments are the only part of the URL being affected, then these may not be necessary.

I think you’ll need to be on 15.4RC for this to work if I am understanding correctly, mostly based on what I get from this blog post from Andy Butland

EDIT: You may also need a custom IContentFinder to help resolve the URL for incoming requests

“It’s important to note here that since we’re changing the outbound URL, but not how we handle URLs inbound, this will break the routing. In order to make the routing work again you have to implement a custom content finder, see IContentFinder for more information on how to do that.”