15

I have condition for printing regions in my page template as is not empty, but it will always print empty regions no matter what. What is the proper way to detect empty regions?

For example, {% if page.local_tasks is not empty %}{{ page.local_tasks }}{% endif %} prints out <div class="region region-local-tasks"></div>.

If I render the region in themename_preprocess_page() with var_dump(drupal_render($variables['page']['highlighted'])); I will get SafeString with placeholder token:

<div class="region region-highlighted"><drupal-render-placeholder callback="Drupal\Core\Render\Element\StatusMessages::renderMessages" arguments="0" token="a8c34b5e"></drupal-render-placeholder></div>

So, technically the region is not empty but I can do nothing about it.

4
  • What does page.local_tasks contain when you feel it should be empty?
    – Clive
    Sep 23, 2015 at 10:23
  • That's a region for local tasks block.
    – user21641
    Sep 23, 2015 at 10:54
  • Right, but what does the object contain? It's not empty, so look to see what other properties it has that might tip you off that there's no content (does it contain a string or an un-rendered array essentially?)
    – Clive
    Sep 23, 2015 at 11:04
  • I have the same problem, and it seems this is a bug
    – Yuseferi
    Sep 18, 2016 at 9:51

9 Answers 9

14

try to apply filters after render, like this :

{% set has_sidebar_first = page.sidebar_first|render|striptags|trim is not empty %}
{% if has_sidebar_first %}
    {# ... #}
{% endif %}
4
  • 1
    this worked for me Jan 21, 2018 at 20:37
  • 1
    This is quite useful. Feb 8, 2018 at 19:01
  • 4
    This approach doesn't work because it doesn't take into account that some regions might get rendered into placeholders, which then will be later replaced with the actual markup. There simply isn't any way to determine whether a region is empty or not in the html.html.twig file. If you want to read the full background of this problem, I suggest reading this Drupal Core issue
    – lauriii
    Jan 25, 2019 at 7:43
  • 1
    As @lauriii said, this does not work with drupal placeholders (my views in blocks typically get filtered out due to the strip_tags filter).
    – Dakwamine
    Mar 11, 2019 at 9:19
12

TL;DR for this is that there is no way to reliably check if region is empty or not in the template.

In Drupal 8 at the point when we are at the template level we are unable to tell whether the region has content or not because the content is rendered lazily. There is open Drupal 8 issue for this.

What you probably will have to do to achieve this is to write CSS that tests whether the region is empty. You can try using using :empty pseudo-selector.

1
  • I have concluded that the most reliable way to get around this problem is to add template suggestions in hook_theme_suggestions_HOOK_alter and remove the regions entirely from the template where its not supposed to be visible.
    – Johan
    Sep 18, 2017 at 10:08
4

This worked for me.

{% if page.sidebar_first|render|striptags %}
<aside id="sidebar-first" class="sidebar sidebar-first layout-sidebar-first" role="complementary">{{ page.sidebar_first }}</aside>
{% endif %}

Simple enough.

1
  • I'm not sure but that might be making your sidebar render twice (once for evaluation and the other time for display).
    – Jigarius
    Dec 11, 2017 at 20:38
3

In twig you should really be able to do:

{% if page.local_tasks %}{{ page.local_tasks }}{% endif %}

However perhaps there is something within page.local_tasks (like empty markup). Please try the following:

{% if page.local_tasks|striptags|trim %}{{ page.local_tasks }}{% endif %}
8
  • That debug snippet does not show anything(ie, nothing to display, the variable is empty).
    – user21641
    Sep 23, 2015 at 11:42
  • When you say debug do you mean dump? What happens if you do {% if page.local_tasks %}Crazy magic{% endif %}? Sep 23, 2015 at 11:45
  • Reading your question I see that page.local_tasks is not empty. It's full of HTML. I'll update my answer. Sep 23, 2015 at 11:47
  • Doesn't your snippet render the content twice if there is content? Or if it is rendered it is cached and it has no impact on performance? Also I don't understand why I need to do any workarounds. This should be working out of the box in the core. @Berdir any comment on this?
    – user21641
    Sep 25, 2015 at 8:37
  • The trouble is that local tasks is not empty. As twig and drupal are both following MVC there is nothing telling twig that is empty (it's not empty). Either you can write a preprocessor which overrides what local tasks provides when empty, provides another value with a 'count' type property you can test against, or something like I suggest. Somewhere or other you are going to take a hit. I think the performance bump will be negligible. Sep 25, 2015 at 23:09
1

try this :

 {% if page.local_tasks|render|striptags|trim  is not empty %}
    {{ page.local_tasks }}
 {% endif %}
1
  • This is the right answer. Attention: |trim needs to come last, after |striptags, as you will strip all the HTML tags first, and then remove any remaining white space. If you do otherwise (I see some proposed answers here applying |trim before |striptags), you end up with leftover whitespace because striptags does leave some empty space behind. Mar 9 at 21:46
1

This actually works in my case

{% if page.sidebar_second|render|striptags('<drupal-render-placeholder>')|trim|length > 0 %}

striptags accepts a string of tags to keep, so you can also add whatever contentless tags you expect to have, like <form><img> etc.

1
  • You can now find a module implementing this at drupal.org/project/twig_real_content So that may safe you from copy-pasting the code in your templates. The module provides a filter and test to use instead: "|real_content" or "is real_content". For details see the module page. Jun 29, 2022 at 16:45
0

You should use Renderer service instead of drupal_render() which is deprecated, so:

$output = \Drupal::service('renderer')->renderRoot($some_array)

This will avoid generating drupal-render-placeholder tag in the output.

Similar issue: How to replace drupal-render-placeholder manually?

0

The following does also work when twig debugging is enabled:

{% set sidebarLength = page.sidebar_first|render|trim|striptags|length %}
{% if sidebarLength > 1 %}
  {% set has_sidebar_first = page.sidebar_first %}
{% else %}
  {% set has_sidebar_first = null %}
{% endif %}
-2

To detect if region is empty or not code like this:

{% if page.local_tasks %}
   {{ page.local_tasks }}
{% endif %}

In above code it checks if local_tasks region is empty or not and if empty then it will not print that region

2
  • 2
    not worked, this is always true
    – Yuseferi
    Sep 18, 2016 at 10:48
  • 1
    The lazy rendering of the blocks is the cause for this snippet not to work. Because the array is not empty, but rendering it returns nothing.
    – Renrhaf
    Jan 15, 2018 at 21:35