Skip to content
Grav 2.0 is officially stable. Read the announcement →

Community guidelines

Please keep discussions civil and on-topic. Repeated violations may lead to a temporary ban.

General

Difference in Twig conditional behavior between Grav 1.7 and Grav 2

Solved by Feature Tester View solution

Started by Pedro M 2 weeks ago · 6 replies · 142 views
2 weeks ago

Hello everyone,

I am currently reviewing the themes I maintain to ensure they are fully compatible with Grav 2, and I have noticed a behavior that seems different from Grav 1.7.x regarding Twig conditional statements.

As an example, Quark (and Quark2) contains several conditional blocks in the sidebar that display content depending on whether a plugin is enabled. For example:

TWIG
{% if config.plugins.archives.enabled %}
<div class="sidebar-content">
    <h4>{{ 'THEME_QUARK2.SIDEBAR.ARCHIVES.HEADLINE'|t }}</h4>
    {% include 'partials/archives.html.twig' with {'base_url': new_base_url} %}
</div>
{% endif %}

In Grav 1.7.x, if the Archives plugin was not installed, execution would not enter the if block.

However, in Grav 2 (current beta), the condition appears to evaluate as true even when the plugin is not installed. As a result, the <h4> element is rendered and Twig attempts to process the code inside the block.

This becomes problematic when a theme relies on filters or functions provided by optional plugins. For example, I have code similar to:

TWIG
{% if config.plugins['translate-date'].enabled %}
    {{ page.date|td(lang, format) }}
{% endif %}

If the translate-date plugin is not installed, I would expect the condition to evaluate to false and skip the block entirely. Instead, Twig enters the block and then throws an error because the td filter does not exist.

I have also tried several alternative checks, including:

TWIG
{% if config.plugins.archives.enabled is not empty %}
{% if config.plugins.archives.enabled is not null %}
{% if attribute(config.plugins, 'archives') is not null %}
{% if attribute(config.plugins, 'archives').enabled|default(false) %}

but the behavior seems unchanged: the condition still evaluates as true and execution enters the block.

My questions are:

  1. Is this expected behavior in Grav 2 / Twig 3?
  2. Has the way plugin configuration objects are exposed to Twig changed compared to Grav 1.7?
  3. What is the recommended way to detect whether a plugin is actually installed and available before using filters, functions, or templates provided by that plugin?

I would appreciate any guidance, as I am currently updating several themes and want to follow the recommended approach for Grav 2.

Thank you.

👍 2
2 weeks ago

Hi @pmoreno, I decided to test this scenario by installing one of the themes you maintain (Editorial) in a clean Grav 2 environment, and reproduced the exact behavior you are describing.

Here are a few insights and how to address them:

  1. Twig 3 Deprecations: First, I had to manually remove the deprecated {% spaceless %} tags in metadata.html.twig and base.html.twig to get the theme to render. You should probably check the Twig 3 Deprecated Features guide for other legacy syntax.

  2. The Compilation Trap: Twig is not actually entering the if block at runtime. What you are seeing is a compile-time SyntaxError, not a logical execution failure. Because Twig 3 compiles the entire template into PHP before running it, encountering an unregistered filter like |td causes a hard crash during the parsing phase, regardless of your wrapping if conditions.

How to fix:

To make your themes fully compatible with Grav 2 when dealing with optional plugin filters, you cannot keep those filters in the same file under a standard condition. You must isolate them into separate partials so the compiler doesn’t evaluate them unless the path is actually executed.

1. In your main template (partials/page-bits/date.html.twig):

Twig

TWIG
{% if config.plugins['translate-date'].enabled %}
    {% include 'partials/page-bits/date-translated.html.twig' %}
{% elseif config.plugins['twig-extensions'].enabled %}
    {% include 'partials/page-bits/date-localized.html.twig' %}
{% else %}
    {{ (page.header.publish_date) ? (page.header.publish_date|date(short_format)) : (page.date ? page.date|date(short_format) : page.modified|date(short_format)) }}
{% endif %}

2. In new isolated file (partials/page-bits/date-translated.html.twig): (We output the value directly using {{ }} because variables set inside an include do not bubble up to the parent template scope).

TWIG
{{ (page.header.publish_date) ? (page.header.publish_date|td(lang, default_format)) : (page.date ? page.date|td(lang, default_format) : page.modified|td(lang, default_format)) }}

3. Same for (partials/page-bits/date-localized.html.twig):

TWIG
{{ (page.header.publish_date) ? (page.header.publish_date|localizeddate('medium', 'none', lang)) : (page.date ? page.date|localizeddate('medium', 'none', lang) : page.modified|localizeddate('medium', 'none', lang)) }}

And you're back on the road! 😉

2 weeks ago

Hi @b.da,

thank you very much for taking the time to test this in a clean Grav 2 environment and for the detailed explanation and suggested approach — it really helped clarify what was going on.

I’ve now tested your proposed solution, and I can confirm the behavior you described regarding Twig 3 and plugin filters.

In particular:

  • The twig-extensions plugin does not work correctly with Grav 2. It throws an exception related to the Twig_Environmenttype hint, which suggests it is not fully compatible with Twig 3.
  • The translate-date plugin does not produce a visible error, but it also does not seem to work as expected, likely due to the same underlying incompatibility with Twig 3 and the current Grav 2 architecture.

So even though the conditional structure in the theme is correct, both plugins appear to be incompatible with Grav 2 at this stage, which makes the original approach unreliable.

Based on this, I think the best direction for now is to avoid relying on these plugins in themes targeting Grav 2, and instead implement a more self-contained solution within the theme itself (or wait for updated versions of the plugins that fully support Twig 3).

Thanks again for your help and for pointing me in the right direction — it was very useful for understanding the root cause of the issue.

2 weeks ago

Could you please create an issue for translate date plugin? I'll address it at some point. Unfortunately it might be only sometime in autumn 😞

Eventually I'll have to go through all of my plugins anyway

2 weeks ago

Okay. I'll do it as soon as I can. I'm going to look into a few more things. Grav 2 has kept us very busy this summer. 😅

6 days ago

I had something similar, turned out to be a bug in that rc version. In the latest rc it respects the check whether a plugin is active or not.

👍 1

Suggested topics

Topic Participants Replies Views Activity
General · by Jerry Hunt, 3 days ago
2 67 3 hours ago
General · by pamtbaau, 8 hours ago
1 44 8 hours ago
General · by Andy Miller, 21 hours ago
0 40 21 hours ago
General · by Marcel, 12 months ago
6 341 4 days ago
General · by Duc , 5 days ago
3 35 5 days ago