SDC: Make empty render arrays evaluate to false in component templates

Created on 5 March 2024, 4 months ago
Updated 18 June 2024, 8 days ago

Problem/Motivation

There is a huge Drupal core issue about evaluating a render array as true or false from a Twig template: 🌱 [meta] Themes improperly check renderable arrays when determining visibility Needs work

In certain situations regions that contain empty blocks still render.
The core issue is that there is no possible way to definitely identify an 'empty' block without first
rendering it.
The ideal result is the ability to add this to a template:

{% if region %}
  <div>{{ region }}</div>
{% endif %}

Very annoying but, after 13 years, still no fix. But I hope it may be fixable at SDC level.

Steps to reproduce

Let's do some tests on Drupal 10.1.1 with this variable:

{% if description %}<p class="fr-tile__desc">{{ description }}</p>{% endif %}

We expect description to be resolved at false.

Test 1: empty array

$variables['description'] = [];

OK: description is false, because in PHP an empty array is false

Test 2: non renderable properties

$variables['description'] = [
  "#cache" => [
    "contexts" => [
      "user.permissions"
    ],
    "tags" => [],
    "max-age" => -1
  ]
]

KO: description is true

Test 3: non renderable properties wrapped in a sequence

$variables['description'] = [
 [
  "#cache" => [
    "contexts" => [
      "user.permissions"
    ],
    "tags" => [],
    "max-age" => -1
  ]
]
]

KO: description is true

Test 4: non renderable properties wrapped in a mapping

Layout Builder is sometimes wrapping the render array in a mapping where the key is the block UUID:

$variables['description'] = [
"cf124739-3274-41cc-829d-c3465ee4eaa5" => [
  "#cache" => [
    "contexts" => [
      "user.permissions"
    ],
    "tags" => [],
    "max-age" => -1
  ]
]
]

KO: description is true.

Test 5: empty mapping

$variables['description'] = [
    "whatever" => []
];

KO: description is true.

Test 6: empty #markup

 $variables['description'] =  [
    "#markup" => "",
  ];

KO: description is true.

Same with #plain_text I guess...

Proposed resolution

So, it may be fixable at SDC level because we are lucky to know:

  • which Twig variables are expecting a render array : the slots as defined in the component definition
  • where to put the bubbled properties: the component render array ([#type => 'component'])

2 informations other render elements are not able to know easily.

So, in ComponentElement::preRenderComponent() for each component slot:

  1. if the array is not a render array, do a recursive loop on items
  2. if the array is a render array where all the children are empty AND where all properties are non-printable or empty:
    • move the non-printable properties (#cache, #attached... what else?) to the component render element if they are bubbable
    • remove the non-printable properties (#weight... what else?) if they are not bubbable
  3. unset the keys of empty children & empty properties

So, the renderable will be evaluated to false by Twig if empty πŸ‘

πŸ› Bug report
Status

Active

Version

11.0 πŸ”₯

Component
single-directory componentsΒ  β†’

Last updated about 21 hours ago

Created by

πŸ‡«πŸ‡·France pdureau Paris

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Comments & Activities

Production build 0.69.0 2024