Recent changes, probably related to - https://www.drupal.org/node/2844466 - made the adding and editing a little less intuitive, as now the links are always show as /node/x or /media/x instead of being more friendly, say using the path alias instead.

CommentFileSizeAuthor
#96 linkit-2877535-62-revised.patch4.21 KBmark_fullmer
#93 ck-markup.png26.52 KBrealityloop
#93 ck-click-link.png15.62 KBrealityloop
#93 ck-edit-link.png32.57 KBrealityloop
#93 devel-link-filed-linkit-widget.png17.28 KBrealityloop
#93 link-field-linkit-widget.png15.77 KBrealityloop
#91 ckeditor-edit-linkit.png27.93 KBrealityloop
#91 ckeditor-click-link-popup.png19.65 KBrealityloop
#91 linkit-widget.png20.37 KBrealityloop
#81 linkit-2877535-81-6.1.x.patch22.62 KBdrpldrp
#80 linkit-2877535-80-6.1.x.patch22.97 KBdrpldrp
#79 linkit-2877535-79-6.1.x.patch20.52 KBdrpldrp
#78 linkit-2877535-78-6.1.x.patch21.71 KBdrpldrp
#77 2877535-77-7.x.patch3.71 KBcasey
#77 2877535-77-6.1.x.patch3.7 KBcasey
#64 linkit-2877535-64.patch3.46 KBarthur.baghdasar
#63 linkit-2877535-62.patch4.05 KBmark_fullmer
#50 linkit-n2877535-50.patch4.13 KBdamienmckenna
#41 interdiff-35-41.txt3.02 KBleon kessler
#41 linkit-2877535-link-shown-after-autocomplete-is-bare-41.patch4.12 KBleon kessler
#39 interdiff_12-39.txt439 bytespghaemim
#39 2877535-39.patch470 bytespghaemim
#37 2877535-36_option_to_use_alias.patch1.62 KBakhoury
#35 2877535-34.patch4.92 KBspadxiii
#35 interdiff-30-34.txt4.03 KBspadxiii
#33 2877535-33.patch4.92 KBspadxiii
#33 interdiff-30-33.txt4.03 KBspadxiii
#32 2877535-32.patch4.83 KBspadxiii
#32 interdiff-30-32.txt4.16 KBspadxiii
#30 interdiff.2877535.24-30.txt764 bytespixelwhip
#30 2877535-30.linkit.Link-shown-after-the-autocomplete-selection-is-the-bare-nodexxx-link-not-the-alias.patch6.66 KBpixelwhip
#28 2877535_display_path_alias_in_autocomplete_input-28.patch31.54 KBmark_fullmer
#28 interdiff_24-28.txt764 bytesmark_fullmer
#24 2877535_display_path_alias_in_autocomplete_input.patch5.91 KBsimeonkesmev
#23 interdiff_16-23.txt1.52 KBkbrodej
#23 show-alias-with-language-and-path-prefix-2877535-23.patch5.17 KBkbrodej
#22 2877535_display_path_alias_in_autocomplete_input.patch5.4 KBsimeonkesmev
#20 2877535_display_path_alias_in_autocomplete_input.patch4.28 KBsimeonkesmev
#16 interdiff_15-16.txt3.31 KBmarco-s
#16 show_alias_in_autocomplete_selection-2877535-16.patch4.37 KBmarco-s
#15 interdiff_14-15.txt3.41 KBmarco-s
#15 show_alias_in_autocomplete_selection-2877535-15.patch3.35 KBmarco-s
#14 show_alias_in_autocomplete_selection-2877535-14.patch470 bytesmarco-s
#12 2877535-12.patch470 bytespfrenssen
#7 2877535-7.linkit.Link-shown-after-the-autocomplete-selection-is-the-bare-nodexxx-link-not-the-alias.patch668 bytesthierry.beeckmans
#5 2877535-4.linkit.Link-shown-after-the-autocomplete-selection-is-the-bare-nodexxx-link-not-the-alias.patch668 bytessingularo
#4 interdiff.2877535.4.txt659 bytessingularo
#2 2877535-2.linkit.Link-shown-after-the-autocomplete-selection-is-the-bare-nodexxx-link-not-the-alias.patch669 bytessingularo

Issue fork linkit-2877535

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

singularo created an issue. See original summary.

singularo’s picture

Attching patch to call the alias manager not just return the path.

tsymi’s picture

Thanks, patch on #2 works for me and met to my need.

singularo’s picture

StatusFileSize
new659 bytes

Hmm it looks like there is a tiny change required for sites running on a non '/' base path.

singularo’s picture

anon’s picture

Status: Active » Needs work

Thanks for patch, we need a test for this tho.

thierry.beeckmans’s picture

Updated patch for the 8.x-5.0-beta7 version.

sime’s picture

Shouldn't this be done in a text output filter?

sime’s picture

On that note, I think this needs to be an optional configuration if this gets applied. We don't want to all our content links breaking when aliases are updated.

dalemoore’s picture

I just ran into this issue setting up my first D8 site. I was expecting this module to work similarly to CKEditor Link with D7, where it uses the node/id link but outputs the alias for the end-user, so that when aliases change (renaming a title, for instance) the path gets updated. Instead, all URLs break if the alias is updated...
EDIT: Scratch this, I updated to the 5.x-beta10 version, and it works now like I thought it should. I see now that you all were working to fix this on that branch.

marco-s’s picture

I have updated from 4.3.0 to 5.0.0-beta10 and I was wondering why the links are shown as /node/x afterwards (that wasn't the case with 4.x). I found the filter 'Linkit URL converter' in the text formats settings, but this filter doesn't seem to work?! Patch #7 works for me for my current case. I also don't need the 'Linkit URL converter' filter with this patch. But I agree with slime that this variant doesn't recognize alias updates and you should use the patch deliberately.

pfrenssen’s picture

moshe weitzman’s picture

Issue tags: +Needs tests

Patch works for me. FWIW, the link already has durable reference to the linked entity (uuid) so perhaps its OK for this href to be a bit brittle? An example [a] tag when using this patch is <a data-entity-substitution="canonical" data-entity-type="node" data-entity-uuid="66950305-f906-4f76-90e4-143a0eddc67e" href="/news/bulletin-2020-05-flexibility-in-the-issuance-and-administration-of-insurance-during-covid-19">dfdfdf</a>

marco-s’s picture

path.alias_manager in #12 needs to be changed to path_alias.manager for D9 compatibility. This patch will now require Drupal >=8.8. (see https://www.drupal.org/node/3092086)

marco-s’s picture

The patch #14 does not provide the url with a language prefix (because of 2772643).
I updated this patch for that case accordingly.

marco-s’s picture

The patch #15 does not consider a possible path prefix configuration. Updated it in this patch.

ciss’s picture

Status: Needs work » Needs review

lukus’s picture

I'm not sure I agree that this is a desirable feature.

- The `href`- will be replaced by the text input filter, once the text is filtered for display.
- The alias is subject to change.
- The system path is actually a true representation of the intended destination.

simeonkesmev’s picture

Hello, I am having this feature requested as well, but I also disagree with the implementation as it introduces dependencies, tries to implement URL building by itself by requesting the path alias manager and breaks the logic by replacing the internal path with an alias which is not stable reference to the target. Here's my take on it where I'm modifying only the representation to the editors and not he saved input.

Status: Needs review » Needs work
simeonkesmev’s picture

Corrections here.

kbrodej’s picture

Patch from #16 worked for me. However did spot a few issues. Attached a patch with changes and interdiff from #16

If the language detection is domain based the path alias will still use language prefix:
- Added a explicit check if language negotiation source is path_prefix

if path alias does not exist for given language it will use /{entity_type}/{id}:
- Added a method to check the alias for current language and fallback to default langugage.

simeonkesmev’s picture

Here's an updated patch with my approach which handles base_paths.
NOTE: It's a different approach from the patch in #23, summary in #20.

askibinski’s picture

@SimeonKesmev I agree with your approach since we already have input format LinkitFilter which will transform the internal node/# url for visitors of the content to the alias.

Remaining issue:
With patch#24 you will see the alias in the autocomplete, but after inserting in the editor the link label/text still is node/# (unless you select text before inserting the link).

I think if no text is selected in the editor the default text to insert should be the node title.

dbielke1986’s picture

Is there a chance to port this patch to version 6.*?

Because Iam facing the same issue:
If you type in "/node/<nid>" and you do not select the search result - it will input <a href="/node/nid".... and not the <a data-entity-substitution="canonical" data-entity-type="node" data-entity-uuid="<uuid>" href="/node/<nid>"... which is a big issue. Not everyone is clicking at the search result, which leads to an issue on multilanguage sites.

dbielke1986’s picture

I created a new issue for version 6.*

https://www.drupal.org/project/linkit/issues/3222939

mark_fullmer’s picture

Status: Needs work » Needs review
StatusFileSize
new764 bytes
new31.54 KB

I agree with the approach stated in #20. The approach here should be **not** to overwrite the internal path with the URL alias, since the latter could change. The patch in #24 , which is the latest version of that implementation, works well but does not include logic for adjusting the autocomplete logic to properly query the internal url in parentheses. In other words, it successfully populates the input area, but upon triggering a subsequent autocomplete search by clicking the input area, the autocomplete query fails because it's trying to match
[alias] ([internal-url]), rather than [internal-url].

The attached patch accounts for that, and is otherwise identical to #24.

(I'm not quite clear what #25 is referring to, so I didn't address that.)

tvalimaa’s picture

#28 fix my issue so node/xxx links are working now as aliases

pixelwhip’s picture

Here's a re-roll of #28. That patch had some extra changes related to the license file that did not look intentional and were not represented in the interdiff.

After fixing that, I was able to apply this patch via composer to 6.0.0-beta3.

sutharsan’s picture

+++ b/src/Controller/AutocompleteController.php
@@ -76,6 +76,13 @@ class AutocompleteController implements ContainerInjectionInterface {
+    $patch_match = [];

Just checking, is this variable name $patch_match intended or was it supposed to be $path_match.

spadxiii’s picture

StatusFileSize
new4.16 KB
new4.83 KB

I tried the patch in #30 and it seems to work, except that the wrong value is saved to the database. The alias (as internal url) is saved instead of the internal path. When selecting a node path, the form field shows "/alias-to-node" and the database contains "internal:/alias-to-node" instead of "entity:node/".

Here's a different patch that uses the #30 as starting point, but makes sure the correct value is saved to the database.

spadxiii’s picture

StatusFileSize
new4.03 KB
new4.92 KB

I seem to have uploaded a patch that doesn't apply. Here's a fresh one.

Status: Needs review » Needs work

The last submitted patch, 33: 2877535-33.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

spadxiii’s picture

Status: Needs work » Needs review
StatusFileSize
new4.03 KB
new4.92 KB

And I seem to have copied the deprecated service name :(
Fixed in new patch.

Status: Needs review » Needs work

The last submitted patch, 35: 2877535-34.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

akhoury’s picture

StatusFileSize
new1.62 KB

This patch adds a configurable option to use alias instead of internal path navigate to /admin/config/content/linkit/manage/{linkit_profile}/matchers/{plugin_instance_id} and check "use alias" checkbox

The autocomplete value and href attribute will contain the alias.

rossidrup’s picture

why dont you hardcode it into latest release?

pghaemim’s picture

StatusFileSize
new470 bytes
new439 bytes

making the #12 D9 compatible.

seanb’s picture

leon kessler’s picture

Version: 8.x-5.x-dev » 6.0.x-dev
Status: Needs work » Needs review
StatusFileSize
new4.12 KB
new3.02 KB

Lots going on this issue. Three separate patches in #35, #37 and #39. Very confusing.

I'm hiding patch #39 and #37, as they go against the agreed approach of storing the internal (node/id) url in the unprocessed text.

I tested patch from #35, all looks good. Except you still see the internal node/id url immediately after selecting the link. After closing the dialog and re-opening to edit, you then see the url alias. This seems a bit broken to me, the value should be consistent so the behaviour is predictable to the user.

After having a look into the patch, I realised that the added code in Drupal\linkit\Element::valueCallback means that the internal url will always be used when submitting the form. This means it's safe to use always use the alias on the suggestions.

Patch attached updates the matches to always use the alias.

Also, I've wrapped the use of \Drupal::service('path_alias.manager') in a check for the installation of the path_alias module. As otherwise we would need to add a hard dependency to this module. Also this should hopefully make the tests pass.

Status: Needs review » Needs work
GasparM’s picture

Had the issue on linkit 6.0.x-dev, patch #41 works for me. I'm on PHP 8.1, drupal core 9.5.1

mark_fullmer’s picture

Note: Linkit 6.0.0-beta4 was released on 5 March 2023. The patch from #41 still applies to the latest changes.

However, this only works with CKEditor 4 currently. CKEditor 5 support would need to be added.

mark_fullmer’s picture

Category: Task » Feature request

However, this only works with CKEditor 4 currently. CKEditor 5 support would need to be added.

I take it back! This *does* work with CKEditor 5 as-is (I was expecting a different display output, but the aliased path is what is displayed in the CKEditor 5 context, which makes sense based on what the change is targeting).

This should still be "Needs work" since the failing tests need to be addressed. Also, I think it makes more sense to classify this as a "Feature" rather than a "Task."

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

jds1’s picture

Status: Needs work » Needs review

Rerolled #41 against 6.0.x https://git.drupalcode.org/project/linkit/-/merge_requests/16. Everything passes. Patch applies cleanly locally against both 6.0.x-dev and 6.0.0-beta4. Tested locally and now I'm getting aliases instead of node URLs! Marking as "Needs Review" – thank you!

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

damienmckenna’s picture

StatusFileSize
new4.13 KB

The merge request in patch format.

lxpcfly’s picture

The linkit-n2877535-50.patch is successfully changed the URL Link field from "node/xxx" to URL Alias, but it still needs to do extra work, as the saved URL is still "node/xxx" rather than saved as its path alias, 'canonical' is not active.

eg:

1. put node/xxx into the link field and click save straight away without selecting the autocomplete result, it only saves node/xxx .
2. edit link, you can see the node/xxx has changed to its path alias, save as is, it is not changing the url, the url link on the mouse hover is still node/xxx.

damienmckenna’s picture

It's ok that the saved value is "node/xxx" because it's converted to the correct URL when the content is rendered; it's a feature.

lxpcfly’s picture

Thank you Damien, but I think once it has the path alias also it appears in the Link field, it should save as path alias with canonical active.

damienmckenna’s picture

That would need to be a separate discussion.

vladt’s picture

I'm encountering an issue after applying patch #50 to Linkit 6.0.0-rc1 (as well as Linkit 5.0-beta 13), the data-entity-substitution, data-entity-type, data-entity-uuid attributes are no longer being added to the link, so the LinkitFilter is no longer working.

This seems to be happening because $href !== $href_dirty_check on line 129 of linkit.module is unsetting the values.

moshe weitzman’s picture

Status: Needs review » Needs work

Sounds like this is right status.

moshe weitzman’s picture

Status: Needs work » Reviewed & tested by the community

In my instance, that check is preventing the values from being unset, not unsetting them. Changing status after my review.

mark_fullmer’s picture

Title: Link shown after the autocomplete selection is the bare node/xxx link, not the alias » Show URL alias after autocomplete selection instead of internal route (e.g., /node/123)
r_h-l’s picture

Testing this in 9.5, #50 breaks the a tag extra attributes. The tag gets put in as just the bare '/node/x' without any data attributes.

mark_fullmer’s picture

Addressing the comments in #51, #53, and #59, all of which are suggesting that the URL alias is what should be saved to the database, rather than the internal route, I agree with Damien McKenna's statement in #52:

It's ok that the saved value is "node/xxx" because it's converted to the correct URL when the content is rendered; it's a feature.

mark_fullmer’s picture

Status: Reviewed & tested by the community » Needs work

It's ok that the saved value is "node/xxx" because it's converted to the correct URL when the content is rendered

After testing to confirm, I take back my comment. Using the latest patch, the comments in #51, #52, and #59 are effectively pointing out a problem -- not that the internal URL is what is saved (that's fine), but that when the resulting page is rendering, the internal URL is what is rendered to the end-user, rather than the URL alias.

Changing status to "Needs work" to address this. I'm also surprised that there is apparently no test coverage to catch this. I'd like to add test coverage for this going forward: the URL alias should be rendered on the page after save.

moshe weitzman’s picture

This patch no longer applies to the most recent release (Sep 30) :(

mark_fullmer’s picture

StatusFileSize
new4.05 KB

This patch no longer applies to the most recent release (Sep 30)

Here's a revised patch that replicates verbatim what was in the patch in #50, and which will apply to the current development release for 6.0.x and 6.1.x.

Noting that the comments from #51, #52, and #59 still need to be addressed: when the resulting page is rendered, the internal URL should not be rendered to the end-user. The URL alias should. Test coverage needs to be added for this, too. Leaving status as "Needs work."

arthur.baghdasar’s picture

StatusFileSize
new3.46 KB

Ive removed this part from the patch everything seems to be working fine for me.
In the code below $input variable comes with an Alias and I don't understand why we should get the $path from it.
In My case the $path variable is converted back to the node/[nid] which is then being set to be the new input.

+    if (!empty($input) && \Drupal::moduleHandler()->moduleExists('path_alias')) {
+      /** @var \Drupal\path_alias\AliasManagerInterface $aliasManager */
+      $aliasManager = \Drupal::service('path_alias.manager');
+      $path = $aliasManager->getPathByAlias($input);
+      if ($path !== $input) {
+        $input = $path;
+      }
+    }
damienmckenna’s picture

Status: Needs work » Needs review
kthull’s picture

Patch from #64 applied to 6.1.2 for me and solved the generic node path on D10.1.5

greenskin’s picture

Status: Needs review » Needs work

The LinkitFilter doesn't look to work with the patch. I'm not seeing the additional attributes getting added to the tag.

spadxiii’s picture

I tried to get something working, but did not succeed.

My goal was to use the alias during editing and store the node-url in the database. The link would then show the node alias in the editor, but in the database the node/ was stored. By adding another data-property (data-entity-path) I tried adding a editorDowncast and dataDowncast in the plugin, but that didn't work correctly: it would create a new a-tag wrapping the one that was being made by the base link plugin.

By adding a general upcast conversion, the href is changed to the alias:

editor.conversion.for('upcast')
      .elementToAttribute( {
        view: {
          name: 'a',
          attributes: {
            href: true,
            ['data-entity-alias']: true
          }
        },
        model: {
          key: 'linkHref',
          value: viewElement => viewElement.getAttribute('data-entity-alias'),
        },
        converterPriority: 'high'
      } );

But I failed trying to move the other way around. I tried adding a dataDowncast (which would set the path back to the href), and an editorDowncast (which would use the alias as href). This didn't work, because when creating an element with the same attribute, would add another element to the html instead of merging them (effectively overwriting the href-attribute)
I also tried using a data downcastDispatcher, but that doesn't seem to be able to get the correct viewElement (or rather, it couldn't find any element at all).

ps. there are some other code changes required as well to not only pass but also use the alias and path in the links.

mrweiner’s picture

For anybody who needs a quick and dirty fix for this, I'm handling it in hook_preprocess_field() with:

function cc_gin_preprocess_field__node__body__article(&$variables) {
  // Assuming $text is the HTML content you're preprocessing
  $text = $variables["items"][0]["content"]["#text"];

  // Create a new DOMDocument and load the HTML content
  $dom = new DOMDocument();
  @$dom->loadHTML(mb_convert_encoding($text, 'HTML-ENTITIES', 'UTF-8'), LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);

  $links = $dom->getElementsByTagName('a');

  foreach ($links as $link) {
    // Check if the link is an internal node link
    if ($link->hasAttribute('href') && str_starts_with($link->getAttribute('href'), '/node/')) {
      $path = $link->getAttribute('href');
      if ($path) {
        continue;
      }

      $alias = \Drupal::service('path_alias.manager')->getAliasByPath($path);
      if (!$alias) {
        continue;
      }

      // Replace the href attribute with the alias
      $link->setAttribute('href', $alias);
    }
  }

  // Save the updated HTML
  $variables["items"][0]["content"]["#text"] = $dom->saveHTML();
}

Note that this was generated by chatgpt, so I'm not sure that all of the args in $dom->loadHTML() are needed, but it seems to do the trick for me.

mark_fullmer’s picture

Version: 6.0.x-dev » 7.x-dev
klidifia’s picture

I updated this issue with some code that will use the entity title (already obtained via Linkit) as the default link text for a brand new inserted link without a selection range: #3388565: Populate displayedText with entity title when left blank

federiko_’s picture

Patch from #64 applied to 7.0.0-alpha1 seems to be working well for me ; here is the generated link markup :
<a class="test-css" href="/fr/mentions-legales" target="_blank" aria-label="test-aria" id="test-idd" rel="test-rel" data-entity-type="node" data-entity-uuid="7a012594-8e2f-446f-8559-ac377b1ec0d5" data-entity-substitution="canonical" tabindex="-1" data-title="Test title">Test link</a>

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

casey’s picture

Sorry for the noise;

First I rebased the existing MR branch on the latest 6.1.x branch but apparently you can't change the destination of MRs. I then reverted that existing MR.

I then applied the patch from #64 to both the 6.1.x and the 7.x branch; apparently the 6.1.x branch has more (recent) changes than the 7.x branch. I've created MRs for both branches.

casey’s picture

StatusFileSize
new3.7 KB
new3.71 KB

Snapshots of latest state of MRs for both 6.1.x and 7.x for safe usage with composer-patches

drpldrp’s picture

StatusFileSize
new21.71 KB

delete

drpldrp’s picture

StatusFileSize
new20.52 KB

delete

drpldrp’s picture

StatusFileSize
new22.97 KB

delete

drpldrp’s picture

StatusFileSize
new22.62 KB

Loading alias info into global drupalSettings allows it to be available to the ckeditor5 linkit plugin on init so the alias can be upcast into the model. Storing in drupalSettings also allows it to be available to all text formats and persistent between switching text formats.

My version does entity lookup by the link href instead of uuid and entity type because I do not use the linkit url conversion filter. It is not currently compatible with linking images.

If you need to do entity lookup by the existing uuid/entity type method, alter linkit_field_widget_single_element_form_alter() so it does the entity load similar to how it's done in src/Plugin/Filter/LinkitFilter.php.

kasey_mk’s picture

I think this no longer applies on 7.0.5. The patch from #77 applies, but appears to be causing the error reported on Can't Insert or Update Link after Upgrading to Drupal Core 10.5

kasey_mk’s picture

Ah! My patented "wait a while and see if things 'magically solve themselves'" technique seems to have worked!

Thanks to all the wizards out there!

vah67007@gmail.com’s picture

Patch #64 worked fine for me. Running 10.5.x version of core.

dcasanova’s picture

I tested the last patches, but it didn't work for Drupal 10.5.x and Linkit 7.0.8. If anyone has any idea how to solve this, I would greatly appreciate it.

mark_fullmer’s picture

Weighing in as a maintainer of the Linkit module, I would point out that there are others in the community who want the entity title to show: #2966320: Show entity title after autocomplete selection instead of internal route (e.g., /node/123). This, plus the fact that it is possible to configure the Linkit metadata to render the entity title in the matcher information, makes me disinclined to plan to include this in a release of Linkit. Community members are free to use the patch here, of course, but I'd really recommend going the route of adjusting the autocomplete metadata in the Linkit settings.

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

realityloop’s picture

Status: Needs work » Needs review

MR 138: for 7.x Continue to use internal route so links don’t get broken, but display url alias in linkit widget and CKeditor when present.

realityloop’s picture

moved to new comment

realityloop’s picture

StatusFileSize
new20.37 KB
new19.65 KB
new27.93 KB
realityloop’s picture

Status: Needs review » Needs work
realityloop’s picture

StatusFileSize
new15.77 KB
new17.28 KB
new32.57 KB
new15.62 KB
new26.52 KB
realityloop’s picture

Status: Needs work » Needs review

Apologies for the commit noise.. Now that all tests are passing for my MR138....

Drupal Link Handling Changes

1. Main Change: Internal Routes for Storage, Aliases for Display

  • Before: Links could be entered using alias (e.g., /my-page), which could break if the alias changed (e.g., to /updated-page).
  • After: Internal links are stored using Drupal's stable internal route (e.g., entity:node/1), but the UI shows the current alias (e.g., /my-page). This prevents broken links.
  • Why?: Aliases can change (e.g., for SEO), but internal routes stay the same. The change ensures links remain working even if aliases are updated.
  • Fragments: Fragments (e.g., #section ?query=1) are preserved in storage and display, but the changes ensure they're appended to the alias in the UI when present.

2. Examples of Creating Links

Internal Link (e.g., to a Node):

  • Without Fragment:
    • Before: User types /my-page in the link field. Stored as internal:/my-page. If alias changes to /new-page, link breaks.
    • After: User types /my-page or selects from autocomplete. Stored as entity:node/1 (internal route). Displayed as /my-page (alias). If alias changes, link still works.
  • With Fragment:
    • Before: User types /my-page#section in the link field. Stored as internal:/my-page#section. If alias changes to /new-page, link breaks.
    • After: User types /my-page#section or selects from autocomplete. Stored as entity:node/1#section (internal route). Displayed as /my-page#section (alias with fragment). If alias changes, link still works.
  • Autocomplete: Suggestions show the alias (with or without fragment) in the display, but use internal routes internally.

External Link (e.g., to Another Site):

  • Without Fragment:
    • Before: User types https://example.com. Stored as https://example.com. No change in behavior.
    • After: Same as before—stored and displayed as https://example.com. The change doesn't affect external links.
  • With Fragment:
    • Before: User types https://example.com#anchor. Stored as https://example.com#anchor.
    • After: Same as before—stored and displayed as https://example.com#anchor.
  • Autocomplete: External matcher suggests the URL (with or without fragment) for bare domains.

Relative Link (e.g., to a Custom Path):

  • Without Fragment:
    • Before: User types /custom/path. Stored as internal:/custom/path. Works as a relative link.
    • After: Same as before—stored as internal:/custom/path. If it matches an alias, it might convert to an entity link; otherwise, stays relative.
  • With Fragment:
    • Before: User types /custom/path#part. Stored as internal:/custom/path#part.
    • After: Same as before—stored as internal:/custom/path#part. If it matches an alias, it will convert to an entity link; otherwise, stays relative.
  • Autocomplete: If no entity matches, it suggests the path (with or without fragment) as-is.

3. Examples of Editing Links

Internal Link:

  • Without Fragment:
    • Before: Link stored as internal:/my-page. User edits to /updated-page. Stored as internal:/updated-page. If /my-page was an alias, editing might not update the entity reference.
    • After: Link stored as entity:node/1. User sees /my-page in the field. If they edit to /updated-page (new alias for the same node), it resolves back to entity:node/1. If edited to a non-entity path, it becomes internal:/updated-page.
  • With Fragment:
    • Before: Link stored as internal:/my-page#section. User edits to /updated-page#newsection. Stored as internal:/updated-page#newsection.
    • After: Link stored as entity:node/1#section. User sees /my-page#section in the field. If they edit to /updated-page#newsection, it resolves back to entity:node/1#newsection. If edited to a non-entity path, it becomes internal:/updated-page#newsection.

External Link:

  • Without Fragment:
    • Before: Link stored as https://example.com. User edits to https://newexample.com. Stored as https://newexample.com.
    • After: Same as before.
  • With Fragment:
    • Before: Link stored as https://example.com#anchor. User edits to https://newexample.com#newanchor. Stored as https://newexample.com#newanchor.
    • After: Same as before. Fragments are preserved.

Relative Link:

  • Without Fragment:
    • Before: Link stored as internal:/custom/path. User edits to /new/path. Stored as internal:/new/path.
    • After: Same. If the new path resolves to an entity, it converts to entity:...; otherwise, stays relative.
  • With Fragment:
    • Before: Link stored as internal:/custom/path#part. User edits to /new/path#newpart. Stored as internal:/new/path#newpart.
    • After: Same. If the new path resolves to an entity, it converts to entity:...#newpart; otherwise, stays relative with the fragment.

4. Other Changes in the Commit

  • UI Improvements: Updated JS for autocomplete behavior (e.g., better display in CKEditor, including fragments).
  • Autocomplete Controller: Added logic to fetch display paths for entities, ensuring aliases (with or without fragments) are shown in suggestions.
  • Widget Updates: Enhanced the link field to display aliases (with or without fragments) while storing internal routes.
  • Matcher and Substitution: Tweaks to how entity paths are built (e.g., using path_processing: false for internal routes, true for aliases), with fragment handling.
  • No Breaking Changes: Existing links continue to work; the commit improves reliability without disrupting current setups.
  • Fixes links to existing aliases if you edit them: If you edit a node with linkint based link and just click save if it is to an existing internal alias that now has a node at that route it will be linked to the node and future path changes will not break the link, likewise if you edit the same type of link in ckeditor and just click save then save the node.

5. Overall Impact

  • Pros: Links are more robust (don't break on alias changes). Users see friendly aliases (with or without fragments) in the UI.
  • Cons: Slightly more complex internally, but transparent to users.
  • Testing Note: The commit includes changes to ensure autocomplete and editing work seamlessly with or without fragments.

Some screengrabs:

linkit widget

linkit widget devel

Ckeditor link click initial popup

ckeditor edit link

ckeditor link markup

mark_fullmer’s picture

Assigned: Unassigned » mark_fullmer

Assigning to myself for review!

mark_fullmer’s picture

StatusFileSize
new4.21 KB

The attached patch is a re-roll of the approach taken in #62/#64 -- i.e., a narrower implementation -- that applies cleanly to Linkit 7.0.9, 7.0.10, and 7.0.11 (latest release), in case anyone was using that and still needs it.