Markdown Render Hooks - GitHub and Hugo compatible links

Hi guys,

with new Hugo 0.62 there are new possibilities. I am especially keen to see the following:

With this, you can get Markdown links that work on both GitHub and Hugo…

Source: https://gohugo.io/news/0.62.0-relnotes/

Before I take a deep dive into this, I would like to ask the community if there is already an implementation of this particular feature.

This would be great for wiki-like content.

Thanks, and I wish Hugo and all great folks around a wonderful 2020! :tada:

I don’t think so. I was thinking about creating a small “proof of concept” doing this, but this Christmas has been lazy … It should not be too hard, tough, the clues being:

  • use Markdown links either “root relative”, e.g. “/docs/my-page.md” or page-relative, e.g. “my-page.md”, “…/blog/my-article.md” etc.
  • Then use {{ (.Page.GetPage .Destination).RelPermalink }} in the hook template (with some added checks for the “not found case”)
4 Likes

This template works great:

Note that the project itself doesn’t run with the current Hugo version. I thought I should be clever and use the README.md as the home page content file, but there were some missing pieces re. mounting of content files (i.e. not directories). I will get to that in a bit …

2 Likes

Thanks @bep

My first draft for Markdown compatible site links like:

[My Article](../my-article/index.cs.md)

Template: /layouts/_default/_markup/render-link.html

{{ $urlBase := strings.TrimPrefix "../" (path.Dir .Destination) }}
{{ $url := (.Page.GetPage $urlBase).RelPermalink }}
<a href="{{ $url }}">{{ .Text }}</a>

Resolves into:

<a href="//localhost:1313/cs/blog/my-article/">My Article</a>

As you mentioned it needs some checks for the “not found case”, but sharing first POC anyway.

Not sure what the trim is there for, but note that .Page.GetPage does properly handle them. The dots have a meaning (navigate one up).

I am unable to get the url without getting rid of the ../ (thanks for the info, I know its meaning).

I payed with the .Page.GetPage for a while, but from my experiments, it seems it does not handle the ../. I am getting nopPage

See my test:

[My Article](../my-article/index.cs.md)
{{ $path := (path.Dir .Destination) }}
{{ $urlBase := strings.TrimPrefix "../" $path }}
{{ $url := (.Page.GetPage $urlBase).RelPermalink }}
{{ $url2 := (.Page.GetPage $path) }}

<pre>
    .Destination
    {{ .Destination }}

    $path
    {{ $path }}

    $urlBase
    {{ $urlBase }}

    $url
    {{ $url }}

    $url2
    {{ $url2 }}
</pre>

Using: Hugo Static Site Generator v0.62.0/extended darwin/amd64 BuildDate: unknown

OK, I have tested this, and GitHub does not support “…” in Markdown links, which is a litle bit surprising.

Also see https://github.com/bep/portable-hugo-links

All right, I am getting lost a bit by now.

  1. We did not discuss ... just ../ so perhaps this is just misspelled.

  2. The ../ does work in your example:
    https://github.com/bep/portable-hugo-links/blame/master/docs/d1.md#L9
    https://portable-hugo-links.netlify.com/docs/d1/

  3. I am unable to replicate your working example.

    • Your repository is giving me error: Error: Error building site: process: readAndProcessContent: walk: Readdir: fdopendir: not a directory but this is something your are already on the top of it.

    • Even if I use your render-link.html template and even if I add markup section into config.yaml (not sure if that is required), I am unable to generate the working link - keep generating the original url.

What am I missing to just get the working example running as presented in https://github.com/bep/portable-hugo-links ?

Thanks!

I probably get why your example works, but my does not.

* [Blog Link1](../blog/p1/index.md)

matches:

/blog/p1/

It works just because your semi-relative structure matches exactly the URL structure.

.Page.GetPage just removes ../ instead of truly resolving the path.

If you use a relative path which does not match with any URL, then it does not work:

[My Article](../my-article/index.cs.md)

You need to update your Hugo version.

Add 2.) fixed by version v0.62.1

Add 3.) Fixed by update of .Page.GetPage in version v0.62.2

Out of curiosity… did my previous post help you to identify the .Page.GetPage issue?

Yes, it made made me go back and test it. I made my test site a little too complicated (the mounts from blog => posts), which made me think that GitHub did not support “…” style of links. But all in all a good thing that I got to fix these issues.

1 Like

Thank you @bep for support and quick fixes.

To close this off, here is the minimul working example for relative links like:

[My Article](../my-article/index.md)
<a href="{{ (.Page.GetPage .Destination).RelPermalink | safeURL }}">{{ .Text | safeHTML }}</a>

For more complex example in test project, follow: https://github.com/bep/portable-hugo-links

Can the content of that github link be added into the hugo docs regarding render-link.html or integrated into a future release?

It nicely fixes the problem hugo seems to have always had of links to anchors in other markdown docs, i.e. [link](some-page.md#an-anchor-link) - never used to render to html correctly.

{{ $link := .Destination }}
{{ $isRemote := strings.HasPrefix $link "http" }}
{{- if not $isRemote -}}
{{ $url := urls.Parse .Destination }}
{{- if $url.Path -}}
{{ $fragment := "" }}
{{- with $url.Fragment }}{{ $fragment = printf "#%s" . }}{{ end -}}
{{- with .Page.GetPage $url.Path }}{{ $link = printf "%s%s" .RelPermalink $fragment }}{{ end }}{{ end -}}
{{- end -}}
<a href="{{ $link | safeURL }}"{{ with .Title}} title="{{ . }}"{{ end }}{{ if $isRemote }} target="_blank"{{ end }}>{{ .Text | safeHTML }}</a>