Link validation inside render-link hook?

I’m trying to come up with a way to get some link validation without needing a site crawler or anything and I thought it’d be possible to get Hugo to take the .Destination and use it to do one of these:

  • .GetPage
  • .ReadFile
  • .FileExists

etc but I’m not having much luck.

I think what I want is for it to simply fail and give me the page it fails on if the link’s destination doesn’t exist. the Relref/ref functionality seems to do that somewhat, but I ran into some weird issues where it would only find top-level pages and broke if I tried to go deeper.

I think because a lot of my subpages use relative links, the fileExists solution won’t work.

Has anyone else been able to build some sort of link validation into this hook?

{{/*  Convert destination to string */}}

{{$x := printf "\"%s.md\"" .Destination }}

{{/*  Check if site pages exist */}}

{{ if strings.HasPrefix .Destination "http" }} 
{{else if strings.HasPrefix .Destination "https" }}
{{else}}
{{os.FileExists $x }}

{{/*  Maybe print in terminal if possible? or idk.  */}}

{{end}}

<a href="{{ .Destination | safeURL }}"{{ with .Title }} title="{{ . }}"{{ end }}{{ if strings.HasPrefix .Destination "http" }} target="_blank" rel="noopener"{{ end }}>{{ .Text | safeHTML }}</a>

also, sidenote: is it just me or is it actually pretty frustrating to validate links in general? It seems like most solutions don’t understand how hugo links work. For example in VS Code, whenever I click a simple relative link on my markdown pages I get the error “The editor could not be opened because the file was not found.” – not sure if this is a setting I can change, but it’s been a pain for a while. I’ve even had some link checkers give me bad advice and tell me links were broken that weren’t.

Link validation is a pain indeed. Regarding the VS Code issue, there is a plugin called Open File that uses some search patterns to look for the file at the cursor when you press a keyboard shortcut, and it usually finds the file in my projects - that helps a lot to me.

1 Like

At a high level, your question is:

How do I use render hooks to validate markdown link and image destinations?

Let’s reframe the question:

How do I use render hooks to accurately resolve markdown link and image destinations?

If we focus on resolution, we get validation for free. More reading…

6 Likes

This is AMAZING and is exactly what I needed. Thank you!! I definitely wouldn’t have been able to figure this out on my own, but I’m going to study this solution and learn from it. :slight_smile:

1 Like

@jmooring, thanks for the great article!

At the end, you indicate

To perform any of these operations, you can “hook” into this render hook with a partial template, after the render hook has captured the resource.

Would you mind providing an example. I am having a hard time figuring out how to do that. Here is my render-image for now. How do I include this in a partial template and where?

{{ if .Title }}
  <figure>
    <img src="{{ .Destination | safeURL }}" alt="{{ .Text }}">
    <figcaption>{{ .Title }}</figcaption>
  </figure>
{{ else }}
  <img src="{{ .Destination | safeURL }}" alt="{{ .Text }}">
{{ end }}

This is a simple example, where we call an image processing partial that resizes and converts to WebP.

git clone --single-branch -b hugo-forum-topic-44071 https://github.com/jmooring/hugo-testing hugo-forum-topic-44071
cd hugo-forum-topic-44071
hugo server

Files of interest:

  • layouts/_default/_markup/render-image.html
  • layouts/partials/process-image.html

We take the attributes and the resource for a round trip between the two.

You could also take a one-way trip from the hook to the partial, and do the rendering in the partial. That’s the approach to use if you’re going to generate multiple image sizes, a picture element, etc.

1 Like

Sorry to revive an old thread, but do you happen to have any guidance on how I could extend this to handle api/sdk reference docs that would sit under /assets/references or static/references?

I noticed the resources.Get section throws an error that it can’t handle directories. Currently links to say /references/some-package/client.html#some-thing return a warning and get very noisy unless I filter them out.

This link render hook can resolve links to global resources (files in the assets directory), but cannot validate fragments within those resources. Fragment validation is only possible within content pages.

I suppose you could try to do it with some ugly regex stuff but… yuck.

1 Like