How to add stuff to <head> from a module twig

Hello!

Following the Theme Tutorial I have a user/themes/mytheme/templates/partials/base.html.twig file in my theme. As it is a modular theme, I further have another file user/themes/mytheme/templates/modular.html.twig that doesn’t extend base.html.twig and a couple of “specialized” templates extending modular.html.twig.

The most important thing is, that neither modular.html.twig nor any of its subclasses has a connection to the html <head>.

Now it happens that one of my modules needs some things added to the <head> (in my case it’s some JavaScript but more general it could be anything). This leads to my question:

Is there a clean way to add stuff to the head from a typical module twig?

Of course on solution would be to make a module template that inherits from base.html.twig but as this link would be rather synthetical I wouldn’t find this practice very elegant.

Thank you in advance!

You can use this useful piece of code that is present on several Grav Themes.
You just need to include it in your base or wherever you want to use it.

{% for meta in page.metadata %}
<meta {% if meta.name %}name="{{ meta.name }}" {% endif %},{% if meta.http_equiv %}http-equiv="{{ meta.http_equiv }}" {% endif %},{% if meta.charset %}charset="{{ meta.charset }}" {% endif %},{% if meta.property %}property="{{ meta.property }}" {% endif %},{% if meta.content %}content="{{ meta.content }}" {% endif %}/>
{% endfor %}

Thanks for sharing! However, I think I don’t understand that completely.

Using this snippet, how would I be able to add stuff to the <head>...</head> section of the page from within a module template (which has no head block)?

you have to use it on the pages that support the modular file, for exemple if you have
01.home
-_modular1
-_modular2

Just open 01.home and go to options in normal mode and you will have a metadata box that is unchecked by default

Ok. Maybe I get this all wrong but I think that metadata is about the meta tags in the header right?

I want to add some js to the <head>.

Sorry, if it’s my fault but I still don’t see how this can do what I need to do :frowning:

ohh, no it’s totally my fault, I read your first post too quickly. I thought you were wanting to add metatag.
For javascript, if the javascript you want to add is not too heavy, I would rather add it on every page, and thanks to pipelining, it might not affect your overrall performance too much.

You also have a few other solution:

  • add these js files conditionnally with an if statement.
  • add inline js
  • add it via your modular file and process it in the footer via the asset manager.

hope it helps this time!

Thank you :slight_smile: yes, that really helps!

Another option would be to load the js directly in the body.

However, my case sometimes is a bit more difficult because:

  1. some of the parameters passed to the js are related to the information in the module - therefore I cannot run the entire js in the page head (without knowing these parameters)
  2. the js needs to be loaded before the rest of the DOM - therefore I still need to run it in the head

To be more precise, the js I want to use is from google maps and looks like this:

http://www.w3schools.com/googleapi/tryit.asp?filename=tryhtml_map_first

I didn’t want to say that earlier, because I am aware of the google maps plugin. But I was looking for a general solution for such cases.

ohh, I see, but IIRC you can add the javascript in the body and it still works

You’re looking for https://github.com/getgrav/grav-plugin-assets/ ?

@paulmassendari - I tried that too, doesn’t work when the js is in the body

@flaviocopes - I saw that plugin. However, I’d like to keep my theme general, so I can maybe release it for public use later. Therefore I’d like to avoid implicit dependencies. Is there a way to make the theme install the plugin automatic (like an explicit dependency)? This would be an acceptable solution.

Otherwise I could still make modular.html.twig inherit from base.html.twig and remove everything but keep the javascript block. However, this would be more like an ugly hack than a good solution…

Yes you can, see https://github.com/getgrav/grav-plugin-login/blob/develop/blueprints.yaml#L16-L18 - works in CLI only now, but in Admin 1.1 it will be available in Admin too.

I’m not aware of a theme-only solution now, except grabbing the Assets plugin code and including it in your theme, but not ideal.

I’m not aware but there
could surely be one

Thank you so far! Of course I would prefer a standalone solution, but this is already a very good way to go. This even more as Admin 1.1 will probably be released soon.

If you (or anyone else) can think of a theme-only solution - please let me know :slight_smile:

Thank you and best regards!

I have one more idea:

If I could store and append an array of javascripts to the pages object from within a twig template, I could also loop through this array in the base.html.twig. Another possibility (although not as good) would be to store that array in the page object of the current page.

To do so, I would need the twig-syntax to store something to an existing object. Can you help me with that?

And do you see any reason why this would (not) work?