Writer field - Use regular links instead of permalinks

Hello,

In a writer field, when creating a link to a internal page, as href value in the template is it possible to display the regular page link instead of the permalink ?

I’m trying Kirby 4 and it’s great. The new link dialog makes it possible to link any word(s) to a page, but the href attribute contains a permalink, wich is problematic in my case.
Otherwise, in the context of a blocks field, I don’t see any other option than to use the markdown field, wich is way less convenient for the user. But maybe you see one ?

Thanks for your help.

For me linking from internal pages does not work.
After assignment source code looks like this:
<a>notes</a>
The href attribute is missing.
If I call the page in the panel again, the link is not recognized at all.
Is this a (known) bug?
I use the starterkit with 4.0.0-beta.1

I don’t think so, works for me. Where are you using this, in a text block?

External links work. Internal page links do not work.
I have tested a block field in the Starterkit.

As I wrote above, I cannot reproduce this in a fresh K4 beta 1 Starterkit, but if you want to report a bug, please do so in the GitHub kirby repo.

I don’t see this bug neither.

@texnixe any idea concerning my question ?

Hm, I don’t think so, looking at the source code, Kirby recognizes links via the file:// or page:// patterns. So it wouldn’t work with this disabled.

What you can do is disable the pages option and use a custom option, i.e. just insert /notes.

Is it possible to hook the render so that it gets the regular link from the permalink ?

A hook that replaces the link and actually stores the result in the content wouldn’t be useful (because of what I wrote above), what you can do is replace those links when rendering, via a custom field method.

Ok thank you :slight_smile:

I’ll try this approach.

It works !

Here is the method :

Kirby::plugin('adrienpayet/process-links', [
  'fieldMethods' => [
      'processLinks' => function ($field) {
          $dom = new DOMDocument();
          @$dom->loadHTML(mb_convert_encoding($field->value(), 'HTML-ENTITIES', 'UTF-8'), LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
          $anchorTags = $dom->getElementsByTagName('a');
          $site = site();

          foreach ($anchorTags as $anchorTag) {
              $href = $anchorTag->getAttribute('href');
              $getIdPattern = '/@\/page\/(.*)/';
              $regexResult = preg_match($getIdPattern, $href, $matches);
              $isInternalPageLink = $regexResult && isset($matches[1]);
              $targetId = $matches[1];

              if ($isInternalPageLink) {
                try {
                  $targetPage = $site->find('page://' . $targetId);
                  if (!$targetPage) {
                      throw new Exception("No internal page found.");
                  }
                  $anchorTag->removeAttribute('target');
                  $attributes = [
                      'href' => $targetPage->url(),
                      'class' => 'internal-link',
                      'data-size' => formatSize($targetPage->size()->toInt())
                  ];
                  foreach ($attributes as $key => $value) {
                      $anchorTag->setAttribute($key, $value);
                  }
                } catch (Exception $e) {
                    error_log($e->getMessage());
                }
              }
          }
          return $dom->saveHTML();
      }
  ]
]);
1 Like

Hi @Adrieng have you published this plugin somewhere?
I’m trying to do the same thing but your code does not include the functions used :wink:

Hi @JuG,

No it’s not published.
Which functions are you talking about ? formatSize() was specific to my project but if you think it could be usefulf to you of course I can share it.

hum :thinking: the code is not working in my install but not for the reason I thought. Seems not to be related to the function afterall. I’ll investigate.

I just ran into the same problem. It’s an odd decision to make Writer fields render permalinks only. This renders the field useless to many use cases where human-readable and SEO friendly links are desired. And this should be the default on any website.

If Kirby wouldn’t store links as permalinks/UUIDs in the writer field bun human-readable URLs, the whole benefit of UUIDs would be lost as those URLs would break with any slug change and couldn’t be recovered.

As with other fields, you might need to apply a specific field method to the field when rendering, e.g. how when using a textarea with KirbyTags you need to apply ->kirbytext() to render it correctly. For the writer field this is ->permalinksToUrls() to convert them to human-readable URLs. Not complicated.

We will explore in a future Kirby version if there could be a catch-all field method for writer fields, e.g. ->toWriterHtml() (though I don’t like that name particularly), that would apply this modification as well as others potentially, so one doesn’t have to remember multiple field methods but just this one.