简体   繁体   中英

Extend template conditionally in Twig

Take the following tree structure:

├───base
│   ├───0001
│   │   └───pages
│   │           file.twig
│   │           file_content.twig
│   └───ext
│       └───store
│       │   └───pages
│       │       └───all
│       │       │       file.twig
│       │       └───0001
│       │               file.twig
│       └───newsletter
│           └───pages
│               └───all
│               │       file.twig
│               └───0001
│                       file.twig
└───pages
    │   file.twig
    └───0001
            file.twig

As you can see, there's a load of file.twig scattered around.

I want to render the contents of the file base/0001/pages/file_content.twig .
But, I want that the following files can change the content inside blocks:

  • ext/<...>/pages/0001/file.twig
  • ext/<...>/pages/all/file.twig
  • /pages/0001/file.twig
  • /pages/file.twig

But, these files may or may not exist, may or may not be needed and must be able to change the content of any block.

Is there any way to make this work?

So far, I have the following:

{% embed 'base/pages/file_content.twig' %}
    {% block page_file %}
        {{ parent() }}
        {% if data.store_enabled %}
            {% include [
                    'base/ext/store/pages/0001/file.twig',
                    'base/ext/store/pages/all/file.twig'
                ] ignore missing
            %}
        {% endif %}
        {% include ['pages/0001/file.twig', 'pages/file.twig'] ignore missing %}
    {% endblock %}
{% endembed %}

This "works", in the sense that it renders the page but doesn't allow any block to be overrided.

How could I make this work?


As an example, consider this structure of files (yes, files are missing, and that's expected):

    ├───base
    │   ├───0001
    │   │   └───pages
    │   │           file.twig
    │   │           file_content.twig
    │   └───ext
    │       └───store
    │       │   └───pages
    │       │       └───0001
    │       │               file.twig
    └───pages
            file.twig

The file base/0001/pages/file_content.twig has the following:

{% block page_file %}
    {% block title %}<h1>Nice title</h1>{% endblock %}
    {% block price %}{% endblock %}
    <div class="clearfix"></div>
{% endblock %}

The file base/ext/store/pages/0001/file.twig has the following content:

{% block price %}<span class="price">55 &euro;</span>{% endblock %}

And the file pages/file.twig has:

{% block title %}{{ parent() }}<hr>{% endblock %}
{% block price %}<div>{{ parent() }}</div>{% endblock %}

The output I expect is the following:

<h1>Nice title</h1><hr>
<div><span class="price">55 &euro;</span</div>
<div class="clearfix"></div>

But with that code, all the other files' changes are being ignored and the output is being only the following:

<h1>Nice title</h1>
<div class="clearfix"></div>

Note:

It's important to notice that I'm using Twig 1.33.2, and using the Twig_Autoloader::register(); method.

I can't use Twig 2.x, since it requires PHP 7.0+ and I'm restricted to PHP 5.3.29.

After a few more attempts, I've finally figured a way to do this.

This is as ugly as it may seem...

Assuming the structure:

├───base
│   ├───0001
│   │   └───pages
│   │           file.twig
│   │           file_content.twig
│   └───ext
│       └───store
│       │   └───pages
│       │       └───0001
│       │               file.twig
└───pages
        file.twig

The main file ( base/pages/file.twig ) has the following code:

{% if data.store_enabled %}
    {% include [
            'base/ext/store/pages/0001/file.twig',
            'base/ext/store/pages/all/file.twig',

            'base/pages/file_content.twig'
        ] ignore missing
    %}
{% else %}
    {% include [
            'pages/0001/file.twig',
            'pages/file.twig',

            'base/pages/file_content.twig'
        ] ignore missing
    %}
{% endif %}

This will include the files inside base/ext/store/pages/ if they exist. If a file is missing there, then the file base/pages/file_content.twig is included.

All the files inside base/ext/store/pages/ must have the following code on the top:

{% extends [
        'pages/0001/file.twig',
        'pages/file.twig',

        'base/pages/file_content.twig'
    ]
%}

And the files inside pages/ must have the following:

{% extends 'base/pages/file_content.twig' %}

This allows you to have override any block inside base/pages/file_content.twig and the files are only included/extended if they exist.

Having there a garanteed file (in this case, base/pages/file_content.twig must always exist) will still display the "default" content and won't throw a nasty exception.


Outside of the scope of this answer, I've initially found a very similar aproach, which used conditional values.

Try it on: https://twigfiddle.com/u06tur

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM