Commit 0bf6a1c0 authored by catch's avatar catch
Browse files

fix: #3152281 Extra field blocks render even when empty

By: herved
By: fskreuz
By: smustgrave
By: hardik_patel_12
By: shalini_jha
By: alexpott
(cherry picked from commit f0c25113)
parent 8d688196
Loading
Loading
Loading
Loading
Loading
+23 −0
Original line number Diff line number Diff line
@@ -10,6 +10,7 @@
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\Core\Plugin\ContextAwarePluginInterface;
use Drupal\Core\Render\Element;
use Drupal\Core\Security\Attribute\TrustedCallback;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\layout_builder\Plugin\Derivative\ExtraFieldBlockDeriver;
@@ -170,6 +171,7 @@ public static function replaceFieldPlaceholder(array &$build, array $built_field
        $built_cache = CacheableMetadata::createFromRenderArray($built_field);
        $merged_cache = $placeholder_cache->merge($built_cache);
        $build[$child] = $built_field;
        $build['#pre_render'][] = [static::class, 'preRenderBlock'];
        $merged_cache->applyTo($build);
      }
      else {
@@ -178,6 +180,27 @@ public static function replaceFieldPlaceholder(array &$build, array $built_field
    }
  }

  /**
   * Pre-render callback to ensure empty extra_field_block's are not rendered.
   *
   * @param array $block_build
   *   The original block render array.
   *
   * @return array
   *   The modified block render array.
   */
  #[TrustedCallback]
  public static function preRenderBlock(array $block_build): array {
    $content = $block_build['content'] ?? NULL;
    if ($content === NULL || Element::isEmpty($content)) {
      // Block content is empty, abort rendering the whole block and preserve
      // cache metadata.
      // @see \Drupal\Core\Render\Renderer::doRender
      $block_build['#printed'] = TRUE;
    }
    return $block_build;
  }

  /**
   * {@inheritdoc}
   */
+29 −0
Original line number Diff line number Diff line
@@ -8,12 +8,21 @@
use Drupal\Core\Entity\Display\EntityViewDisplayInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Hook\Attribute\Hook;
use Drupal\Core\KeyValueStore\KeyValueFactoryInterface;
use Symfony\Component\DependencyInjection\Attribute\Autowire;

/**
 * Entity hook implementations for layout_builder_test.
 */
class LayoutBuilderTestEntityHooks {

  public function __construct(
    #[Autowire(service: 'keyvalue')]
    protected readonly KeyValueFactoryInterface $keyValueFactory,
  ) {

  }

  /**
   * Implements hook_ENTITY_TYPE_view().
   */
@@ -29,6 +38,21 @@ public function nodeView(array &$build, EntityInterface $entity, EntityViewDispl
        '#markup' => 'Extra Field 2 is hidden by default.',
      ];
    }
    if ($display->getComponent('layout_builder_test_empty')) {
      $build['layout_builder_test_empty'] = [
        '#cache' => [
          'tags' => ['test_extra_fields_empty'],
        ],
      ];

      $render = $this->keyValueFactory->get('test_extra_fields_empty')->get('render_extra_field', FALSE);
      if ($render) {
        $build['layout_builder_test_empty'][] = [
          '#type' => 'markup',
          '#markup' => 'This extra field is visible because it is not empty.',
        ];
      }
    }
  }

  /**
@@ -47,6 +71,11 @@ public function entityExtraFieldInfo(): array {
      'weight' => 0,
      'visible' => FALSE,
    ];
    $extra['node']['bundle_with_section_field']['display']['layout_builder_test_empty'] = [
      'label' => 'Extra Field (empty)',
      'description' => 'Extra Field (empty) description',
      'weight' => 0,
    ];
    return $extra;
  }

+14 −0
Original line number Diff line number Diff line
@@ -4,6 +4,7 @@

namespace Drupal\Tests\layout_builder\Functional;

use Drupal\Core\Cache\Cache;
use Drupal\layout_builder\Entity\LayoutBuilderEntityViewDisplay;
use Drupal\layout_builder\Section;
use Drupal\node\Entity\Node;
@@ -11,6 +12,8 @@
use PHPUnit\Framework\Attributes\Group;
use PHPUnit\Framework\Attributes\RunTestsInSeparateProcesses;

// cspell:ignore blocknodebundle fieldlayout

/**
 * Tests the Layout Builder UI.
 */
@@ -484,6 +487,17 @@ public function testExtraFields(): void {
    // Confirm that the newly added extra field is visible.
    $this->drupalGet('node/1');
    $assert_session->pageTextContains('Extra Field 2 is hidden by default.');

    // Ensure empty extra field and its container are not rendered.
    /* @see \Drupal\layout_builder\Plugin\Block\ExtraFieldBlock::preRenderBlock */
    $selector = '.block-extra-field-blocknodebundle-with-section-fieldlayout-builder-test-empty';
    $assert_session->elementNotExists('css', $selector);
    // Force extra field to render, reload page and ensure presence.
    \Drupal::keyValue('test_extra_fields_empty')->set('render_extra_field', TRUE);
    Cache::invalidateTags(['test_extra_fields_empty']);
    $this->getSession()->reload();
    $assert_session->elementExists('css', $selector);
    $assert_session->elementTextContains('css', $selector, 'This extra field is visible because it is not empty.');
  }

  /**