Escape shortcodes when processing Markdown using RenderString

I’m having trouble escaping shortcodes when passing them through the RenderString function. I have some Markdown which contain shortcodes inside of code blocks and I want to prevent Hugo from processing the shortcodes.

Here’s a reduced test case: let’s say I put this into a shortcode template:

{{ print 
    "```go-html-template\n" 
    `{{< qr text="https://gohugo.io" />}}` 
    "\n```" 
    | .Page.RenderString 
}}

Output:

This will output a code block with a QR code in it. This is not what I want.

The conventional solution is to escape shortcodes using something like {{</* foo */>}} but that’s not working in this case.

{{ print 
    "```go-html-template\n" 
    `{{</* qr text="https://gohugo.io" /*/>}}` 
    "\n```" 
    | .Page.RenderString 
}}

Output:
Screenshot 2025-07-01 at 7.04.54 PM

This outputs a code block which contains {{</* qr text="https://gohugo.io" /*/>}}. The escape characters are left intact.

How do I escape shortcodes inside Markdown when using RenderString?

See https://github.com/gohugoio/hugo/issues/10058.

Can you call your shortcode using the {{% %}} notation instead?

{{% sc %}}
Some **other** text.

```go-html-template {style=friendly}
{{</* qr text="https://gohugo.io" /*/>}}
```

Some **other** text.
{{% /sc %}}

layouts/_shortcodes/sc.html

{{ .Inner }}

rendered:

Thanks for the suggestion, @jmooring.

In my case, the Markdown content is being imported from an external source and my shortcode doesn’t use .Inner.

I would have expected the RenderString function and the content renderer to treat escaped shortcodes in the exact same manner but that doesn’t seem to be the case.

You might consider substitution.

{{ $s := `
Some **other** text.

~~~go-html-template
{{< qr text="https://gohugo.io" />}}
~~~

Some **other** text.
`
}}

{{ $s | strings.ReplaceRE "{{<" "@@@" | .Page.RenderString | strings.ReplaceRE "@@@" "{{<" | safeHTML }}

where “@@@” is any string that is unlikely to appear anywhere. You only need to replace one of the delimiters.

The only reason I’m using ~~~ is to make this example work where the input is multiline. Your input can use triple backticks.

And the only reason I’m using strings.ReplaceRE instead of strings.Replace is that I can pipe—the argument order of strings.Replace isn’t great.

Thanks again, @jmooring, I appreciate the help.

One work-around I found was to replace the triple backticks with the {{< highlight >}} shortcode. Escaping seems to work reliably when the code is inside that shortcode.

Something like this works:

{{ print 
    "{{< highlight go-html-template >}}\n" 
    `{{</* qr text="https://gohugo.io" /*/>}}` 
    "\n{{< /highlight >}}" 
    | .Page.RenderString 
}}

Perhaps I misunderstood. If what you’re receiving is always a code example, why not use the transform.Highlight template function directly?

The examples that I gave above were simplified for clarity. The actual strings being rendered in my custom shortcode contain more than just code. They often also include things like paragraphs and headings written in Markdown, interspersed with code samples.

1 Like