Injecting JavaScript from shortcode?

Apologies if this has already been asked.

I was wondering whether there is a way of injecting js files from within a shortcode? I have a gallery shortcode on my site that requires some additonal js for a lightbox. The js is quite heavy, so I’d rather only load it on pages that actually have a gallery.

If possible, I’d like to be able to check whether a shortcode has been used on a page in the template, and only add the script element if the shortcode has been used at least one. The shortcode is used within markdown, rather than the template. If this worked, I could then extend the system for other components such as accordions or tabs etc.

Does anyone know of any way of achieving something like this?

Currently I have a lightweight js ‘loader’ file that uses a query selector and conditionally requires es6 modules if it finds an element with a certain class, but if possible I’d like to do away with this and just add the script element to the end of the body on pages where it is needed.

1 Like

That should already work if you mark the output in the template as | safe?

Hi keats, thank you. Where would I put the script tag, and how would I check for duplication to ensure it was only loaded once?

You have nth variable for each shortcode. You should include your JS only when this variable is equal to 1.

2 Likes

I’d not seen that nth variable, thank you. I was hoping to find a way of conditionally injecting the files from the page template, so they are all at the end of the body element, but will look into using nth to inject it from the shortcode itself.

Thanks again.

IMO it would be really good to add this use-case to that page on the docs.

Sorry for late post, but I am unsure how this would work. Presumably the shortcode would be add any output into it’s own location. But supporting JavaScript would go into the header or footer of the web page?

I’m curious because I would like to replicate the behaviour of the mathjax plugin for Wordpress. It uses the shortcodes in content and loads mathjax if and only if it is needed. The shortcode expands to mathjax syntax locally, but also forces the load of mathjax in the header.

You can require a script anywhere in the page, it’s just that by default it would block the rendering of the page unless you use defer. I don’t know Wordpress but I don’t see how a shortcode could access <head>.

In wordpress the content is parsed before the header is produced. So the shortcode just sets a global variable while it is doing it’s other work. I’ve given this a go in zola, but it is not clear to me what the global context is. It doesn’t appear that variables from a shortcode are visible to other parts of the template. I don’t know if this is because of the scope or because the order in which things are evaled.

Shortcodes are pure functions in Zola: they just get the args and render the corresponding template. You cannot set anything from a shortcode in the outer context. Do you have a link to an explanation on how it works in Wordpress that I could read?

I am not sure what explanation you are after. Wordpress shortcodes call a function. This sets a variable. The variable is then enacted later.

The equivalent in zola would be something like having a shortcode defined so:

{% set_global latex=true %}

and then in one of the page templates you would have something like:

{% if latex %}
latex has happened
{% else %}
latex has not happened
{% endif %}

Another possibility would be add some configuration to the front-matter. But as far as I can see from __tera_context arbitrary front matter is not available to templates. So, the only solution that I can see at the moment is to have two page templates, one with mathjax enabled and one without, which I can configure in the front-matter. That works, of course, but means multiple templates rather than conditional logic.

Everything you set in the extra section is available.

I see. Then it’s definitely not going to work like that. Content rendering is pretty far from the template it’s actually going to be rendered in in Zola.

Ah, I had missed that! Thank you, I can use this as a solution.

Okay. It would need a generalization of the nth variable I guess for this to work. Well, the extra front-matter is a good solution for my use case. Wordpress doesn’t have a real equivalent to front matter (although you can add metadata in the GUI) hence the use of shortcodes.