Use shortcode within definition of shortcode - hugo

How can I reuse a shortcode in Hugo within another shortcode?
I only found a way to nest shortcodes within markdown but what I want to do is to reuse a shortcode within the definition of another shortcode.

No not in the definition, but you can use nested Shortcodes.
The nested approach is the official one (as discussed here):
Nested Shortcodes
You can call shortcodes within other shortcodes by creating your own templates that leverage the .Parent variable.
.Parent allows you to check the context in which the shortcode is being called.
See Shortcode templates.
See an illustration here: this is a workaround, and not one shortcode using another.

You can do it with partials as a workaround: You can outsource your reusable shortcode into a partial and call that inside your shortcode as often as you want. For the sake of an example, I'm going to write my own string to lowercase function:
layout/partials/string-to-lower.html:
{{- $stringOriginal := . -}}
{{- $stringLower := $stringOriginal | lower -}}
{{- return $stringLower -}}
layout/shortcodes/some-shortcode.html:
{{- $myString := "TeST" -}}
{{- partial "string-to-lower" $myString -}}
{{< some-shortcode >}} will then print test in your content.
If you want to use your shortcode not only in other shortcodes, but also in your content, then you can work with a wrapper shortcode for your outsourced shortcode (partial):
layout/partials/string-to-lower.html (the outsourced code):
{{- $stringOriginal := . -}}
{{- $stringLower := $stringOriginal | lower -}}
{{- return $stringLower -}}
layout/shortcodes/string-to-lower.html (the wrapper):
{{- with .Get 0 -}}
{{- partial "string-to-lower" . -}}
{{- end -}}
Then you can use {{< string-to-lower "TeST" >}} in your content or {{- partial "string-to-lower" "TeST" -}} in your templates to print test.

Related

How do I avoid nil pointer evaluating resource.Resource.Permalink with Hugo static site generator using range .Pages?

I'm trying to create a schema for events within a range of pages. This works fine for a single page but I'm trying to add on my list template so I have all the events. I'm getting the following error currently: nil pointer evaluating resource.Resource.Permalink
....{{ define "JSON-LD" }}
{{ range .Pages }}
<script type='application/ld+json'>
{
"#context": "https://www.schema.org",
"#type": "Event",
"name": "{{.Description}}",
"url": "{{.Params.eventURL}}",
{{ with .Params.images -}}
"image": [
{{- range $index, $element := . -}}
{{- if ne $index 0 -}}, {{ end }}
{{ $image := $.Resources.GetMatch $element -}}
{{ $image.Permalink -}}
{{- end }}
],
{{ end -}}....
That error is due to the Resources.GetMatch coming back nil and therefore their is a nil pointer when you try to get {{$image.Permalink}}
{{ with }} is a good option to check for success before you try to get the Permalink.
However, the error you describe is an error you probably want as it means you have a resource not found - i.e. $element is not a valid resource in that case, which you should fix in the markdown or wherever you are getting it from as then, you have no real, at build time, way to know you have an invalid resource.
I hope that helps.

Hugo shortcode adding extra space at end of link text

I'm using a Hugo shortcode to add a class to links. We want to copy Wikipedia's style for "red links", pages that haven't been built yet but are planned.
The shortcode red-link.html looks like this:
{{ with .Get "title" }}{{.}}{{else}}{{.Get "url"}}{{end}}
When I use it in a markdown file, it looks like this:
Here is an {{< red-link title="example red link" url="#" >}}.
What I want is this (no space between link text and punctuation):
<p>Here is an example red link.</p>
What I get is this:
<p>
"Here is an "
example red link
" ."
</p>
Which ends up looking like this:
What do I need to change to remove that extra space between the end of the link and the period?
I had the same issue but the project was configured to add a new line at the end of all files. Instead of reconfiguring the project to also allow files without new lines at the end, I have found an ugly, but working solution.
Given the example of catertot, you probably have the following shotcode (notice the ending new line):
{{ blabla }}
The solution is to add a {{- "" -}} at the very end of the shortcode:
{{ blabla }}{{- "" -}}
This tells Hugo to strip any whitespace behind the link itself, resulting in a perfectly inlined shortcode without spaces.
I use a Hugo theme for my website which had a custom shortcode render-link.html file in quickstart/themes/YOUR_THEME/layouts/_default/_markup by default. The solution, as another answer points out is to add whitespace delimiters {{- /* This comment removes trailing newlines. */ -}} to your file, which removes leading and trailing whitespaces. However, in my theme, this was placed after the </a> tag, rendering it useless (see below).
<a href="{{ .Destination | safeURL -}}"{{ with .Title -}} title="{{ . -}}"{{ end -}}{{ if strings.HasPrefix .Destination "http" -}} target="_blank"{{ end -}}>{{ .Text -}}</a>{{- "" -}}
Ensure your shortcode looks as follows:
<a href="{{ .Destination | safeURL -}}"{{ with .Title -}} title="{{ . -}}"{{ end -}}{{ if strings.HasPrefix .Destination "http" -}} target="_blank"{{ end -}}>{{ .Text -}}{{- "" -}}</a>
If this does not solve the problem, consider checking your IDE settings. For example, in VS Code, you should consider disabling Settings → Files: Insert Final Newline.
Check out these other threads:
Single whitespace character after custom link template for Goldmark #6832
Markdown render hooks extra space
In your shortcode file, remove everything, including all blank lines, below this:
{{ with .Get "title" }}{{.}}{{else}}{{.Get "url"}}{{end}}
If that doesn't get rid of that space, try using appropriate
Go Template trim-whitespace delimiters ({{- and -}}). For example, try changing the above to this:
{{ with .Get "title" -}}{{. -}}{{else -}}{{.Get "url" -}}{{end -}}
I had this problem with my years-since shortcode, which I wrote about at https://www.ii.com/hugo-tips-fragments/#_8_years_since.
I was using a custom render-link.html file containing an empty line, this was creating a new paragraph before each link included with a Shortcode.
Removing this empty line in render-link.html fixed my issue. To be clear:
Before:
<!-- Source: https://roneo.org/en/hugo-open-external-links-in-a-new-tab/ -->
<a href="{{ .Destination | safeURL }}"{{ with .Title}} title="{{ . }}"{{ end }}{{ if strings.HasPrefix .Destination "http" }} target="_blank" rel="nofollow noopener noreferrer" {{ end }}>{{ .Text | safeHTML }}</a>
After:
<!-- Source: https://roneo.org/en/hugo-open-external-links-in-a-new-tab/ -->
<a href="{{ .Destination | safeURL }}"{{ with .Title}} title="{{ . }}"{{ end }}{{ if strings.HasPrefix .Destination "http" }} target="_blank" rel="nofollow noopener noreferrer" {{ end }}>{{ .Text | safeHTML }}</a>

How can you get the full path of a page resource in Hugo?

I have some posts in Hugo with page resources that are SVG files that I want to include inline in the resulting HTML. For example, here's a typical folder structure:
content
+-- posts
+-- somepost
+-- index.md
+-- diagram.svg
In the post, I'd like to include the content of diagram.svg inline as part of the resulting HTML. Reading through another related question, I created a shortcode to do that that looks like this:
{{- readFile (.Get 0) | safeHTML -}}
However, this means that I need to provide the full path to the SVG resource, which results in this in my markdown:
{{< readsvg "content/posts/somepost/diagram.svg" >}}
Ideally, I would like the shortcode to find the page resource so that the markdown can be simplified to:
{{< readsvg "diagram.svg" >}}
If I use the page resource functions, I can get the resource itself by doing: {{ $svg := $.Page.Resources.GetMatch (.Get 0) }} but the resulting file name is relative to the resource bundle while readFile needs it to be relative to the top of the project. How can I get the full path of the resource so that I can pass it to readFile?
I tried to use absURL to do that but this doesn't work as I have custom URLs on posts.
Thanks to ruddra for pointing me in the right direction, the full answer that worked was:
{{ $svgFile := (path.Join (path.Dir .Page.File.Path) (.Get 0)) }}
{{- readFile $svgFile | safeHTML -}}
If you want more flexibility in how you specify the resource in the markdown, you can add a resource match to that solution:
{{ $svgRes := .Page.Resources.GetMatch (.Get 0) }}
{{ $svgFile := (path.Join (path.Dir .Page.File.Path) $svgRes) }}
{{- readFile $svgFile | safeHTML -}}
I think the svg file should be inside static directory. But still if you want to put it in same directory as the markdown files, probably you can use .File.Dir in the custom shortcode. Like this:
{{ $svgFile := print (.Page.File.Path) (.Get 0) }}
{{- readFile $svgFile | safeHTML -}}

Hugo post directory appearing on homepage, but not posts

For my blogdown-created website (using the Xmin theme), the posts directory - from which I can view individual posts - appears on the homepage, instead of individual posts.
https://joshuamrosenberg.com/
This seemed to happen after updating to the lastest version of Hugo. The source for my website is here. I'm a bit puzzled about what to do: do you have any advice?
This is due to a breaking change in Hugo 0.57.0, and I have fixed the issue in the latest version of the XMin theme. Basically you need to replace
{{ range (where .Data.Pages "Section" "!=" "") }}
with
{{ $pages := .Pages }}
{{ if .IsHome }}{{ $pages = .Site.RegularPages }}{{ end }}
{{ range (where $pages "Section" "!=" "") }}
in the template file layouts/_default/list.html.

Including source files from a repo in HUGO posts

I'm setting up a blog with HUGO, as a commented code repo, and I'm including source files right from the repos on the posts.
I've been able to get it to a working condition and want to improve it but I'm stuck.
What I've done
There's a .gitignore'd repos dir inside the HUGO site root, that holds the source code repos.
There's a getSourceFile.html shortcode:
{{ with .Get 0 }}
<pre><code>{{ readFile . }}</code>
<span class="source-footer">{{.}}</span>
</pre>
{{ end }}
Then, in the post I can use the shortcode like so:
#### Base/EntityTypeConfiguration.cs
Estas clases permiten manejar una clase de configuración por cada clase del modelo...
{{< getSourceFile "repos/EFCoreApp/src/EFCore.App/Base/EntityTypeConfiguration.cs" >}}
and I get this:
Which is pretty nice, since I don't have to copy and paste code, it's 100% up to date and I am sure it compiles.
But this is where I'm stuck!
What I would like to do
1) Setting up the repo root in the front matter so the shortcode is simpler to use, like so:
{{< getSourceFile "src/EFCore.App/Base/EntityTypeConfiguration.cs" >}}
2) Being able to pass the language as a parameter to the shortcode to use it in the highlighting feature, something like so (this does not work):
{{< getSourceFile "src/EFCore.App/Base/EntityTypeConfiguration.cs" "csharp" >}}
getSourceFile.html:
{{ with .Get 0 }}
```{{.Get 1}}
<pre><code>{{ readFile . }}</code>
<span class="source-footer">{{.}}</span>
</pre>
```
{{ end }}
Or better yet, infer it from the file extension! ;-)
I think it shouldn't be too difficult but this is my first experience with Hugo, Go and the Templates, so, Could someone help me with this, please?
Thanks in advance.
I finally got the answer in HUGO's dicussion forum, so I just wanted to post it here to finish the question.
This is the final shortcode:
{{ $file := .Get 0 }}
{{ $repoFilePath := printf "%s/%s" $.Page.Params.reponame $file }}
{{ $repoFile := printf "repos/%s" $repoFilePath }}
{{ $fileExt := replace (index (findRE "(\\.)\\w+$" $file) 0) "." "" }}
<pre><code class="language-{{ $fileExt }}">{{ readFile $repoFile }}</code>
<span class="source-footer">{{ $repoFilePath }}</span>
</pre>
And this even solves the language highlighting from the file extension.

Resources