Automagically loading suitable scripts in <head>

I’m using a theme which has the following files:

  • layouts/partials/header.html – the part provided by the theme
  • layouts/partials/head_custom.html – for adding own scripts etc., header.html loads this

Also, I have created some shortcodes which need specific JS libraries. So far, they are all included in head_custom.html for every page. But the shortcodes are not used on every page!

So, my idea is the following:

  1. Set a variable in the shortcodes ($i_need_library)
  2. Check in head_custom.html for the presence of this variable
  3. Only if variable is present, include library.

Is this possible somehow? I could not achieve it so far.

If there is a forum question for this already, I’m sorry that I haven’t found it yet; however, most similar entries seem to suggest a solution by manually setting front matter information, which I do not want.

Hi,

You can check .HasShortcode: https://gohugo.io/templates/shortcode-templates/#checking-for-existence

Thank you! This works nicely now in my “posts” pages, however it does not work on the list pages. In both templates (single.html and list.html) the header partial is included in exactly the same way.

Could this be related to the .Summary behaviour? I use this command in list.html, manually setting <!--more--> in my posts for the summary to be rendered correctly.

Do all pages in the rendered Group contain this shortcode or not?

If the latter then of course the scripts will be included, since not all pages contain that shortcode.
If the former please provide a repo that reproduces the issue for us to have a better look.

Not all pages contain the shortcode. I didn’t think about this. So just to clarify, .HasShortcode only evaluates to true if all pages in a list page have the shortcode? From my userspace kind of view I would have expected Hugo to look at the (list) page, see that the shortcode is included (because of the appearance in at least one summarised page) and behave like is it there then…

Maybe I should just generally include the scripts without condition in list.html, which of course would be less nice if I want to change anything later.

.HasShortcode returns true for the specific page context. So, if you have a posts/_index.md that uses that shortcode, it will evaluate to true on your list.html layout.

You will need to include some logic to do this. Something like (untested)

{{ $include := false }}
{{ if .IsNode }} <!-- list page -->
  {{ if .HasShortcode }} <!-- list page _index.md uses shortcode -->
    {{ $include = true }}
  {{ end }}
  {{ range .Pages }}  <!-- check child pages -->
    {{ if .HasShortcode }} 
      {{ $include = true }}
    {{ end }}
  {{ end }}
{{ else }}  <!-- single page -->
  {{ if .HasShortcode }} 
    {{ $include = true }}
  {{ end }}
{{ end }}
1 Like

Technically, this works (with, in my case, another recursion because .Pages is only “Posts” and the articles are below that).

However it is just as good as when I did not have any check at all (for list pages; for single pages it definitely is an improvement), because this checks every whole article, resulting in “of course we need all those scripts” even if the shortcodes are only used after the summary.

Is there any possibility to filter out the “raw” contents in the summary? .Summary.HasShortcode does not work, probably because it’s already the rendered HTML.

As I mentioned above, .HasShortcode returns true for a specific page context. .Summary is not a page. .Summary.HasShortcode will not work.

Read more about page variables here: https://gohugo.io/variables/page/

I did say you would need to add logic. The snippet was just a suggestion for how that might look.

You can split the .RawContent of the Page (not .Summary) delimited by <!--more-->. Then findRE your shortcode names.

Thank you for the explanation and the links! From there on, I could make it work. In case anyone ever has a similar objective, this is a possible solution:

{{ $includeScript := false }}
{{ if .IsNode }} <!-- list page -->
	{{ range .Pages }}	<!-- check child pages -->
		{{ range .Pages }}	<!-- another recursion because of the "/posts/xyz" structure; does work with category lists -->
			{{ $rawsummary := split .RawContent "<!--more-->" }}	<!-- prepare for checking only the part of the article that will show up on the list page -->
			{{ if (findRE "{{< first-shortcode|{{< second-shortcode" (index $rawsummary 0)) }} <!-- check if this part uses the shortcode -->
				{{ $includeScript = true }}
			{{ end }}
		{{ end }}
	{{ end }}
{{ end }}
{{ if or (.HasShortcode "first-shortcode") (.HasShortcode "second-shortcode") }} <!-- check if single page or list page itself use the shortcode -->
	{{ $includeScript = true }}
{{ end }}

Later on, include the script with

{{ if $includeScript }}
	<script type="text/javascript" src="{{ "js/my-fancy-script.js" | relURL }}"></script>
{{ end }}

This is suitable for the shortcodes first-shortcode and second-shortcode both needing the same script my-fancy-script.js. Adapt to your needs!

1 Like

This topic was automatically closed 2 days after the last reply. New replies are no longer allowed.