Loading core/modules/layout_builder/src/Plugin/Block/ExtraFieldBlock.php +23 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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 { Loading @@ -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} */ Loading core/modules/layout_builder/tests/modules/layout_builder_test/src/Hook/LayoutBuilderTestEntityHooks.php +29 −0 Original line number Diff line number Diff line Loading @@ -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(). */ Loading @@ -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.', ]; } } } /** Loading @@ -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; } Loading core/modules/layout_builder/tests/src/Functional/LayoutBuilderTest.php +14 −0 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -11,6 +12,8 @@ use PHPUnit\Framework\Attributes\Group; use PHPUnit\Framework\Attributes\RunTestsInSeparateProcesses; // cspell:ignore blocknodebundle fieldlayout /** * Tests the Layout Builder UI. */ Loading Loading @@ -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.'); } /** Loading Loading
core/modules/layout_builder/src/Plugin/Block/ExtraFieldBlock.php +23 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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 { Loading @@ -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} */ Loading
core/modules/layout_builder/tests/modules/layout_builder_test/src/Hook/LayoutBuilderTestEntityHooks.php +29 −0 Original line number Diff line number Diff line Loading @@ -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(). */ Loading @@ -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.', ]; } } } /** Loading @@ -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; } Loading
core/modules/layout_builder/tests/src/Functional/LayoutBuilderTest.php +14 −0 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -11,6 +12,8 @@ use PHPUnit\Framework\Attributes\Group; use PHPUnit\Framework\Attributes\RunTestsInSeparateProcesses; // cspell:ignore blocknodebundle fieldlayout /** * Tests the Layout Builder UI. */ Loading Loading @@ -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.'); } /** Loading