Search code examples
symfonymacrostwigbolt-cms

Cleanly including css/js required by content in a macro?


I have a page template like so:

{# page.twig #}    
{% import "_widgets.twig" as widgets %}

{% include '_header.twig' %}

<body>
    {{ widgets.fancy_widget(record.items) }}
    {# more content goes here #}
</body>

_header.twig contains the <head> tag and some blocks for css and javascript:

{# _header.twig #}
<!DOCTYPE html>

<head>
    {% block javascripts %}
    {% endblock %}

    {% block stylesheets %}
    {% endblock %}
</head>

_widgets.twig contains a macro which generates some markup

{# _widgets.twig #}
{% macro fancy_widget(fanciful_items) %}

    {# insert special css and js into <head> only if the macro is used #}
    {% block stylesheets %}
        <link rel="stylesheet" href="css/some_fancy_widget.css">
    {% endblock %}

    {% block javascripts %}
        <script src="js/some_fancy_widget.js"></script>
    {% endblock %}


    {% for item in fanciful_items %}
        {# output some fancy markup #}
    {% endfor %}

{% endmacro %}

What I'd like to do is add the widget css/js to the blocks in _header.twig if the macro is called. Ideally they'll only be added once, so multiple calls won't create extra <link> and <script> tags.

Is this possible? Or is there a better way to accomplish this?


Solution

  • I would say that you are not using Twig correctly.

    In fact your page.twig must extends base.html.twig.

    {# app/Resources/views/base.html.twig #}
    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="UTF-8" />
        <title>{% block title %}Welcome!{% endblock %}</title>
        {% block stylesheets %}{% endblock %}
        <link rel="icon" type="image/x-icon" href="{{ asset('favicon.ico') }}" />
    </head>
    <body>
        {% block body %}{% endblock %}
        {% block javascripts %}{% endblock %}
    </body>
    </html>
    

    Then your page.html.twig must extends this base.html.twig

    You cannot define or overide blocks in macros. The simplest way will be:

    In your page.html.twig:

    {% extends 'base.html.twig' %}
    {% import "_widgets.twig" as widgets %}
    {% block stylesheets %}
        {{ parent() }}
        <link rel="stylesheet" href="css/some_fancy_widget.css">
    {% endblock %}
    {% block javascripts %}
        {{ parent() }}
        <script src="js/some_fancy_widget.js"></script>
    {% endblock %}
    {% block body %}
    
    {% endblock %}
    

    and the rest (Your macro) : _widgets.twig :

    {# _widgets.twig #}
    {% macro fancy_widget(fanciful_items) %}
    
    
    {% for item in fanciful_items %}
        {# output some fancy markup #}
    {% endfor %}
    
    {% endmacro %}