How to check if .Inner is empty - hugo

I am trying to write a {{< gallery >}} shortcode that will either generate a gallery with all the images in a directory you define, the contents you define via .Inner, or simply all the image resources related to the page. Here are the forms I'm trying to support:
{{< gallery dir="/gallery/alaska/" />}} - specified directory
{{< gallery >}} {{< figure src="image1.jpg" >}} {{< /gallery >}} - specified inner content
{{< gallery >}} - use all the image resources
I can process the first two, but it is not clear to me how to determine if there nothing in the .Inner variable so I can process form 3 above. I would expect to do something like the following:
{{- with (.Get "dir") -}}
// do stuff with the specified directory (works fine)
{{- else -}}
{{- if .Inner }}
{{ .Inner }} // Always executes
{{- else -}}
// do stuff related to resources in this page
{{- end }}
{{- end }}
How do I detect the bare shortcode with no arguments nor inner content?

The key to making this work is to use an empty tag in the form of <tag/> so that there is inner content but it is empty.
This means the following code works if you use {{< gallery />}} as your shortcode:
{{ with (.Get "dir") }}
// do stuff with the directory
{{ else }}
{{ with .Inner }}
{{ . }}
{{ else }}
// do stuff related to this page
{{ end }}
{{ end }}

Related

How to embed a YouTube playlist in hugo website

I can make use of the following code, {{< youtube hvWSg6NblSU >}} to embed the YouTube video in hugo website, where hvWSg6NblSU is the value in following url: https://www.youtube.com/watch?v=hvWSg6NblSU
Instead of embedding a single video, I want to embed the following playlist: https://www.youtube.com/playlist?list=PLDe3_HhjV1foHQbtGpdo0FSmsMrVykuKJ
Question: Is there a way I can embed the above playlist. Basically I am trying to make a page using hugo which will show the playlist on YouTube.
In the following link: https://naresh-chaurasia.github.io/talk2naresh/course/python-kids/, I have a single YouTube video but want to add link to entire playlist using hugo. Is it possible.
Although I can create a hyperlink to the playlist, but I want to display the YouTube playlist.
Thanks.
It is not supported by the built-in youtube shortcode.
What you can do is create a new youtube shortcode for playlists.
Steps
Create: /layouts/shortcodes/youtubepl.html
In that file place the following: (based on the built-in youtube shortcode)
{{- $pc := .Page.Site.Config.Privacy.YouTube -}}
{{- if not $pc.Disable -}}
{{- $ytHost := cond $pc.PrivacyEnhanced "www.youtube-nocookie.com" "www.youtube.com" -}}
{{- $id := .Get "id" | default (.Get 0) -}}
{{- $class := .Get "class" | default (.Get 1) -}}
{{- $title := .Get "title" | default "YouTube Video" }}
<div {{ with $class }}class="{{ . }}"{{ else }}style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"{{ end }}>
<iframe src="https://{{ $ytHost }}/embed/videoseries?list={{ $id }}{{ with .Get "autoplay" }}{{ if eq . "true" }}&autoplay=1{{ end }}{{ end }}" {{ if not $class }}style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" {{ end }}allowfullscreen title="{{ $title }}"></iframe>
</div>
{{ end -}}
(aside: If you prefer to have a different shortcode name, simply change the filename. For example, if you prefer to use {{< ytplaylist >}} change the shortcode filename to ytplaylist.html.)
Usage
Usage is the same as the built-in {{< youtube >}} shortcode, just use the new shortcode name like so: {{< youtubepl id="ID-HERE" >}} or {{< youtubepl ID-HERE >}}.
Instead of the video ID, you'll use the playlist ID.

Hugo v0.55.x Deprecation Errors - ".File.BaseFileName" on zero object

I've been experimenting with finding a fix for a new deprecation error that occurs with Hugo version 0.55.5:
.File.BaseFileName on zero object. Wrap it in if or with: {{ with .File }}{{ .BaseFileName }}{{ end }}
The two affected snippets of code in question:
{{ $header := print "_header." .Lang }}
{{ range where .Site.Pages "File.BaseFileName" $header }}
{{ .Content }}
{{else}}
{{ if .Site.GetPage "page" "_header.md" }}
{{(.Site.GetPage "page" "_header.md").Content}}
{{else}}
<a class="baselink" href="{{.Site.BaseURL}}">{{.Site.Title}}</a>
{{end}}
{{end}}
&& the footer:
{{ $footer := print "_footer." .Lang }}
{{ range where .Site.Pages "File.BaseFileName" $footer }}
{{ .Content }}
{{else}}
{{ if .Site.GetPage "page" "_footer.md" }}
{{(.Site.GetPage "page" "_footer.md").Content}}
{{end}}
{{end}}
I've been attempting different variations of wrapping those segments of code with {{ with .File }} as the error message suggests, but it isn't liking anything I've been coming up with. As an example, if I put that surrounding bit of code around the {{ range ... }} statement, I get the error: can't evaluate field Site in type source.File. If someone could assist in figuring out where {{ with .File }} should be placed, it would be greatly appreciated.
You get this error
can't evaluate field Site in type source.File
Because the context changes when inside with. To fix it, wrap your code in a {{ with .File }} as you mentioned.
Then everywhere you're using .Site, replace it with site.
Then make sure you're using Hugo version 0.53.0 or higher, so that the site keyword is available.

If statement for taxonomies?

I have a switch and want to add an if statement for taxonomies but don't know how to call it? I tried if .IsTaxonomy but get an error...
{{ if eq .Type "blog" }}
{{ .Title }}
{{ end }}
{{ if eq .Type "help" }}
{{ .Title }}
{{ end }}
{{ if eq .Type "reviews" }}
{{ .Title }}
{{ end }}
{{ if .IsHome }}
home
{{ else if eq .Type "page" }}
{{ .Title }}
{{ end }}
I have a switch and want to add an if statement for taxonomies but don't know how to call it? I tried if .IsTaxonomy but get an error...
The .Type variable that you use with your if statements is something that Hugo gets from the content folder (more precisely the section). So your posts stored in /content/tutorial/ get the tutorial type. You can also set the type of a piece of content by hand. But .Type does not by default equal the content's taxonomy.
An alternative is to use Hugo's .IsNode page variable -- that one always returns true when the current page is a list page. That is, a page with posts from a certain taxonomy or section.
You can inspect the page's .RelPermalink variable to see if the current page contains some taxonomy name (like "reviews"). But I would advise against that, since it isn't a good practice. Any taxonomy change you make or new taxonomy means your theme's code need to be changed. Plus it also requires that you (or your users) never make a spelling mistake with taxonomy names, since else the theme's code breaks.
If I look at your if statements code, the following seems to be the equivalent of what you're trying to do:
{{ if .IsNode }}
<!-- Taxonomy and section list pages -->
{{ .Title }}
{{ else if .IsPage }}
<!-- Content pages -->
{{ else if .IsHome }}
<!-- Homepage -->
home
{{ else }}
<!-- All other pages, like the 404 page -->
{{ end }}

Resize image in Hugo (v 0.32.x) in markdown

I am trying to resize an image in Hugo (not using HTML / CSS), which is apparently available in the v 0.32 update. Beneath the "Image Processing" heading at the link in the last sentence, the following "Resize" method is described:
Resize to the given dimension, {{ $logo.Resize "200x" }} will resize to 200 pixels wide and preserve the aspect ratio. Use {{ $logo.Resize "200x100" }} to control both height and width.
I'm having some trouble implementing this in my Hugo site. In particular, I am using a .md file, and am trying to add an image which is stored somewhere else in the site's source files.
For example, here's how I would add the (not-resized) image in the .md file:
![pdf image](../static/_media/images/pdf.png)
How could I add this same file, resized to 50x50 pixels, using the resize method in the v0.32 release?
Using my newer version of Hugo (v0.53) I had to adapt the answer by JoostS a bit:
Created a page bundle
Modified the shortcode to look like this at the start:
{{ $original := .Page.Resources.GetMatch (print "images/" (.Get 0) "*") }}
You can not use it like this (in markdown). Resizing only works on resources. A resource is a file in the resource directory or a file in a page bundle. To access resources in markdown you will have to use a shortcode.
Note that you can define the static dir as the resources directory. Once you do that, you can just use the static directory and write something like:
(.Site.Resources.GetMatch "_media/images/pdf.png").Resize "50x50"
However, you should access this through a shortcode, like Talves did. I simplified his code a little for extra readability:
{{< imgresize "_media/images/pdf.png" >}}
Calling this shortcode (layouts/shortcodes/imgresize.html):
{{ $image := (.Site.Resources.GetMatch (.Get 0)).Resize "50x50" }}
<img src="{{ $image.RelPermalink }}">
As of 2022, if all you need is displaying the image in a different size, maybe Hugo’s Built-in "figure" Shortcode would do?
{{< figure src="/media/spf13.jpg" title="Steve Francia" >}}
You will need to make sure you have included your images within the content of your page usually at the level of the page itself unless you reference them using the answer I link in the note below.
NOTE: You can access resources from an outside section as in this answer
Write a shortcode
layouts/shortcodes/imgresize.html
{{ $original := .Page.Resources.GetByPrefix (.Get 0) }}
{{ $options := .Get 1 }}
{{ .Scratch.Set "image" ($original.Resize $options) }}
{{ $image := .Scratch.Get "image" }}
<img src="{{ $image.RelPermalink }}" width="{{ $image.Width }}" height="{{ $image.Height }}">
[Alternative] Shortcode accessing resource under content/media section
{{ $imagename := (.Get 0) }}
{{ $options := .Get 1 }}
{{ with .Site.GetPage "section" "media" }}
{{ $original := .Resources.GetByPrefix $imagename }}
{{ with ($original.Resize $options) }}
<img src="{{ .RelPermalink }}" width="{{ .Width }}" height="{{ .Height }}">
{{ end }}
{{ end }}
Call the shortcode from within the markdown of the page.
{{< imgresize pdf "50x50" >}}
pdf refers to the image by its name prefix to get the resource.
Using a sub folder page to access the resources
In the next example shortcode you must have a page at the same level as your images. Include an index.md at the same level (example: content/media/logos/index.md)
add layouts/shortcodes/logo-resize.html
{{ $imagename := (.Get 0) }}
{{ $options := .Get 1 }}
{{ with .Site.GetPage "page" "media/logos/index.md" }}
{{ $original := .Resources.GetByPrefix $imagename }}
{{ with ($original.Resize $options) }}
<img src="{{ .RelPermalink }}" width="{{ .Width }}" height="{{ .Height }}">
{{ end }}
{{ end }}
Call the shortcode
{{< logo-resize pdf "50x50" >}}
GitHub Example
If you're using Page Bundles you can reference any file in the page's folder, whether or not it is declared in front matter:
.
|- This is the Page (a folder)
|- index.md
|- photo1.jpg
\- photo2.jpg
INside index.md
{{< imgresize photo1.jpg "350x350" "Alternate Text" >}}
The shortcode (same as #Talves but uses GetMatch and Fit, and includes alternate text for image.)
{{ $original := .Page.Resources.GetMatch (.Get 0) }}
{{ $options := .Get 1 }}
{{ .Scratch.Set "image" ($original.Fit $options) }}
{{ $image := .Scratch.Get "image" }}
{{ $title := .Get 2 }}
<img src="{{ $image.RelPermalink }}" width="{{ $image.Width }}" height="{{ $image.Height }}" alt="{{ $title }}">
UPDATE! There is a new and better way: render hooks!
Create a render hook
For images in the markdown, you can use a ‘render hook’. This is a file that describes/overrides how markdown images are handled. To use the above approach in the render hook you should create the following file:
/layouts/_default/_markup/render-image.html
… and put this logic inside:
{{ if (resources.GetMatch .Destination) }}
<img src="
{{ ((resources.GetMatch .Destination).Fit `600x600 jpg Smart q50`).RelPermalink | safeURL }}
" alt="{{ .Text }}" />
{{ end }}
Note that we use ‘.Destination’ for the source of the original image and ‘.Text’ for the alt text defined in the markdown. Once you added the render hook all images in your Hugo project can and will be resized.
More info can be found at Hugo Codex and in the official docs.

Concatenate variable in Hugo

This snippet works wonderfully on Hugo:
{{ if and (or .IsPage .IsSection) .Site.Params.contentCommitsURL }}
{{ $File := .File }}
{{ $Site := .Site }}
{{with $File.Path }}
Link to API call
{{ end }}
{{ end }}
With,
[Params]
contentCommitsURL = https://api.github.com/repos/csitauthority/CSITauthority.github.io/commits?path=HUGO/content/
it is able to beautifully generate the following link
Link to API call
in the layout html file.
Problem Description
The URL is generated. Now I'm pulling hairs trying to figure out how to concatenate the commands { $Site.Params.contentCommitsURL }}{{ replace $File.Dir "\\" "/" }}{{ $File.LogicalName }} in a page variable such as {{ $url }}
For instance:
{{ $url := {{ $Site.Params.contentCommitsURL }}{{ replace $File.Dir "\\" "/" }}{{ $File.LogicalName }} }}
does not work
but the following does:
{{ $url := "https://api.github.com/repos/csitauthority/CSITauthority.github.io/commits?path=HUGO/content/post/vlan-101.md"}}
I want to be able to do something like this:
{{ $url := $Site.Params.contentCommitsURL + (replace $File.Dir "\\" "/") + $File.LogicalName }}
^Obviously, that doesn't work. I want to know what does.
On the Hugo discourse forum, someone hinted a solution and I was able to come up with the following.
{{ if and (or .IsPage .IsSection) .Site.Params.contentCommitsURL }}
{{ $File := .File }}
{{ $Site := .Site }}
{{with $File.Path }}
{{ $fileDir := replace $File.Dir "\\" "/"}}
{{ $url := $File.LogicalName | printf "%s%s" $fileDir | printf "%s%s" $Site.Params.contentCommitsURL }}
{{ $.Scratch.Set "url" $url }}
{{ end }}
{{ end }}
Where I want it to appear, I use the Scratch function like this:
{{ $url := $.Scratch.Get "url"}}
{{ range getJSON $url }}
<div style="display:inline-block; width:40px;"><a href="{{.author.html_url}}" target="_blank">
<img src="{{.author.avatar_url}}" alt="{{.author.login}}" text="{{.author.login}}" class="inline" width="40" height="40" style="height: 40px;height: 40px; vertical-align:middle; margin: 0 auto;"></a>
</div>
{{ end }}
The code is self-explanatory so I won't bother with a verbose description. Instead, I'd like to bring your focus on the implementation. You'll notice that the Scratch function has been used.
The hugo documentation says this:
Variables defined inside if conditionals and similar are not visible on the outside.
(see this issue)
It's a workaround that involves storing the value temporarily. here's more on scratch
Limitations
As of this moment, I feel this code is not complete. It works but, it shows the author based on commits. So multiple commits will generate the same author multiple times. I bring this limitation to your notice, to develop a creative solution. I'll update this answer when I get a satisfactory answer. Meanwhile, feel free to suggest.
here's my original answer on hugo discourse.

Resources