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

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.

Related

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>

Can't use template variable of type string where a string literal would be allowed?

It seems I cannot invoke .Resources.GetMatch with a template variable of type string, though I can invoke it with a string literal. I know I can invoke it with . in a with block, but would like to know why this code doesn't work.
Main template invokes partial with a second argument stuffed into .Scratch:
single.html
...html
<div >
<p>Feature image:</p>
{{ .Scratch.Set "arg1" .Params.image}}
{{ partial "local-image.html" . }}
<p>End feature image:</p>
</div>
Partial tries to retrieve the scratch argument and retrieve the corresponding page resource object:
{{ $srcPath := (.Scratch.Get "arg1") }}
{{ printf "debug type %T, value %#v" $srcPath $srcPath}}
{{ .Resources.GetMatch $srcPath }}
Hugo build error:
ERROR 2020/11/24 00:28:34 Failed to render pages: render of "page" failed:
execute of template failed: template: _default/single.html:67:7: executing "main" at <partial "local-image.html" .>:
error calling partial: "C:\Users\xyz\src\hugo-blog\themes\hugo-theme-bootstrap4-blog\layouts\partials\local-image.html:5:23": execute of template failed:
template: partials/local-image.html:5:23: executing "partials/local-image.html" at <$srcPath>:
invalid value; expected string
If I comment out the failing line so I can see the preceeding debug output,
{{ $srcPath := (.Scratch.Get "arg1") }}
{{ printf "debug type %T, value %#v" $srcPath $srcPath}}
{{/* .Resources.GetMatch $srcPath */}}
Build succeeds, and page renders this:
Feature image:
debug type string, value "IMG_20200404_164934.jpg"
End feature image:
So the puzzle here is why .Resources.GetMatch complains about $srcPath when the latter is demonstrably of type string.
(Yes, I know it would be more colloquial to pass multiple arguments into a partial in a dict, but I was running into similar errors extracting values out in the partial, so came up with the above more concise example.)
I rewrote my problematic code and came up with a workable solution, but I never did discover exactly where I was going wrong above (it remains reproducible for anyone who would like to point out exactly where I did go wrong).
To close this thread with something like an acceptable answer, here's what I did.
Maybe it will help some future wanderer...
Basically,
stuff all the arguments into a dict where the partial is invoked.
at the top of the partial, save value of . (e.g in a nicely-named local $args or $argv)
wherever you need a particular argument value, it's readily available in $args.xyzzy
I don't know why this simple and effective pattern eluded me yesterday, I see lots of similar suggestions around the web today...
single.html
...html
<div >
<p>Feature image:</p>
{{ partial "local-image.html" (dict "page" . "arg1" .Params.image) }}
<p>End feature image:</p>
</div>
Then, to retrieve or use these arguments in the partial:
{{ $args := . }}
. . .
{{ $srcPath := $args.arg1 }}
{{ printf "debug type %T, value %#v" $srcPath $srcPath}}
{{ .Resources.GetMatch $srcPath }}
Build succeeds, and page renders this:
Feature image:
debug type string, value "IMG_20200404_164934.jpg"
"IMG_20200404_164934.jpg"
End feature image:
Q.E.D.

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.

Use shortcode within definition of shortcode

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.

Resources