Currently the link module supports both internal and external URLs and I get that a lot of people use the module for internal links. Right now the storage for the field data supports both, but the default widget only support external URLs.

Plan A:

  • Decide we only want to support external URLs in the widget and change nothing. Leave internal URL widget for contrib.
  • Pros: Lowest complexity
  • Cons: Users may find out-of-the-box solution limiting.

Plan B:

  • Rename the current widget from 'URL field' to 'External URL field' and add a new 'Internal URL field' widget.
  • Pros: we support both, not too much extra code
  • Cons: this makes a specific instance only able to use one or the other and not mix.

Plan C:

  • Add an option on the field instance to have the administrator say if this field supports internal only, external only, or both. The default widget will change it's validation based on the options.
  • Pros: Able to mix/match. Seems better as a field instance setting, not a widget setting.
  • Cons: Most amount of complexity to add. Widget will not be able to support HTML5 'url' FAPI type if option is not 'external only' since the url field by nature only supports external fields.

Plan D:

  • Always use the FAPI 'url' type, and attempt to resolve what are 'local' URLs to un-aliased internal Drupal URLs.
  • Pros: Simplicity. We are able to handle both types with the same widget and use the new HTML5 FAPI type always.
  • Cons: Medium complexity.
  • How does this work for sites that have multiple domains (multisite or domain access) or SSL? Would we still want to add additional logic for 'Allow the following types of URLs: [X] Internal [X] External'?

Comments

Dave Reid’s picture

Maybe out next step is trying to figure out what rough percentage of use case there is for supporting internal URLs, and how they are used (mixed internal/external all in one field, etc).

Dave Reid’s picture

Component: Code » Miscellaneous
attiks’s picture

Use case for most of our clients: the can add banners and the banner entity has an entity reference field so they can refer to an internal page easily, and also a link field so they can enter a path to a non-entity page (like a view). We use a custom formatter that checks if the entity reference is filled, if not the link field is used as output.

I would be happy with just an external link field, only thing I need to change is the entity reference, so it can 'reference' menu items as well.

The problem with internal URL's is that once the path changes the field isn't updated, so you'll get a 404. Same problem in case of a typo.

So A > B, I would avoid C, because then you almost have a duplicate of the link module.

RobW’s picture

I think C would have the most value for site builders. It contains A and B, so any use case that they cover is covered by C, plus more.

I don't know how deep you want to get into validation and formatting/theming here. My wish list for an all in one link formatter would be:

  • Accepts internal and external links.
  • Allows per field restriction of only internal, only external, or both.
  • Recognized internal links, stores the non-aliased path, and outputs the aliased path when themed.
  • Lets us do preprocessing and theming tomfoolery by telling us if the link is internal or external in a theme var.
klonos’s picture

I believe that we can only assume things when it comes to concluding to a "rough percentage" of the most-common use case. Basing our decisions on such assumptions in general is plain wrong. We need to support most common use cases (both internal/external URLs in our case - no pun intended) if we can afford it.

On another somewhat related issue, perhaps if the field was set as internal-only, then it would make more sense to have it as an autocomplete by default. Only added complexity I see in this when it comes to implementation is that a) we need to account for admin URLs besides content URLs and also user permissions and b) we perhaps need to (optionally) allow the auto-complete to accept non-existing (yet) URLs. Allowing this autocomplete field to accept non-existing URLs (free-tagging style) would allow it to handle external URLs as well as a bonus (...but would that be a feature or a bug?). Does that seem reasonable?

Last thing (of-topic - only mentioning because it seems that we'll have both URL and image field in D8 core) I wanted to mention is that we need to think about images with URLs (or the other way 'round: URLs with images). How do we do that best? Do we make it a URL field that accepts an optional image as some sort of attachment or the other way 'round having it be an Image field that has an optional URL? AFAIK we cannot have fields within fields. Do we do this taking advantage of what we can do with field collections (supposing this might also be in core)?

pcambra’s picture

I would say that the most usual use case is to add a link field that doesn't care if the url is internal or external, but both plan A and B are a simpler approach and I don't think that is that bad to use 2 fields for that particular.

More on url input type for html5: http://www.w3.org/TR/html-markup/input.url.html

Option C clearly disables the option of using html5 unless we consider everything as an external, so I'd ++ A and in case there's time, implement B.

Dave Reid’s picture

Yeah if we went with option C then we'd only be able to use the 'url' FAPI type if the field was set to 'External only'

chx’s picture

The way i imagine entering things, you enter full URLs anyways -- copypaste from browser URL bar. That supports HTML5 url too. Then if you've pasted something which starts with base_url offer (make a checbkox visible via JS states) to strip base_url from it and store it that way and re-assemble only on edit so that a dev-prod URL change doesn't break linkage.

Dave Reid’s picture

Ok so let's add this:

Option D
Always use the FAPI 'url' type, and attempt to resolve what are 'local' URLs to un-aliased internal Drupal URLs.

I have a feeling this might be our best option, but we would need to ensure that it works easily and works well. The unanswered questions are how do we present the field values once they've been saved build them out to a full URL and have to re-process them every time a node is saved? How do we preform this resolution when the site is on multiple domains (multisite or domain access)?

chx’s picture

If the URL is not external (there's a function already for that) we can just alias it and put the active base_url before it, ie show url($value, array('external' => TRUE)). The user will be presented (because the base_url matches) with the same "strip" checkbox which the user can just leave ticked. This is consistent to what the browser does anyways.

chx’s picture

Issue summary: View changes

Revising

chx’s picture

Posting some musings from IRC by davereid: Copying a link from subdomain.mysite.com/content/test-node into a text field on mysite.com/node/1/edit (using multisite). Do we just accept that this cannot resolve it in this case? I guess we could add support for this in something like Pathologic to process link fields, and just punt complex resolution to contrib.

I completely agree. If you edit site X paste links from site X. This is what core covers. If you paste from site Y, that's contrib.

RobW’s picture

D was what I was imagining in my head, but didn't spend the time to reason/type out. Big ++.

Dave Reid’s picture

Hrm, given the scenario that is available with just Drupal 7/8 core:

Given the following:
- I have a multilingual-enabled site using domain switching
- With the English domain being mysite.com
- And the French language domain being fr.mysite.com

If I'm editing a node at mysite.com/node/1/edit and paste in a link of 'http://fr.mysite.com/content/french-title' how do we attempt to resolve this as a 'local' URL? The same could be said for things with language prefixes too. Do we need to store the language of the URL in the field data? Because link module doesn't do that.

klonos’s picture

In the case of multilingual sites can't we check the URL language detection setting for the site and then depending on that setting strip either the subdomain or the prefix from the URL? I think that this way, with the language subdomain/prefix stripped the end page will be resolved based on the settings of each visitor. Right? I mean even though the URL might be rendered plain (without any language "hint") on the page, the user still gets redirected to their preferred/browser default/whatever set in the URL language detection section when they click on it. Don't they?

sun’s picture

Don't want to kill the party, but with this you're seriously duplicating Link module.

Dave Reid’s picture

No need to comment if you don't have anything productive to add. The directions here are actually *not* a duplicate of Link module.

RobW’s picture

I don't see a problem with URL field being a stripped down version of link module in core. The field type is a common request, and there can still be a space for link module alongside a core field, maybe by adding more in depth features or custom validation.

sun’s picture

#501434: Move Link/URL field type into core landed for D8 core. Would it make sense to move this issue/discussion into the core queue?

(If not, let's make sure to create a new issue for core and summarize the essential discussion so far. FWIW, my primary vote goes for Plan D, with the small addition of turning the 'url' form element into an autocomplete, so when entering an internal path, it autocompletes to an external path. If that doesn't fly, then my secondary vote goes for Plan C, and I'd suggest to first try to conditionally override the user agent's default URL validation [which should be possible through the pattern attribute, and if that fails it is possible via JS].)

dodorama’s picture

My vote goes for plan A, easy and straightforward and already landed.
In the most common scenario (content editor updating content in the Live website) they can still paste a complete internal URL and it will work.
In complex scenarios where you might have a DEV/PROD/LIVE or multiple languages I believe an entity reference field is what you should use.
A contrib link module is then where more complex things should happen. But I'm pretty sure than 95% of the users won't need it.

klonos’s picture

Project: URL field » Drupal core
Version: 8.x-1.x-dev » 8.x-dev
Component: Miscellaneous » field system

...Would it make sense to move this issue/discussion into the core queue?

I don't know if this question was for the module maintainers, but this has been brought up in #501434: Move Link/URL field type into core and I for one would love it if I could be done having to use an additional contrib module for doing this in D8. So, lets do switch to core queue and if it is decided to not do it in core, we switch back.

Now, as for the way to go from the proposed plans D + autocomplete for internal URLs sounds better to me too. If not that, then C.

No matter which of the two we choose to go with, I believe that having a per-widget setting to allow/limit internal/external/both is a must.

swentel’s picture

Component: field system » link.module

Guess this belongs to the link module.

Dave Reid’s picture

Project: Drupal core » URL field
Version: 8.x-dev » 7.x-1.x-dev
Component: link.module » Miscellaneous

Yeah I'm going to steal this issue back to the module issue queue and will file a duplicate issue for core's link module.

Dave Reid’s picture

amateescu’s picture

Duplicate issue titles are never a good thing to have :)

Dave Reid’s picture

If only there was a way for users on drupal.org to edit the issue titles easily!

DamienMcKenna’s picture

DamienMcKenna’s picture

Issue summary: View changes

Adding Plan D

klonos’s picture

dealancer’s picture

There also should be a support of schemaless URLs, such as //google.com

johnhanley’s picture

Looking for this as well.

Murz’s picture

For enable internal links we can remove $absolute argument from function valid_url:

$absolute: Whether the URL is absolute (beginning with a scheme such as "http:").

Here is example for file url.module - line:

  if ($value !== '' && !valid_url($value, TRUE)) {

change to:

  if ($value !== '' && !valid_url($value)) {

But better way will be add option to field "Allow internal links".