Skip to content

Conversation

@kjac
Copy link
Contributor

@kjac kjac commented Sep 15, 2025

Prerequisites

  • I have added steps to test this contribution in the description below

If there's an existing issue for this PR then this fixes #18475

Description

See the linked issue for a description. This PR fixes the issue.

As it turns out, this:

  • Applies to both link querystrings and anchors
  • Only applies to internal (local) links

Property naming

Although this fix applies to both querystrings and anchors, I have opted to call the new property QueryString to align with the ApiLink used by the multi URL picker to generate output for the Delivery API. For ApiLink, the QueryString property can also contain anchors.

Testing this PR

Make sure that both querystrings and anchor links are included for:

  • Internal (local) links
  • External links

Remember to test with:

  • Default RTE output
  • RTE output as JSON

@bjarnef
Copy link
Contributor

bjarnef commented Sep 15, 2025

@kjac an option may also be to split the hash into a Fragment property https://learn.microsoft.com/en-us/dotnet/api/system.uri.fragment?view=net-9.0

But currently both exist in the Querystring field in link picker, which is fine as long fragment is the last part (but I don't think there are specific validation for this at the moment).

Copy link
Contributor

@AndyButland AndyButland left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good from my perspective, apart from a small issue that needs resolving to avoid a binary breaking change (noted inline). Fine for me to merge once that is resolved, and when you have considered @bjarnef's feedback too.

Have tested with various links, with expected results:

As Markup:

<p>Test <a href=\"/test-landing/#test\" title=\"Test Landing\" data-anchor=\"#test\" data-start-item-path=\"home\" data-start-item-id=\"ac2038d9-dfc2-4294-b778-7edf90d1a178\">link</a>.</p>\n
<p>Test <a href=\"/?foo=bar\" title=\"Home\" data-anchor=\"?foo=bar\" data-start-item-path=\"home\" data-start-item-id=\"ac2038d9-dfc2-4294-b778-7edf90d1a178\">link 2</a>.</p>\n
<p>Test <a href=\"https://umbraco.com?foo=bar\" data-anchor=\"?foo=bar\">link 3</a>.</p>

As JSON:

"elements": [
    {
        "text": "Test ",
        "tag": "#text"
    },
    {
        "tag": "a",
        "attributes": {
            "anchor": "#test",
            "title": "Test Landing",
            "route": {
                "path": "/test-landing/",
                "queryString": "#test",
                "startItem": {
                    "id": "ac2038d9-dfc2-4294-b778-7edf90d1a178",
                    "path": "home"
                }
            }
        },
        "elements": [
            {
                "text": "link",
                "tag": "#text"
            }
        ]
    },
    {
        "text": ".",
        "tag": "#text"
    }
]
},
{
"tag": "p",
"attributes": {},
"elements": [
    {
        "text": "Test ",
        "tag": "#text"
    },
    {
        "tag": "a",
        "attributes": {
            "anchor": "?foo=bar",
            "title": "Home",
            "route": {
                "path": "/",
                "queryString": "?foo=bar",
                "startItem": {
                    "id": "ac2038d9-dfc2-4294-b778-7edf90d1a178",
                    "path": "home"
                }
            }
        },
        "elements": [
            {
                "text": "link 2",
                "tag": "#text"
            }
        ]
    },
    {
        "text": ".",
        "tag": "#text"
    }
]
},
{
"tag": "p",
"attributes": {},
"elements": [
    {
        "text": "Test ",
        "tag": "#text"
    },
    {
        "tag": "a",
        "attributes": {
            "href": "https://umbraco.com?foo=bar",
            "anchor": "?foo=bar"
        },
        "elements": [
            {
                "text": "link 3",
                "tag": "#text"
            }
        ]
    },
    {
        "text": ".",
        "tag": "#text"
    }
]
}
],

@kjac
Copy link
Contributor Author

kjac commented Sep 16, 2025

The link picker does indeed combine hash and querystring into the same field:

image

...and since ApiLink potentially also has both hash and querystring in the same field, I figure it makes sense to continue this logic.

@bjarnef
Copy link
Contributor

bjarnef commented Sep 16, 2025

Yes, technically hash isn't part of Uri class though IIRC.
Perhaps something to consider later. It can possible simplify frontend when having a mix of different types of link, but in our use-case we just parse the link in frontend meaning an arrow down icon when down to anchor on same page, otherwise an arrow right icon.

@kjac kjac merged commit a282002 into v13/dev Sep 16, 2025
19 checks passed
@kjac kjac deleted the v13/bugfix/18475-locallinks-parsing branch September 16, 2025 06:25
kjac added a commit that referenced this pull request Sep 16, 2025
…#20142)

* Support querystring and anchor for local links in Delivery API output

* Add default implementation for backwards compat

* Add default implementation for backwards compat (also on the interface)

* Fix default implementation
@kjac kjac mentioned this pull request Sep 16, 2025
1 task
kjac added a commit that referenced this pull request Sep 16, 2025
* Support querystring and anchor for local links in Delivery API output (#20142)

* Support querystring and anchor for local links in Delivery API output

* Add default implementation for backwards compat

* Add default implementation for backwards compat (also on the interface)

* Fix default implementation

* Add extra tests proving that querystring/postfix can be handled for local links in both legacy and current format.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants