Problem/Motivation

LinkWidget error messages only make suggestions appropriate for internal paths. If a user is attempting to enter an external path, then the messages may be confusing.

Steps to reproduce

  1. Add a Link field to any content type. Set the "Allowed link type" setting to "External links only".
  2. Attempt to create a new instance of the content. Enter an invalid URL like invalid://not-a-valid-protocol in your link field and submit the form.
  3. Note that the field error message is "The path '@uri' is invalid."
  4. Change the link field's "Allowed link type" setting to "Both internal and external links".
  5. Attempt to create a new instance of the content. Enter an invalid URL like www.example.com in your link field and submit the form.
  6. Note that the field error message is "Manually entered paths should start with /, ? or #."

Proposed resolution

Add different error messages meaningful to each link type.

Remaining tasks

Review and feedback.

User interface changes

Internal widget

Before:
The internal widget's error message before the change
After:
The internal widget's error message after the change

External widget

Before:
The external widget's error message before the change
After:
The external widget's error message after the change

Internal/External widget

Before:
The generic widget's error message before the change
After:
The generic widget's error message after the change
\

API changes

Data model changes

Issue fork drupal-2828556

Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Comments

gambry created an issue. See original summary.

gambry’s picture

Title: External link gets Internal link validation error message if recognize as internal » External type link gets Internal type validation error message if recognize as internal
gambry’s picture

gambry’s picture

Title: External type link gets Internal type validation error message if recognize as internal » External type link gets Internal type validation error message if recognized as internal
gambry’s picture

Issue summary: View changes
gambry’s picture

Status: Active » Postponed

This issue is actually postponed until #2613694: Expose link_type on LinkWidget element is committed.

Version: 8.2.x-dev » 8.3.x-dev

Drupal 8.2.6 was released on February 1, 2017 and is the final full bugfix release for the Drupal 8.2.x series. Drupal 8.2.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.3.0 on April 5, 2017. (Drupal 8.3.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.3.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.4.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

gambry’s picture

Version: 8.3.x-dev » 8.4.x-dev
Status: Postponed » Active

I'm targeting this 8.4.x as #2613694: Expose link_type on LinkWidget element got committed only on that branch.

gambry’s picture

Status: Active » Needs review
StatusFileSize
new760 bytes
new2.63 KB

The last submitted patch, 9: external_type_link_gets-2828556-9--test-only.patch, failed testing.

wturrell’s picture

I was able to reproduce the bug in Safari and the patch fixes it as described.

Note Opera and Chrome won't let you get this far… you get a browser-generated "Please enter a URL" popup if you don't use an http(s):// prefix, even if begins "www." (can be disabled with formnovalidate attribute)

I'm wondering if we could be making it easier for users - e.g. a default http:// placeholder (though that could cause confusion with https://) or maybe simply a better error message than:

The path 'www.example.com' is invalid.

Something like:

URLs should begin http:// or https://

(Any Help text the site builder chooses to add is displayed separately to the "This must be an external URL such as..." message.)

gambry’s picture

@wturrell thank you very much for testing this!

I'm wondering if we could be making it easier for users - e.g. a default http:// placeholder

Although I understand your suggestion, this could be problematic. The input URL accept a full URL, without protocol schema dependencies. So ftp:// , mysql:// are valid URL and suggesting a specific one from Drupal core will create more problems than the ones we try to fix.

The developer and contrib modules can prefix the input field and additionaly specify a validation regexp pattern for targeting their specific scenarios.

or maybe simply a better error message than: The path 'www.example.com' is invalid.

Yeah, may be this is a solution. But worth opening a follow up task/feature request for that, as this bug report patch is trying to make the field behaviours consistent.

gambry’s picture

Issue summary: View changes
mac_weber’s picture

Assigned: Unassigned » mac_weber
Issue summary: View changes
Status: Needs review » Needs work
+++ b/core/modules/link/src/Plugin/Field/FieldWidget/LinkWidget.php
@@ -133,13 +134,16 @@ public static function validateUriElement($element, FormStateInterface $form_sta
+    if ($element['#link_type'] !== LinkItem::LINK_EXTERNAL && parse_url($uri, PHP_URL_SCHEME) === 'internal') {

Here you disabled this validation for external links, so it will display a different error message.

+++ b/core/modules/link/src/Tests/LinkFieldTest.php
@@ -163,6 +163,8 @@ public function testURLValidation() {
+    // Missing protocol schema.

The test fails because it is using the wrong error message, as you had disabled the external links form validation. It will work if you use $validation_error_2, the string from constraints validation. Moreover, this test is already covered by the invalid URL 'no-leading-slash' => $validation_error_2,.

AFAIK, Drupal 8 only supports HTML5 browsers. @wturrell probably you are using an older version of Safari, as version 9.0 supports url field validation: https://html5test.com/compare/browser/safari-9.0.html#row-form.url

I understand that we need need to display meaningful messages to users, so I'm changing the issue as to display messages according to each field type.

mac_weber’s picture

Title: External type link gets Internal type validation error message if recognized as internal » Display meaninguful error messages according to the link type.
mac_weber’s picture

Assigned: mac_weber » Unassigned
Status: Needs work » Needs review
StatusFileSize
new5.86 KB
new5.65 KB
new8.25 KB

I'm adding a patch for tests with the same strings as the current version, so it should pass the tests.

There is the same tests patch with the corresponding strings as in the new code, this should pass only in the tests together with the new code.

This patch displays error messages based on the link type, as the original issue was about misleading users when the messages do not correspond to the same type.

The last submitted patch, 16: link-error_messages_by_link_type-2828556-16--test-only.patch, failed testing.

Status: Needs review » Needs work

The last submitted patch, 16: link-error_messages_by_link_type-2828556-16.patch, failed testing.

wturrell’s picture

@mac_weber - actually Safari 10.0.3 (El Capitan), but according to caniuse.com there's only partial form validation support due to a webkit bug.

I'm guessing browser form validation will always be disabled in the drivers Simpletest and Mink use? Can't find much written about it. It obviously makes manual testing a little slower (editing DOM each time to add novalidate attribute) - apparently there used to be a setting in chrome://flags/, but removed (presumably as no longer an experiment).

Anyway where I'm going with this is we could open a separate issue about improving the wording (#11/#12) but it may be a waste of time if it's a message increasingly few people will ever see, given it'll usually be intercepted by the browser. (i.e. I've no desire to hold this issue up.)

gambry’s picture

Hey @Mac_Weber, I don't quite get your feedbacks:

Here you disabled this validation for external links, so it will display a different error message.

That's exactly the problem. LINK_EXTERNAL types get LINK_INTERNAL/LINK_GENERIC validation message when they shouldn't.

If I use 'www.example.org' as value for an external link, the message shouldn't say "Manually entered paths should start with /, ? or #." if the user omits to input the scheme, i.e. using", as explained on the IS.

The test fails because it is using the wrong error message, as you had disabled the external links form validation.

Which test is failing? test-only patch fails because is the PoC with the test without the fix, while full patch passes the tests.

mac_weber’s picture

I opened a follow-up issue for the HTML5 message: #2861316: Display meaningful HTML5 validation error message

@wturrell you can get rid of the input type url in the file LinkWidget.php in the function formElement() by changing '#type' => 'url', to '#type' => 'textfield',

@gambry The constraint validation message is $message = "The path '@uri' is invalid.", which could lead to another similar issue being opened to get a more meaningful message to end users. I think we better fix and improve all 3 link type messages in this issue.

I see the test failed on testURLValidation while it is passing on my local machine. I will mark it to re-test.

gambry’s picture

which could lead to another similar issue being opened to get a more meaningful message to end users. I think we better fix and improve all 3 link type messages in this issue.

Totally makes sense!
Thanks.

mac_weber’s picture

Status: Needs work » Needs review
StatusFileSize
new8.43 KB
new3.18 KB

Fixed the patch to avoid the "uninitialized string offset" error.

Status: Needs review » Needs work

The last submitted patch, 23: link-error_messages_by_link_type-2828556-23.patch, failed testing.

mac_weber’s picture

Status: Needs work » Needs review
StatusFileSize
new8.47 KB

I had forgotten to rebase.

Status: Needs review » Needs work

The last submitted patch, 25: link-error_messages_by_link_type-2828556-25.patch, failed testing.

mac_weber’s picture

Status: Needs work » Needs review
StatusFileSize
new9.12 KB
new663 bytes

Added one more string from the Menu Link module.

gambry’s picture

Status: Needs review » Needs work
Issue tags: +drupaldevdays, +DevDaysSeville
  1. +++ b/core/modules/link/src/Plugin/Field/FieldWidget/LinkWidget.php
    @@ -7,6 +7,7 @@
    +use Drupal\link\Plugin\Field\FieldType\LinkItem;
    

    This use statement is not used and it raises a coding standard error.

  2. +++ b/core/modules/link/src/Plugin/Field/FieldWidget/LinkWidget.php
    @@ -133,13 +134,32 @@ public static function validateUriElement($element, FormStateInterface $form_sta
    +              break;
    ...
    +              break;
    

    Case breaking statement should be followed by a blank line.

  3. +++ b/core/modules/link/tests/src/Functional/LinkFieldTest.php
    @@ -139,38 +139,24 @@ public function testURLValidation() {
         // Test external and internal URLs for 'link_type' = LinkItemInterface::LINK_GENERIC.
    

    Although not modified by the patch, This comments goes over the 80chars limit. I would break it at "for".

  4. +++ b/core/modules/link/tests/src/Functional/LinkFieldTest.php
    @@ -178,7 +164,57 @@ public function testURLValidation() {
    +   *   The link type identifier, such as LinkItemInterface::LINK_GENERIC,
    

    Comma at the end of the line.

  5. +++ b/core/modules/link/tests/src/Functional/LinkFieldTest.php
    @@ -178,7 +164,57 @@ public function testURLValidation() {
    +        break;
    ...
    +        break;
    

    Same as above.

  6. +++ b/core/modules/link/tests/src/Functional/LinkFieldTest.php
    @@ -178,7 +164,57 @@ public function testURLValidation() {
    +        // Invalid protocol
    ...
    +        // Missing host name
    

    missing full stop.

  7. +++ b/core/modules/link/tests/src/Functional/LinkFieldTest.php
    @@ -178,7 +164,57 @@ public function testURLValidation() {
    +      ]
    

    Missing comma at the end of array item.

Worth mentioning:

  • When submitting /test/path on a LINK_EXTERNAL I get 'The path '/test/path' is invalid.', so only LINK_EXTERNAL internal values matching !in_array($element['#value'][0], ['/', '?', '#'], TRUE) will get the new meaningful error message.
  • Probably just a local glitch but I managed to make my site critical due link widget plugin not loaded properly. Don't worry about this, I'll try reproduce and investigate.
juanjesustrigo’s picture

Assigned: Unassigned » juanjesustrigo

I'll work on this

juanjesustrigo’s picture

Status: Needs work » Needs review
StatusFileSize
new8.93 KB
new4.13 KB

I have fixed the seven points explained in the comment #28.

gambry’s picture

Assigned: juanjesustrigo » Unassigned
Status: Needs review » Reviewed & tested by the community

Looks good to me. Test is green, no CS issues. Thanks!

mac_weber’s picture

Thank you for the review and the patch fixing CS.

When submitting /test/path on a LINK_EXTERNAL I get 'The path '/test/path' is invalid.', so only LINK_EXTERNAL internal values matching !in_array($element['#value'][0], ['/', '?', '#'], TRUE) will get the new meaningful error message.

It will trigger the new message for external links in case of missing protocol, such as example.com. I thought about a different logic to also trigger this message in case of trying to use an internal link, but it would require other changes in the test file, which I think we better spend time after fully converting it to BrowserTestBase. In fact it just got converted between comments #24-#25, but it still needs to get rid of deprecated methods there and I think there is one part that needs a rewrite.

Then, I think we are good to commit this issue.

alexpott’s picture

Status: Reviewed & tested by the community » Needs work
  1. +++ b/core/modules/link/src/Plugin/Field/FieldWidget/LinkWidget.php
    @@ -133,13 +133,34 @@ public static function validateUriElement($element, FormStateInterface $form_sta
    -    // If getUserEnteredStringAsUri() mapped the entered value to a 'internal:'
    -    // URI , ensure the raw value begins with '/', '?' or '#'.
    -    // @todo '<front>' is valid input for BC reasons, may be removed by
    -    //   https://www.drupal.org/node/2421941
    -    if (parse_url($uri, PHP_URL_SCHEME) === 'internal' && !in_array($element['#value'][0], ['/', '?', '#'], TRUE) && substr($element['#value'], 0, 7) !== '<front>') {
    ...
    +    // Check if it is an internal link or an external link missing protocol.
    +    if (parse_url($uri, PHP_URL_SCHEME) === 'internal') {
    +
    +      // Ensure internal links raw value begins with with '/', '?' or '#'.
    +      if (!in_array($element['#value'][0], ['/', '?', '#'], TRUE)) {
    +
    +        // @todo '<front>' is valid input for BC reasons, may be removed by
    +        //   https://www.drupal.org/node/2421941
    +        if (substr($element['#value'], 0, 7) !== '<front>') {
    

    Changing this here makes a reviewer have to consider whether this change is part of the bugfix. As far as I can tell it's not. Also whether or not this makes the code more understandable is highly debatable. I don't think this change belongs here.

  2. +++ b/core/modules/link/src/Plugin/Field/FieldWidget/LinkWidget.php
    @@ -133,13 +133,34 @@ public static function validateUriElement($element, FormStateInterface $form_sta
    +              $error_message = 'External links must be a full URL and include its protocol, such as %link_example.';
    ...
    +              $error_message = 'Use a title of a piece of content to select it, or enter an internal path starting with /, ? or #.';
    ...
    +              $error_message = 'Use a title of a piece of content to select it, or enter an internal path starting with /, ? or #. External links must be a full URL and include its protocol, such as %link_example.';
    ...
    +          $form_state->setError($element, t($error_message, ['%link_example' => 'http://example.com']));
    

    This is not how t() works. We can't make the change like this because the translation extractor won't find the new strings. We need to put the t() inside the switch.

mac_weber’s picture

@alexpott 1. According to coding standards line length this should be split, not?

2. Yet now we should remove all t() from tests - not in this issue - there is a similar code in the tests already in core:

+++ b/core/modules/link/tests/src/Functional/LinkFieldTest.php
@@ -216,7 +255,7 @@ protected function assertInvalidEntries($field_name, array $invalid_entries) {
-      $this->assertText(t($error_message, ['@link_path' => $invalid_value]));
+      $this->assertText(t($error_message, ['@link_path' => $invalid_value, '@link_example' => 'http://example.com']));

Version: 8.4.x-dev » 8.5.x-dev

Drupal 8.4.0-alpha1 will be released the week of July 31, 2017, which means new developments and disruptive changes should now be targeted against the 8.5.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.5.x-dev » 8.6.x-dev

Drupal 8.5.0-alpha1 will be released the week of January 17, 2018, which means new developments and disruptive changes should now be targeted against the 8.6.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

kingdutch’s picture

Status: Needs work » Needs review

Putting this back to needs review. #34 provided some reasoning as a reply to the comments in #33. I would like to know what still needs doing for this issue to move it forward.

borisson_’s picture

Status: Needs review » Needs work

#34.1 While there might be a case for this, coding standards/documentation cleanup shouldn't be in the same issue as a bug fix. That just makes all of our lives harder. In this case - that means that this change needs to be reverted to the docs
#34.2 Yes there is already code like this in a test. But as far as I can see, the code that @alexpott quoted in #33 is not in a test.

So this doesn't have to change in the tests, there it's ok, it does have to change in the other, non-test code.

Back to needs work, let's make the docs the same again and let's see if we can keep the if-statement the same as well and let's change the t from #33.2 as well.

Version: 8.6.x-dev » 8.7.x-dev

Drupal 8.6.0-alpha1 will be released the week of July 16, 2018, which means new developments and disruptive changes should now be targeted against the 8.7.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.7.x-dev » 8.8.x-dev

Drupal 8.7.0-alpha1 will be released the week of March 11, 2019, which means new developments and disruptive changes should now be targeted against the 8.8.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.8.x-dev » 8.9.x-dev

Drupal 8.8.0-alpha1 will be released the week of October 14th, 2019, which means new developments and disruptive changes should now be targeted against the 8.9.x-dev branch. (Any changes to 8.9.x will also be committed to 9.0.x in preparation for Drupal 9’s release, but some changes like significant feature additions will be deferred to 9.1.x.). For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

Version: 8.9.x-dev » 9.1.x-dev

Drupal 8.9.0-beta1 was released on March 20, 2020. 8.9.x is the final, long-term support (LTS) minor release of Drupal 8, which means new developments and disruptive changes should now be targeted against the 9.1.x-dev branch. For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

Version: 9.1.x-dev » 9.2.x-dev

Drupal 9.1.0-alpha1 will be released the week of October 19, 2020, which means new developments and disruptive changes should now be targeted for the 9.2.x-dev branch. For more information see the Drupal 9 minor version schedule and the Allowed changes during the Drupal 9 release cycle.

Version: 9.2.x-dev » 9.3.x-dev

Drupal 9.2.0-alpha1 will be released the week of May 3, 2021, which means new developments and disruptive changes should now be targeted for the 9.3.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.3.x-dev » 9.4.x-dev

Drupal 9.3.0-rc1 was released on November 26, 2021, which means new developments and disruptive changes should now be targeted for the 9.4.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.4.x-dev » 9.5.x-dev

Drupal 9.4.0-alpha1 was released on May 6, 2022, which means new developments and disruptive changes should now be targeted for the 9.5.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.5.x-dev » 10.1.x-dev

Drupal 9.5.0-beta2 and Drupal 10.0.0-beta2 were released on September 29, 2022, which means new developments and disruptive changes should now be targeted for the 10.1.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 10.1.x-dev » 11.x-dev

Drupal core is moving towards using a “main” branch. As an interim step, a new 11.x branch has been opened, as Drupal.org infrastructure cannot currently fully support a branch named main. New developments and disruptive changes should now be targeted for the 11.x branch, which currently accepts only minor-version allowed changes. For more information, see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

cilefen’s picture

Title: Display meaninguful error messages according to the link type. » Display meaningful error messages according to the link type
fox mulder’s picture

d10 version of #30

dcam made their first commit to this issue’s fork.

dcam’s picture

Issue summary: View changes
Status: Needs work » Needs review
Issue tags: -drupaldevdays, -DevDaysSeville

I converted the patch in #50 to an MR, undid some of the code style changes, addressed the feedback in #33, and updated the IS.

dcam’s picture

Hiding patches.

smustgrave’s picture

Status: Needs review » Needs work
Issue tags: +Needs Review Queue Initiative, +Needs screenshots

Can we add screenshots of the new messages compared to the old please.

dcam’s picture

Issue summary: View changes
Status: Needs work » Needs review
Issue tags: -Needs screenshots
StatusFileSize
new4.09 KB
new4.82 KB
new6.55 KB
new6.15 KB
new4.87 KB
new7.47 KB

Added screenshots

philltran made their first commit to this issue’s fork.

philltran’s picture

Added a branch and MR based on Drupal core 11.2.x

needs-review-queue-bot’s picture

Status: Needs review » Needs work
StatusFileSize
new91 bytes

The Needs Review Queue Bot tested this issue. It no longer applies to Drupal core. Therefore, this issue status is now "Needs work".

This does not mean that the patch necessarily needs to be re-rolled or the MR rebased. Read the Issue Summary, the issue tags and the latest discussion here to determine what needs to be done.

Consult the Drupal Contributor Guide to find step-by-step guides for working with issues.

nod_’s picture

Status: Needs work » Needs review
smustgrave’s picture

Status: Needs review » Needs work

Appears to be 2 MRs now not sure what's up for review.

philltran’s picture

@smustgrave
I added a second Merge Request MR13480 based on 11.2.x . The other MR is based on 11.x. Sorry if this was incorrect. I created the branch as I needed a patch for my 11.2.x based site. Please let me know the proper workflow. Thanks.

dcam’s picture

Status: Needs work » Needs review

@philltran most people generate a patch file for the version and upload it to the issue rather than opening a new MR. There's nothing wrong with creating a new branch for that purpose, but as you've seen creating an MR from that branch results in confusion.

I'm going to hide your 11.2 branch in the issue UI so that it's clear which MR needs to be reviewed. This won't make your branch go away permanently. There's a link to show hidden branches below the branch list. So you can maintain it and keep it up to date if necessary.

dcam changed the visibility of the branch 2828556-11_2_x to hidden.

smustgrave’s picture

Yes no worries @philltran, so reviewing the changes and not 100% sure 'content title' is correct. What if I'm linking to a media or something else is that still "content"

dcam’s picture

...not 100% sure 'content title' is correct. What if I'm linking to a media or something else is that still "content"

I don't mind changing it. I don't love how it's worded anyway. But how do we say tell people to enter the title of a node when we aren't supposed to say "node" in the UI?

philltran’s picture

Yes, I normally do post patch files. All the patches were just hidden.... so I did not want to be that guy that added a new one. LOL.

How about instead of 'content title' , we say 'title of referenced item'. Is that to many words?

smustgrave’s picture

Or what about 'entity title' vs content

philltran’s picture

I think 'entity title' works well.

dcam’s picture

Or what about 'entity title' vs content

Except you can only reference nodes.

All the patches were just hidden...

@philltran When we create MRs on issues that have been around since the old patch days we hide the old patch files. I assume this is done mostly for the sake of de-cluttering the issue summary. And there are probably other benefits like making sure people are focusing on the right thing when working or reviewing. But if you have a new patch that was made for the sake of helping people who need a stable fix for something, then that's relevant content and you shouldn't worry about doing it.

philltran’s picture

@dcam Thanks for the words of wisdom.

smustgrave’s picture

Then maybe content works? Not sold on it but can’t think of anything new

smustgrave’s picture

Status: Needs review » Reviewed & tested by the community

I can't think of anything better and this is a net improvement.

catch’s picture

Status: Reviewed & tested by the community » Needs review

One question about the wording on the MR.

dcam’s picture

I made the suggested change.

smustgrave’s picture

Status: Needs review » Reviewed & tested by the community

Update LGTM

catch’s picture

Status: Reviewed & tested by the community » Fixed

Committed/pushed to 11.x, thanks!

Now that this issue is closed, review the contribution record.

As a contributor, attribute any organization that helped you, or if you volunteered your own time.

Maintainers, credit people who helped resolve this issue.

  • catch committed 45f43f34 on 11.x
    fix: #2828556 Display meaningful error messages according to the link...

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.