Fake "replace" fixes possible bug with shortcodes

I have simple shortcode for Quizdown.js:

{{ $_hugo_config := `{ "version": 1 }` }}
<div class='quizdown'>
  {{ .Inner }}
</div>

And here is simple Quiz:

## Quiz Time!

{{< quizdown >}}

### Where is it recommended to place non-essential internal scripts for optimal page load performance?

- [ ] In the `<head>` section
- [x] At the end of the `<body>` section
- [ ] In an external file
- [ ] In a `<div>` element

> **Explanation:** Placing non-essential scripts at the end of the `<body>` allows the HTML content to load first, improving perceived performance.

{{< /quizdown >}}

Quizdown javaScript library expects uncompressed plain Markdown wrapped in div.

This shortcode generates unescaped output which breaks the page HTML:

<h2 id="quiz-time">Quiz Time!</h2>

<div class='quizdown'>
  

### Where is it recommended to place non-essential internal scripts for optimal page load performance?

- [ ] In the `<head>` section
- [x] At the end of the `<body>` section
- [ ] In an external file
- [ ] In a `<div>` element

> **Explanation:** Placing non-essential scripts at the end of the `<body>` allows the HTML content to load first, improving perceived performance.


</div>

However, by just adding fake replace function, it works:

{{ $_hugo_config := `{ "version": 1 }` }}
<div class='quizdown'>
  {{ replace .Inner " " " "  }}
</div>

Output:

<h2 id="quiz-time">Quiz Time!</h2>

<div class='quizdown'>
  

### Where is it recommended to place non-essential internal scripts for optimal page load performance?

- [ ] In the `&lt;head&gt;` section
- [x] At the end of the `&lt;body&gt;` section
- [ ] In an external file
- [ ] In a `&lt;div&gt;` element

&gt; **Explanation:** Placing non-essential scripts at the end of the `&lt;body&gt;` allows the HTML content to load first, improving perceived performance.



</div>

Not a bug.

You need to escape special HTML characters (use the htmlEscape function), then tell Go’s html/template package that the resulting string is a safe HTML document fragment (use the safeHTML function).

<div class='quizdown'>
  {{ .Inner | htmlEscape | safeHTML }}
</div>

Your no-op replacement worked because string functions (with the exception of strings.Truncate) return values with a string data type. Go’s html/template package then kicks-in, escaping as needed to make the output safe against code injection.

You don’t need this at the top of your shortcode:

{{ $_hugo_config := `{ "version": 1 }` }}

That on-the-fly configuration setting isn’t documented, and was primarily intended to help site and theme authors transition to v0.55.0 back in 2019. Yes, it still works, but you should get out of the habit of using it.

4 Likes

Thanks, it does the trick! I tried individually htmlEscape and safeHTML but not both…

However, this is strange: {{ replace .Inner " " " " }} will escape, and {{ .Inner }} won’t. Perhaps “replace” wilt try to unescape :wink:

That’s because the shortcode Inner method returns template.HTML … it’s already marked as safe.

1 Like

WOW I think I understand now: .Inner is marked as safe, but applying dummy function to it makes it “unsafe” so it will be escaped.

1 Like

Bingo.

1 Like

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