19

Is it possible to use template parameters in the content of a post with Hugo? E.g. if I have the following parameters:

[params.company]
name = "My Company"

Can I then do something like this in the content of a post?

This site, {{ .Site.BaseURL }} is operated by {{ params.company.name }}

I've tried, but it's literally printing the above instead of interpolating the variables.

jbrown
  • 7,518
  • 16
  • 69
  • 117
  • In normal go template, you would write `.Params.company.name` and you wouldn't name the variable itself params. I've edited the question to not confuse the next readers. – TamaMcGlinn Jun 17 '20 at 09:01
  • As correctly pointed out by the edit reviewer, only you may fix the mistakes, as my suggested edit changes the content of your post; what I'm saying is that you should change `params.company` to just `company` - otherwise you are defining a parameter called params, which must be addressed as `.Params.params.company.name`. Note that second mistake, the reference should start with `.Params` not simply `params` - it's case insensitive but the custom is to have the P capital. – TamaMcGlinn Jun 23 '20 at 13:17

3 Answers3

16

1. Front matter way

As far as I'm aware, it's not possible* to put variables within the markdown file's content because MD parser would strip them, but it's possible to do it using custom variables on the front matter of each .md content file. The Hugo engine can target any fields you set in front matter. Front matter fields can be unique as well.

In your case, the template which is called to show the rendered .MD file has access to front matter parameters and you can change template's behaviour (like add classes of extra <div>'s) or even pull the content right from the parameter.

For example, on my .md files I have:

---
title: "Post about the front matter"
<more key pairs>
nointro: false
---

The key nointro: true would make my first paragraph to be normal size. Otherwise, if key is absent or false, first paragraph would be shown at larger font size. Technically, it's adding a custom class on a <div>.

In the template, I tap into the custom parameter nointro this way:

parent template which shows your markdown file, which has front matter parameters:

<div class="article-body {{ if .Params.nointro }} no_intro {{ end }}">
{{ .Content }}
</div><!-- .article-body -->

Notice I can't put variables within {{ .Content }}, but I can outside of it.

For posterity, that's piece of the content from a file hugo/themes/highlighter/layouts/partials/blog-single-content.html, it's a partial for single post content. You can arrange your partials any way you like.

Obviously, that's Boolean parameter flag, but equally it could be content which you could use directly:

MD file's top:

---
title: "One of our clients"
<more key pairs>
companyname: "Code and Send Ltd"
---

Text content is put here.

Then, reference it like this (extra insurance against blank value using IF):

Anywhere in Hugo template files:

{{ if .Params.companyname }}{{ .Params.companyname }}{{ end }}

2. Using config.(toml/yaml/json)

Now, looking at your example, "This site is operated by " would almost warrant a custom field in more global location, for example, hugo/config.toml. If I wanted to add a companyname into my config, I'd do it this way:

hugo/config.toml:

BaseURL = "_%%WWWPATH%%_"
languageCode = "en-uk"
title = "Code and Send"
pygmentsUseClasses = true
author = "Roy Reveltas"
theme = "Highlighter"
[params]
  companyname = ""

Then I'd use it anywhere via {{ .Site.Params.headercommentblock }}.

I guess if you want your client pages to be static pages then single location might not be the best and you might want to tap into front-matter. Otherwise, if it's a site's footer, this way is better. Alternatively, you could even put this data even on data files.


3. Using custom placeholders and replacing via Gulp/npm scripts

I said not possible*, but it's possible, although unconventional and more risky.

I had such setup when I needed two builds for my website: 1) Prod and 2) Dev. Prod URL's were coming from two places: CDN and my server. Dev had to come from a single place in a static folder because I wanted to see images and was often working offline on a train.

To solve that, I used two custom variables in all my templates (including markdown content): _%%WWWPATH%%_ and _%%CDNPATH%%_. I came up with this unique pattern myself by the way, feel free to adapt it. Then, I put it also on hugo/config.toml as:

hugo/config.toml:

BaseURL = "_%%WWWPATH%%_"

After Hugo happily generated the website with those placeholders, I finished off the HTML's using a Grunt task:

grunt file:

replace: {
  dev: {
    options: {
      patterns: [{
        match: /_%%CDNPATH%%_+/g,
        replacement: function () {
          return 'http://127.0.0.1:1313/'
        }
      }, {
        match: /_%%WWWPATH%%_+/g,
        replacement: function () {
          return 'http://127.0.0.1:1313/'
        }
      }...

For posterity, I recommend Gulp and/or npm scripts, I'd avoid Grunt. This is my older code example above from the days when Grunt was the best.

If you go this route, it's riskier than Hugo params because Hugo won't error-out when your placeholder values are missing or anything else wrong happens and placeholders might spill into the production code.

Going this route you should add multiple layers of catch-nets, ranging from simple following Gulp/Grunt/npm scripts step which searches for your placeholder pattern to pre-commit hooks ran via Husky on npm scripts that prevent from committing any code that has certain patterns (for example, %%_). For example, at a very basic level, you would instruct Husky to search for anything before allowing committing this way:

package.json of your repo:

"scripts": {
  "no-spilled-placeholders": "echo \"\n\\033[0;93m* Checking for spilled placeholders:\\033[0m\"; grep -q -r \"%%_\" dist/ && echo \"Placeholders found! Stopping.\n\" && exit 1 || echo \"All OK.\n\"",
  "precommit": "npm run no-spilled-placeholders"
},

Basically, grep for pattern %%_ and exit with error code if found. Don't forget to escape the code because it's JSON. I use similar (more advanced) setup in production and nothing slips through. In proper setup you should creatively look for anything mis-typed, including: %_, _%, %__, __% and so on.

Community
  • 1
  • 1
revelt
  • 2,312
  • 1
  • 25
  • 37
  • Hmm OK I guess I could add a token and replace it post-generation with sed. It's a pity that's my only option though. Thanks anyway. – jbrown Feb 06 '17 at 10:18
  • 1
    Points 1 and 2 of this answer describe using variables in templates, but not directly in the content of posts or pages. Option 3 would work but is completely overkill if you can use the param shortcode. – Kevin Apr 24 '20 at 14:54
11

Normal Go template is not supported in the markdown file, but shortcodes are:

{{< param "company.name" >}}

To access arbitrary other Go template values, create a custom shortcode for it and call that from your markdown file.

For your example, you need the site's baseUrl, so save this as layouts/shortcodes/base_url.html:

{{ .Site.BaseURL }}

And write this in your markdown file:

+++
[company]
name = "My Company"
+++

This site, {{< base_url >}} is operated by {{< param "company.name" >}}
TamaMcGlinn
  • 2,840
  • 23
  • 34
  • 1
    Just to note that Hugo's documentation implies that you should be able to use the `$.Param` method to [access page fields in front matter content](https://gohugo.io/variables/page/#the-param-method), but it doesn't seem to work. – Jon Gibbins Jun 18 '21 at 15:48
  • But how about for email? I use `{{< param email >}}` which works, but if you want to linkify it in markdown you need to wrap in angled brackets. But sadly `<{{< param email >}}>` prints nothing – Mark Sep 08 '22 at 12:03
  • can you make your custom shortcode emit the extra angle brackets? So, in your markdown you would only have `{{< my_email_shortcode >}}` or similar. – TamaMcGlinn Sep 08 '22 at 12:05
  • This is really helpful. Actually, according to the asked question, the best way should be using the global configs. But this piece of information was really helpful for me. I was trying to develop some sub page layouts, while working on a big open sourced template. So instead of writing partials, I just used this trick. – Mesut Yılmaz Jan 29 '23 at 15:22
7

There is also the shortcode param : {{< param "companyName" >}} : https://gohugo.io/content-management/shortcodes/#param

Multicolaure
  • 864
  • 8
  • 15