diff --git a/core/modules/layout_builder/layout_builder.module b/core/modules/layout_builder/layout_builder.module index 4631de2547..3684c6098b 100644 --- a/core/modules/layout_builder/layout_builder.module +++ b/core/modules/layout_builder/layout_builder.module @@ -207,6 +207,17 @@ function layout_builder_entity_presave(EntityInterface $entity) { } } +/** + * Implements hook_entity_insert(). + */ +function layout_builder_entity_insert(EntityInterface $entity) { + if (\Drupal::moduleHandler()->moduleExists('block_content')) { + /** @var \Drupal\layout_builder\InlineBlockEntityOperations $entity_operations */ + $entity_operations = \Drupal::classResolver(InlineBlockEntityOperations::class); + $entity_operations->handleInsert($entity); + } +} + /** * Implements hook_entity_delete(). */ diff --git a/core/modules/layout_builder/src/InlineBlockEntityOperations.php b/core/modules/layout_builder/src/InlineBlockEntityOperations.php index ad255cd6fe..f59a947532 100644 --- a/core/modules/layout_builder/src/InlineBlockEntityOperations.php +++ b/core/modules/layout_builder/src/InlineBlockEntityOperations.php @@ -155,7 +155,7 @@ public function handlePreSave(EntityInterface $entity) { if (!$this->isLayoutCompatibleEntity($entity)) { return; } - $duplicate_blocks = FALSE; + $duplicate_blocks = $entity->isNew(); if ($sections = $this->getEntitySections($entity)) { if ($this->originalEntityUsesDefaultStorage($entity)) { @@ -174,6 +174,29 @@ public function handlePreSave(EntityInterface $entity) { $this->removeUnusedForEntityOnSave($entity); } + /** + * Handles parent entity insert. + * + * @param \Drupal\Core\Entity\EntityInterface $entity + * The parent entity. + */ + public function handleInsert(EntityInterface $entity) { + if (!$this->isLayoutCompatibleEntity($entity)) { + return; + } + + // If the parent entity is created with already-associated blocks (e.g. a + // clone or duplicate of the existing entity), those blocks must be added + // after the entity is saved. + if ($sections = $this->getEntitySections($entity)) { + foreach ($this->getInlineBlockComponents($sections) as $component) { + $plugin = $component->getPlugin(); + $block_id = $this->getPluginBlockId($plugin); + $this->usage->addUsage($block_id, $entity); + } + } + } + /** * Gets a block ID for an inline block plugin. * @@ -254,7 +277,7 @@ protected function saveInlineBlockComponent(EntityInterface $entity, SectionComp $pre_save_configuration = $plugin->getConfiguration(); $plugin->saveBlockContent($new_revision, $duplicate_blocks); $post_save_configuration = $plugin->getConfiguration(); - if ($duplicate_blocks || (empty($pre_save_configuration['block_revision_id']) && !empty($post_save_configuration['block_revision_id']))) { + if ($entity->id() !== NULL && ($duplicate_blocks || (empty($pre_save_configuration['block_revision_id']) && !empty($post_save_configuration['block_revision_id'])))) { $this->usage->addUsage($this->getPluginBlockId($plugin), $entity); } $component->setConfiguration($post_save_configuration); diff --git a/core/modules/layout_builder/tests/src/FunctionalJavascript/InlineBlockTest.php b/core/modules/layout_builder/tests/src/FunctionalJavascript/InlineBlockTest.php index bbcd3cf512..26a09132dd 100644 --- a/core/modules/layout_builder/tests/src/FunctionalJavascript/InlineBlockTest.php +++ b/core/modules/layout_builder/tests/src/FunctionalJavascript/InlineBlockTest.php @@ -658,4 +658,88 @@ public function testEditInlineBlocksPermission() { $assert($permissions, TRUE); } + /** + * Tests that Inline Blocks are added to duplicated entities. + */ + public function testDuplicateEntityInlineBlockUsage() { + /** @var \Drupal\Core\Cron $cron */ + $cron = \Drupal::service('cron'); + /** @var \Drupal\layout_builder\InlineBlockUsageInterface $usage */ + $usage = \Drupal::service('inline_block.usage'); + $this->drupalLogin($this->drupalCreateUser([ + 'administer content types', + 'access contextual links', + 'configure any layout', + 'administer node display', + 'administer node fields', + 'administer nodes', + 'bypass node access', + 'create and edit custom blocks', + ])); + + $assert_session = $this->assertSession(); + $page = $this->getSession()->getPage(); + + // Enable layout builder. + $this->drupalPostForm( + static::FIELD_UI_PREFIX . '/display/default', + ['layout[enabled]' => TRUE], + 'Save' + ); + $this->clickLink('Manage layout'); + $assert_session->addressEquals(static::FIELD_UI_PREFIX . '/display/default/layout'); + + // Enable overrides. + $this->drupalPostForm(static::FIELD_UI_PREFIX . '/display/default', ['layout[allow_custom]' => TRUE], 'Save'); + $this->drupalGet('node/1/layout'); + + // Add a basic block with the body field set. + $this->drupalGet('node/1/layout'); + $this->addInlineBlockToLayout('New Block title', 'New block body'); + $this->assertSaveLayout(); + $node_1_block_id = $this->getLatestBlockEntityId(); + $this->drupalGet('node/1'); + $assert_session->pageTextContains('New Block title'); + $assert_session->pageTextContains('New block body'); + + /** @var \Drupal\node\NodeStorageInterface $node_storage */ + $node_storage = $this->container->get('entity_type.manager')->getStorage('node'); + + /** @var \Drupal\node\NodeInterface $node_1 */ + $node_1 = $node_storage->load(1); + + // Clone node 1. + $cloned = $node_1->createDuplicate(); + $cloned->save(); + + // Confirm inline blocks exist on clone. + $new_id = $cloned->id(); + $this->drupalGet('node/' . $new_id); + $cloned_block_id = $this->getLatestBlockEntityId(); + $cloned_usage = $usage->getUsage($cloned_block_id); + $this->assertNotEmpty($cloned_usage); + + // Confirm cloned inline block has the right layout entity. + $this->assertNotEmpty($cloned_usage->layout_entity_id); + $this->assertEqual($new_id, $cloned_usage->layout_entity_id); + $this->assertNotEmpty($cloned_usage->layout_entity_type); + + $assert_session->pageTextContains('New Block title'); + $assert_session->pageTextContains('New block body'); + + // Delete the original. + $this->assertNotEmpty($usage->getUsage($node_1_block_id)); + $this->drupalGet('node/1'); + $this->drupalGet('node/1/delete'); + $page->pressButton('Delete'); + $this->drupalGet('node/1'); + $this->assertNull($node_storage->loadUnchanged(1)); + $cron->run(); + + // Ensure entity block was kept for clone. + $this->assertNull($this->blockStorage->load($node_1_block_id)); + $this->assertFalse($usage->getUsage($node_1_block_id)); + $this->assertCount(1, $this->blockStorage->loadMultiple()); + } + }