Smart Link Support?

Is there way to do smart links, something that would turn FOO-1234 into a link that points to https://foo.example.com/FOO-1234?

I am looking for this to work on every page in the site and am not looking for a shortcode and am not looking for a javascript solution either.

If that means a literal replacement of a plain text with the link simplest I see is a regular expression on the rendered content.

Instead of {{- .Content -}}in your main blocks use.

{{ .Content | replaceRE `\b(FOO-\d{4})\b` "<a href=\"https://foo.example.com/$1\">$1</a>" | safeHTML }}

This will replace “FOO-” followed by four digits between word boundaries with the link.

input: this FOO-1234! will be replaced, but thatFOO-1234 not.

output: this FOO-1234! will be replaced,but thatFOO-1234 not`

readings: safe.HTML

Hmm that could work but i have like 20 of these to do. We use them across our discourse, chat servers, and other stuff for quickly linking to issues and stuff.

Although I suppose I could drop a list in the config and then iterate that in the template. I’ll give that a shot.

Thanks!

rescannig each page 20 or so times might not be the fastest. think about storing a full regex in a param and call that once.

or use a partial that constructs the pattern from a list of singe patterns/fixed texts … and calls the replacement.

if your replacements strings are fixed there’s strings.ReplacePairs

but that depends on the “like FOO-1234” and “20 or so”

Hmm, replacePairs could work, but it’s going to get a bit insane.

Here’s our current setup from discourse and I need to add 2 additional ones for this site that should probably end up in discourse as well.

It’s hard to tell from here, but a lot of the URLS are pretty similar, but there are ones that are completely different.

Also I forgot that the specific ones I’m trying to do right now come from front matter not content.

ReplacePairs is not a regex replace. for your shown list you would need a generation step. still might be faster than multipass the content.

the patterns (except the first) seem to match [A-Z][A-Z0-9]+-[0-9]+

accessing front matter is not a problem. Details depend on details of that frontmatter layout

just to make sure:
you have a Hugo site with static (not generated!) Markdown pages (links typed in) where these smartlinks should be replaced on all pages.

without the full picture it’s hard to come up with something

  • what to replace on all pages (global patterns)
  • page based replacements (pattern or text)
  • frontmatter settings …

usually a SPEC would be nice maybe a comprehensive example with the variants.

If it where mine, i would probably go with a compromise between “very simple adding” and a “specific tag” to handle. and use a link render hook smart://ABC-123

  • Just one place to change the logic
  • no change to other template blocks
  • access to page front matter and link attributes
  • configuration possible with config file, data files, …
  • possible error handlink (link checking, missing replacements, …)

Example showcase: [](smart://FOO-1234)

  • link render hook based on the embedded one:

    {{- $u := urls.Parse .Destination -}}
    {{- if eq $u.Scheme "smart" }}
       {{- partial "smartlink" (dict "link" $u.Host "page" .Page) }}
    {{- else -}}
       {{- /* content of the embedded hook /* -}}
    {{- end }}
    {{- /**/ -}}
    
  • replacement starter partial

    {{- /* whatever replacement, verification logic is here */ -}}
    {{- $link := .link | replaceRE `\b((\w+)-\d{4})\b` "https://$2.example.com/$1" }}
    <a href="{{ $link }}">{{ .link }}</a>
    {{- /**/ -}}
    

So, for Markdown you could either:

  • Write these as Markdown links, e.g. [FOO-1234]() (I think you need the empty parens?) and render them as you please in a link render hook.
  • Define Passthrough render hooks and add a template for that. You would need some delimiters, though. FOO may work as the start delimiter.

To help clarify what exactly I’m looking for, I want something that does this automatically for me, like smart links, auto linkers, etc. Using markdown links and delimiters defeats the purpose.

The site in question is https://security.imfreedom.org. The immediate problem is on the Advisories page where I want the advisory identifier links (cve-, talos-, whatever) to the official disclosure page. On this page, those identifiers come from front mater of a child page, so a partial or filter or something might be necessary. Here’s an example of a child page.

The actual articles are copy that is shared all over the place, emails, discourse, this site, social media, etc, so having to modify it for publication on any platform increases the amount of work dramatically, which is why automating this is important. The current pages are still a work in progress but an example can be seen here.

While it hasn’t been a priority in the past, we’re trying to add additional metadata, like the links to the issues where these were reported, links to the fixed revisions, etc etc, which is why all of it is in the front matter.

As I mentioned, this copy is used all over just like all the other copy we have. A good example is our change logs. Using the Auto Linkify Words component of Discourse, we are able to copy our literal change log from version control which looks like the following

* Cleanup license check script
  Elliott Sales de Andrade, RR 4539
* Move the build containers to the imfreedom organization
  Gary Kramlich, RR 4613
* Prepare for the new round of API development
  Gary Kramlich, RR 4672
* Add StringList
  Gary Kramlich, RR 4692
* Add a pango attribute for handling mention data
  Gary Kramlich, RR 4693, BIRB-26

And have it rendered with links automatically as seen here

This example is live here.

I looked at doing this via a goldmark extension and run across hugo-goldmark-extensions, which could make this possible but I won’t have the bandwidth to implement it there for quite a while.

The viewable things help to get an impression on the thing you want to do.

anyway

  • CVE in frontmatter of some other page, you could just extract that, create a link and add to the card. no regex replace for that use case.
  • changelog will need a replace unless you change it to a link when generating it.

for the use cases where you have the IDs somewhere in a “data” (frontmatter, data file, get-remote, …) and the target page is generated with a template I assume you won’t need a post generation - brute force - regex on the target page but handle it in the generation templates.

Imho passthrough won’t work with that multi tag setup. It allows you to have multiple start-end markers [ ['CVE-', ' '], [ 'RR ', ' ' ] ] but you won’t be able to see which one has been triggered from within the hook.

For me there are still too many open points regarding the source/data organization and the initial relation to especially no shortcode which implies the tag is part of a markdown source file (before generation) while JS leads to a displayed html page…
But from what I’ve seen it rather looks like a set of machine generated pages with links from data.
No way to come up with more than these general statements.

I created this issue to possibly improve this:

Yes this does look like it would solve this, so I’m going to mark it as the solution. Thanks!