A different image shortcode
Posted on July 24, 2023 (Last modified on August 17, 2023) • 8 min read • 1,555 wordsAdd more options to the image shortcode.
The Hinode theme, I am using on this site, has already a very functional way of displaying images in content, which is the image
shortcode that can be found in layouts/shortcodes/image.html
file. This shortcode makes use of the layouts/partials/utilities/Getimage.html
and the layouts/partials/assets/image.html
partials for the actual work.
Even though the image
shortcode already did a lot of things very well, I still wanted a few changes, which were the following:
The new shortcode and underlying functionality is still compatible with the existing functionality and I could have just changed the relevant files, however, I decided to copy the existing code into new files and make the changes there, leaving the original ones untouched. It is just neater that way. This resulted in the following new files:
mimage
shortcode layouts/shortcodes/mimage.html
mGetimage
partial to get the image: layouts/partials/utilities/mGetimage.html
mimage
partial to show the image: layouts/partials/assets/mimage.html
Additionally the following file is needed:
mimage
shortcode, in the file assets/scss/components/_mimage.scss
.The detailed information on how to use and install the shortcode is available in the documentation.
The source code of the shortcode starts with a check of all the parameters (see also
this page for all the parameters).
One of these parameters is src
, which specifies which image to load. This is part of the code that takes care of loading the image in layouts/partials/utilities/mGetImage.html
.
1{{ $url := .url -}}
2{{ $page := .page -}}
3
4{{ $img := "" }}
5{{ $remote := hasPrefix (lower $url) "http" }}
6{{ if $remote }}
7 {{ $img = resources.GetRemote $url -}}
8{{ else }}
9 {{ if $page }}
10 {{ $img = $page.Resources.GetMatch $url }}
11 {{ end }}
12 {{ if not $img }}
13 <!-- Do we have a headless bundle? -->
14 {{ $headless := $page.GetPage "headless" }}
15 {{ if $headless }}
16 {{- $img = $headless.Resources.GetMatch $url -}}
17 {{ end }}
18 {{ end }}
19 {{ if not $img }}
20 {{ $img = resources.GetMatch $url }}
21 {{ end }}
22{{ end }}
The highlighted part is the part that was added by me. The mGetImage
partial has two input parameters, url
and page
. What happens in this snippet is that first a check is performed on whether or not the url
is for a remote image. If so it tries to load that image. If not, we get to line 9.
If the shortcode is used in a page bundle (index.md
or _index.md
) the code on line 11 will try to load the image relative to the page. If this image cannot be found or when the page where the shortcode is used is not a page bundle, the code will go to line 12 to check if there is a headless page bundle defined. This is true when there is a folder headless
in the same folder as where the page with the shortcode is located, and in that headless
folder there is an index.md
file with the following frontmatter:
---
headless: true
---
If the image cannot be found, the code tries to load the specified image from the assets
folder. If that also fails, no image will be found.
The caption and credits for the image is specified when the shortcode is used or, either derived from a file or from the Exif information of the image. The following shows the code that takes care of that:
1<!-- Check if we need to derive the caption automatically from non-remote images -->
2{{- if eq $autoCaption "true" -}}
3 {{- $remote := hasPrefix (lower $url) "http" -}}
4 {{- if and (not $remote) (or (not $caption) (not $credits)) -}}
5 <!-- Check for existence of a .txt file with the same name as the current image, or for a description in the EXIF -->
6 {{ $textPath := printf "%s/%s.txt" (path.Dir $img.RelPermalink) (path.BaseName $img.RelPermalink) -}}
7 {{ if os.FileExists $textPath -}}
8 <!-- read the file -->
9 {{- $reading := split (os.ReadFile $textPath) "|" -}}
10 {{- range $index, $value := $reading -}}
11 {{- if and (not $caption) (eq $index 0) -}}
12 {{ $caption = $value }}
13 {{- end -}}
14 {{- if and (not $credits) (eq $index 1) -}}
15 {{ $credits = $value }}
16 {{- end -}}
17 {{- end -}}
18 {{- end -}}
19 {{- with $img.Exif -}}
20 {{- if not $caption -}}
21 {{- $caption = .Tags.ImageDescription -}}
22 {{- end -}}
23 {{- if not $credits -}}
24 {{- $credits = strings.Title (lower .Tags.Artist) -}}
25 {{- end -}}
26 {{- end -}}
27 {{- end -}}
28 {{- if and $caption (not $title) }}
29 {{- $title = $caption -}}
30 {{- end -}}
31{{- end -}}
This code is only executed when autocaption
has been set to “true”, the image is not remote and the caption and/or the credits have not been set as a parameter.
Line 6 builds the name of the text file that has the caption and/or credits for the current image. The name of the file is the same as the name of the image being processed, but with the extension .txt
. Following that a check is performed if the file exists and if so, it will read the file.
The format of the file is expected to be as follows:
This part is the caption|and this is the credits
The part before the |
character is the caption and the part following the |
character is the credits. If there is no |
character, everything is processed as the caption. When there are only credits, the contents of the file should start with the |
character, followed by the credits. Any text after a second |
character will be discarded. This is realized in lines 9-17.
When the caption or credits have not been found yet, an attempt is made to read it from the Exif information that is normally stored in the image file. This takes place in lines 19-26. In line 24, each first letter in the caption is capitalized. The reason for this is that some camera’s store the photographer’s name in all caps.
One of the changes that is not further detailed out here is that the ratio of 3x2 has been added. This has been made part of the code that creates the imgset
, which is used in the below code. This is a set of images of different sizes that will be used for different screen sizes.
1{{- if or $caption $credits -}}
2 <figure {{ with $outerClass }}class="{{ . }}"{{ end }}>
3{{ end }}
4 <div class="{{ with $ratio }}ratio ratio-{{ . }}{{ end }}{{ if not (or $caption $credits) }} {{ $outerClass }}{{ end }}">
5 <img class="img-fluid {{ $innerClass }}"
6 {{ with $imgset -}}
7 srcset="{{ . }}"
8 sizes="100vw"
9 {{- end }}
10 src="{{ absURL $fallbackURL }}"
11 alt="{{ $title }}">
12 </div>
13{{- if or $caption $credits -}}
14 <!-- Add camera to credits -->
15 {{- if $credits -}}
16 {{- $icon := partial "assets/icon.html" (dict "icon" "fas fa-camera") }}
17 {{ $credits = printf "%s %s" $icon $credits }}
18 {{- end -}}
19 <!-- Place credits in brackets if there is both a caption and a credit -->
20 {{- $break := "" -}}
21 {{- if and $caption $credits -}}
22 {{- $credits = printf " ( %s)" $credits -}}
23 {{- end -}}
24
25 <figcaption class="figure-caption {{ $captionClass }}">{{ $caption | safeHTML }}{{ $credits | safeHTML }}</figcaption>
26</figure>
27{{- end -}}
The major change this code has compared to the original code, is the addition of the caption and credits, and how classes are assigned to the image and the caption/credits. The changed code is highlighted.
When there is neither a caption or credits, both the outerClass
and innerClass
are assigned to the image. When either the caption or credits exits, the image and the capt6ion/credits are wrapped in a figure
and the outerClass
is assigned to the figure, the innerClass
to the image, and captionClass
to the caption/credits. Furthermore a camera icon is added in front of the credits.
Compared to the parameters of the shortcode, outerClass
corresponds to outer
, innerClass
to inner
and captionClass
to text
.
The image
shortcode provides already a lot of functionality, but I just wanted a bit more and something slightly different, which the mimage
shortcode provides. If you like it, feel free to use it.