1
votes

I have layout template

<html>
<body>
{% block content %}{% endblock %}
</body>
</html>

And many child templates like this

{% extends 'layout/default.twig' %}
{% block content %}
    <p>content</p>
{% endblock %}

And it's very annoying that every single child template in Twig must include {% block content %}...{% endblock %} to be extended by parent block, otherwise there will be error: A template that extends another one cannot have a body.

Is there any solution to bind all child template output(that is not located in any block) in some variable, and then use it to paste in parent template? Like this:

Layout

<html>
<body>
{{ _context.childOutput }
</body>
</html>

Child

{% extends 'layout/default.twig' %}
<p>content</p>

It will make child templates code more compact and there will be no dependency from parent templates blocks name.

UPD Submitted new issue on Twig's GitHub https://github.com/twigphp/Twig/issues/2027

3
Only "clean" way to achieve this imo would be to create your own parser that extends from the twig's one and move the non-content block into a default block / variableDarkBee
Look at the include command: twig.sensiolabs.org/doc/tags/include.htmlEmanuel Oster
include and emeb commands are bad issues because they still adds some trash in child templates, and makes it depended from "parent" template context.barbushin
Is the content of the child template static? Does it contain variables?A.L

3 Answers

1
votes

The 2 lines you have in each template allows you aswell to redefine many blocks in one template. I can't see how the solution you want can do that.

<html>
<head>
{% block meta %}{% endblock %}
</head>
<body>
{% block content %}{% endblock %}
</body>
</html>

you can see include and embed but if you really have only one block in your templates twig is maybe not the solution you need

1
votes

While seeing in this GitHub issue that you define variables in the controller, I had the following idea. I'll assume that the child template only contain static code since you didn't describe this point.

You can modify the function in your controller in order to fetch the content of the child template then pass it to the parent template directly:

function acmeAction()
{
    // …

    return $this->render(
        'AcmeBundle:layout:default.html.twig',
        array(
            'title' => $title,
            'description' => $description,
            'content' => file_get_contents(
                $this->container->get('kernel')->locateResource(
                    '@AcmeBundle/Resources/views/layout/child.html.twig'
                )
            )
        )
    );
}

And the parent template:

<head>
    <title>{% block title %}{{ title }}{% endblock %}</title>
    <meta name="description" content="{% block description %}{{ description }}{% endblock %}" />
</head>
<body>
    {% block body %}{{ content }}{% endblock %}
</body>

This way you won't need to define the parent in the child template.

0
votes

You can define some variables in the child and display them in the parent:

Layout

<html>
<body>
{{ myValue }
</body>
</html>

Child

{% set myValue %}
    <p>content</p>
{% endset %}
{% include 'layout/default.twig' %}

This works because:

Included templates have access to the variables of the active context.

Source: http://twig.sensiolabs.org/doc/tags/include.html


And it's very annoying that every single child template in Twig must include {% block content %}...{% endblock %} to be extended by parent block

While it may sound annoying when you only have one variable, you will see the benefits of this approach when you will have to define also the title of the page, the JavaScript code, etc. In this case the use of multiple {% block … %} is really useful.

See this example:

Layout

<html>
<head>
    <title>{% block title %}{% endblock %}</title>
</head>
<body>
    {% block content %}{% endblock %}
    {% block javascript %}{% endblock %}
</body>
</html>

Child

{% extends 'layout/default.twig' %}

{% block title %}
    My title
{% endblock %}

{% block content %}
    <p>content</p>
{% endblock %}

{% block javascript %}
    <script>…</script>
{% endblock %}