Skip to content

Link Control: Disallow underscores in TLD-like validation - #74247

Open
SirLouen wants to merge 2 commits into
WordPress:trunkfrom
SirLouen:fix/is-url-like-no-underscores
Open

SirLouen wants to merge 2 commits into
WordPress:trunkfrom
SirLouen:fix/is-url-like-no-underscores

Conversation

@SirLouen

@SirLouen SirLouen commented Dec 29, 2025 •

Copy link
Copy Markdown
Member

What?

Disallow underscore from domains

Why?

According to RFC 1035 (Section 3.5) and RFC 1123 (2.1) domains and TLD should not contain underscores

How?

Introduce two checks, early returning while preserving the same format, to avoid parsing when underscores are present on the string.

Unit tests have been modified accordingly.

PS: I've also added an equivalent for Core that happens not to be checking also

Testing Instructions

There are Unit Tests in place. But this can be tested by registeing a Link Control component and passing a domain with underscores.

To test this easily do the following

  1. Create a new post
  2. Add a paragraph
  3. Add two links
  • In the first link use a valid URL: https://example.com
  • In the second link use an invalid URL: https://example_com.com <-- Note that Github doesn't auto-anchor it because it's invalid :)

Click on each link. You will see that the valid one has an icon, while the invalid one doesnt have it.

Note: Test adding underscores anywhere else, try with different patterns.

Screenshots

Valid:
image

Invalid

Before After
image image

@SirLouen
SirLouen requested a review from getdave as a code owner December 29, 2025 01:34
@github-actions

github-actions Bot commented Dec 29, 2025 •

Copy link
Copy Markdown

The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the props-bot label.

If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message.

Co-authored-by: SirLouen <sirlouen@git.wordpress.org>
Co-authored-by: getdave <get_dave@git.wordpress.org>

To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook.

@github-actions github-actions Bot added the [Package] Block editor /packages/block-editor label Dec 29, 2025
@SirLouen SirLouen added [Package] Components /packages/components [Feature] Link Editing Link components (LinkControl, URLInput) and integrations (RichText link formatting) [Package] Editor /packages/editor and removed [Package] Components /packages/components labels Dec 29, 2025
@SirLouen SirLouen self-assigned this Dec 29, 2025
@SirLouen SirLouen added the [Type] Bug An existing feature does not function as intended label Dec 29, 2025

@getdave getdave left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thank you for the PR and fixes. I have one question to ensure we are covering internal anchor links.

Comment on lines +24 to +30
// Underscores are not allowed in domain names (RFC 1035).
const hasUnderscores = val.includes( '_' );

if ( hasUnderscores ) {
return false;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

As isUrlLike is a loose check, I think we might want to move the underscore check to after the check for isInternal. I'm assuming _ is valid for internal anchors but I could be wrong.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

If I'm correct then we should add test coverage for internal anchors that contain underscores.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

In fact we have been discussing this in Core, and there is one caveat we should consider:

It's very rare, but since DNS have control over subdomains it could exist something like:

https://this_is_an.example.com

Despite of not being compliant, it could technically exist, and there are ancient sites in blogspot with this format

So we have to account for this. We can only care about protocol, domain and tld, but not the full fqdn.

Also there should be more checks not only underscore., I'm going to raise the level of testing.

@SirLouen
SirLouen force-pushed the fix/is-url-like-no-underscores branch from 0d46c4c to e00ce83 Compare January 10, 2026 00:04
@github-actions github-actions Bot removed the [Package] Editor /packages/editor label Jan 10, 2026
@SirLouen
SirLouen requested a review from getdave January 10, 2026 00:05

@getdave getdave left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thanks for continue to iterate on this. Having considered in more detail, I have some UX concerns about the strictness of this approach that I'd like to discuss.

Context: Intent Detection vs Validation

I'm currently working on PR #73486, which adds strict URL validation to LinkControl at submission. This will block invalid URLs and show clear error messages before links are saved.

Given that context, I think we need to reconsider the strictness here, as isURLLike serves a different purpose: determining user intent rather than validation.

How isURLLike Affects UX

The function determines whether to:

  • Show globe icon and treat input as URL entry (true)
  • Search for Posts/Pages and show "Create new page" (false)

This makes it crucial that it correctly interprets what users are trying to do.

The Problem

The current implementation applies strict RFC validation for intent detection, which creates scenarios that might be confusing (although I'd value your perspective):

Example: User types http://example_test.com

  • User has explicitly typed http:// - intent is unambiguous
  • Current PR returns false (underscore in domain)
  • LinkControl searches for Posts/Pages instead
  • User sees "Create new page" rather than globe icon
  • Confusing: "I typed a URL with http://, why is it searching?"

The user clearly intended to enter a URL but never reaches the validation that would give helpful feedback.

Recommendation

Since strict validation is coming in PR #73486, should we keep isURLLike focused on intent detection:

1. Trust explicit protocols

if ( protocolIsValid ) {
    return true; // User typed a protocol, trust their intent
}

2. Use simpler TLD detection

// Just check for: dot + 2-10 letters + (end or slash)
const regex = /\.[a-zA-Z]{2,10}(?:\/|:|$)/;

Flow with this approach:

  • http://example_test.com → Recognised as URL intent → User submits → Validation error (clear)
  • example_test.com → Recognised as URL intent → User submits → Validation error
  • my blog post → Searches Posts/Pages
  • example (no TLD) → Searches Posts/Pages

3. Your subdomain logic is good - perhaps it would be useful in the validation PR instead?

Re: Internal Anchors with Underscores

Thanks for updating this 👍 Adding test coverage would still be valuable:

it( 'returns true for internal anchor links with underscores', () => {
    expect( isURLLike( '#my_section_name' ) ).toBe( true );
} );

Summary

My concern is about applying strict validation at the intent detection layer rather than at submission. The validation logic itself is solid - it's just about using it at the right point in the user journey.

What do you think? I'd value your perspective as I may have missed something.

@SirLouen

Copy link
Copy Markdown
Member Author

@getdave got you. I'm going to review based on that perspective.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

[Feature] Link Editing Link components (LinkControl, URLInput) and integrations (RichText link formatting) [Package] Block editor /packages/block-editor [Type] Bug An existing feature does not function as intended

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants