How do I add css/js to `<head>` from partial content/template

In baseof.html or in a partial called within the <head> of baseof.html

{{- $shortCodeName := "foo" -}}
{{- $regex := printf "{{(<|%%)\\s%s\\s(>|%%)}}" $shortCodeName -}}
{{ with findRE $regex .RawContent }}
  <link rel="stylesheet" href="foo.css">
  <script src="foo.js"></script>
{{ end }}

This looks at the raw content of the page. If it finds that you’ve called a shortcode via {{< foo >}} or {{% foo %}} it will add add some CSS and JavaScript.

EDIT: This is a generic, low-level approach to parsing content. I’ve used this in the past to search for the inclusion of AMP components, specific HTML attributes, etc. To look for an individual shortcode, use .HasShortcode instead.

It is getting interesting!

This is a step forward… the inclusion if now controlled by the (raw) contents of the page. Usable in a number of situations.

The ultimate goal remains: Can I do something in the shortcode to control the inclusion?

(The answer may be ‘no’, but the question is intriguing.)

Sure. For example:

layouts/shortcodes/foo.html:

<span data-foo>{{ .Inner | .Page.RenderString }}</span>

Then, in baseof.html, use findRE against .Content instead of .RawContent to look for data-foo:

{{- $regex := "data-foo" -}}
{{ with findRE $regex .Content }}
  <link rel="stylesheet" href="foo.css">
  <script src="foo.js"></script>
{{ end }}
3 Likes

Bingo!

So the magick is: have the shortcode generate something ‘visible’ in the content, and examine the content in the base template. Nifty.

1 Like

I find this quite awkward (and prone to future portability issues) … is this the best we have? It sounds like block/define should have been the answer but their behavior still stumps me – you can have multiple defines of something and don’t get duplicate content in all pages, while other defines do push their guts in all pages. Docs aren’t very clear.

Perhaps you meant to say, “Thank you for taking the time to share what has worked for you and your team.” :grinning:

4 Likes

Touche. Forgot indeed to say thanks.

I, too, took time to share what worked for me, so I wasn’t a complete asshole, just a regular asshole.

1 Like

Given that the page content is fully processed before it is passed to the base html I’d expect to be able to exchange information via the page Scratch.

@jmooring and all

Thanks for this - its helpful (at least I could potentially write instructions with a shortcode to tell a user to modify the baseof.html

But is there a maybe future feature request here? to allow a shortcode to fire / hook into the head to add in scripts?

Sorry - being new maybe this is already on the roadmap?

thanks

I think that the .HasShortcode function largely addresses this requirement, in a very flexible way.

2 Likes

… sure - makes sense if I’m rolling my own theme … or am skilled enough to code

Equally I also don’t expect all theme developers to get on board and put a {{ if .HasShortcode}} in their theme

Oh wait … I guess I’m thinking about theme components which can extend Hugo and the main theme.

and maybe shortcodes should just have these natural limitations (like not being able to add content to the

See also Use conditional for css style with shortcode

thanks @sciurius

But would .Page.Scratch be populated when baseof.html is supposed to output ? In other words, does Hugo populate all .Content and .Page.Scratch before starting to render html in baseof.html? I didn’t find a clear explanation of the order of execution of the various components in Hugo. Looking again at @jmooring’s example above, he suggests doing a regex find on .Content to detect if some html string exists that was part of a shortcode, but shortcodes can be called in a number of places, e.g. invoked from some partial called within inside baseof.html, and all sort of other funky invocations. Are there clear docs to explain the execution path to cover all situations?