barbushin
barbushin

Reputation: 5305

Extend Twig template without blocks

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

Upvotes: 1

Views: 1602

Answers (3)

A.L
A.L

Reputation: 10483

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.

Upvotes: 1

A.L
A.L

Reputation: 10483

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 %}

Upvotes: 0

goto
goto

Reputation: 8164

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

Upvotes: 1

Related Questions