Issue with render-link and goldmark

Hello there,
i’ve been using Hugo for some time but i’ve never really tried to customize it for my needs.

I’m using hugo v0.81.0+extended darwin/amd64 on OSX 10.14.6 (Mojave)

What i’m trying to do

I have an affiliation site running with HUGO and Google requires/suggest to add an attribute to those outgoing link added for monetization (like amazon links) to avoid passing value to the destination site(s). In the past it was used the “nofollow” attribute but now the rel=“sponsored” is the suggested option. See more details here on Google.

Since i’ve learned that HUGO can “customize” the html rendering of links i’ve decide to accomplish this feature:

  • If an outgoing link is read…
  • …if the link contains “amazon” or “amazn”…
  • …add the rel=“sponsored” attribute.
  • all the other cases, don’t change anything.

This solution would be ideal, because if there is no customized rendering, the content can be moved to another site and it gracefully downgrade to a normal rendering of links

What i’ve tried

Being a newbie in HUGO (and having no knowledge of GO), but having some experience in php and wordpress, i’ve read the official documentation and browsed for some possible options, using google and github.

I’ve found this snippet on GitHub from @bep himself:

{{ $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>

If i got this right, when the code intercept an url having a prefix of “http”, it’s considered “remote” (not local) and a target="_blank" is added to decorate the href.

This method inspired me so i changed the HasPrefix parameter to intercept the beginning of “amazon” i could add a rel=“sponsored” instead of the target="_blank".

But that was not enough

The proof of concept worked, now i needed to add 2 conditional clauses to look for “amazon” and “amazn” strings and add rel=“sponsored” to both.

And that’s where i hit my limits, i know i’d probably need to study some GO to improve the way i use the code, but this is what i’ve tried:

{{ $link := .Destination }}

{{ if (strings.HasPrefix $link "https://www.amazon")| or  (strings.HasPrefix $link "https://amzn")   }}
  {{ .Scratch.Set "sponsored" "yes" }}
{{ end }}

{{- if not ( .Scratch.Get "sponsored" ) -}}
  {{ $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 .Scratch.get "sponsored" }} rel="sponsored" target="_blank"{{ end }}>{{ .Text | safeHTML }}</a>

To explain the logic behind it:

  • if the HasPrefix is true in any of the 2 cases, write a “yes” value inside the Scratch “sponsored” variable
  • if the “sponsored” variable is not false (aka it’s set) it’s to be considered a remote url to be decorated with rel=“sponsored”.

When i try to run hugo i’ve got this error message:

Error: Error building site: “(URL REDACTED)/_default/_markup/render-link.html:8:21”: execute of template failed: template: _default/_markup/render-link.html:8:21: executing “_default/_markup/render-link.html” at <.Scratch.Get>: can’t evaluate field Scratch in type goldmark.linkContext

And that’s where i decided to ask inside the community to get some insights.

Any idea?

1 Like

or, and, and all these work different:

{{ if or (something) (something else) (etc...) }}

that seems to be your only issue. The error is about scratch, because the moment you set the scratch to something irritating is not marked as an error, the moment you try to use that is.

{{ if or (strings.HasPrefix $link "https://www.amazon")  (strings.HasPrefix $link "https://amzn") }}

should work, if the stuff in the brackets is ok (did not check).

1 Like

Awesome, it works!

For the posterity, i’ll post the entire code (but it could be further improved by looking only for part of the domain or reading the strings from array in the parameters and loop through it there are multiple domains to mark as sponsored)

{{ $link := .Destination }}
{{ $storage := newScratch }}

{{ if or (strings.HasPrefix $link "https://www.amazon")  (strings.HasPrefix $link "https://amzn") }}
  {{ $storage.Set "sponsored" "yes" }}
{{ end }}

{{- if not ( $storage.Get "sponsored" ) -}}
  {{ $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 $storage.Get "sponsored" }} rel="sponsored" target="_blank"{{ end }}>{{ .Text | safeHTML }}</a>

Wow, i’ve just realized that the “in” operator search for substring. AMAZING!

Wow, i did it!

The hardest part for me was understanding that in order to read the Site Params array called “sponsored” from inside a partial, i had to use “site.*” (underscore) variable instead of “$.Site”. :upside_down_face:

{{ range site.Params.sponsored  }}
    {{ if in $link . }} <!-- The . represents an element in $array -->
      {{ $storage.Set "sponsored" "yes" }}
    {{ end }}
{{ end }}

This topic was automatically closed 2 days after the last reply. New replies are no longer allowed.