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…

5 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