diff --git a/core/lib/Drupal/Core/Config/Action/Plugin/ConfigAction/EntityClone.php b/core/lib/Drupal/Core/Config/Action/Plugin/ConfigAction/EntityClone.php index e23f093010d..2a669b76a48 100644 --- a/core/lib/Drupal/Core/Config/Action/Plugin/ConfigAction/EntityClone.php +++ b/core/lib/Drupal/Core/Config/Action/Plugin/ConfigAction/EntityClone.php @@ -56,6 +56,21 @@ final class EntityClone implements ConfigActionPluginInterface, ContainerFactory if (empty($original)) { throw new ConfigActionException("Cannot clone '$configName' because it does not exist."); } + + // Treat the original ID like a period-separated array of strings, and + // replace any `%` parts in the clone's ID with the corresponding part of + // the original ID. For example, if we're cloning an entity view display + // with the ID `node.foo.teaser`, and the clone's ID is + // `node.%.search_result`, the final ID of the clone will be + // `node.foo.search_result`. + $original_id_parts = explode('.', $original->id()); + $clone_id_parts = explode('.', $value['id']); + assert(count($original_id_parts) === count($clone_id_parts)); + foreach ($clone_id_parts as $index => $part) { + $clone_id_parts[$index] = $part === '%' ? $original_id_parts[$index] : $part; + } + $value['id'] = implode('.', $clone_id_parts); + $clone = $original->createDuplicate(); $clone->set($original->getEntityType()->getKey('id'), $value['id']); diff --git a/core/lib/Drupal/Core/Entity/EntityDisplayBase.php b/core/lib/Drupal/Core/Entity/EntityDisplayBase.php index 40e713b9d43..f51e508c502 100644 --- a/core/lib/Drupal/Core/Entity/EntityDisplayBase.php +++ b/core/lib/Drupal/Core/Entity/EntityDisplayBase.php @@ -324,7 +324,6 @@ abstract class EntityDisplayBase extends ConfigEntityBase implements EntityDispl /** * {@inheritdoc} */ - #[ActionMethod(adminLabel: new TranslatableMarkup('Copy to another mode'), pluralize: FALSE)] public function createCopy($mode) { $display = $this->createDuplicate(); $display->mode = $display->originalMode = $mode; diff --git a/core/tests/Drupal/KernelTests/Core/Recipe/EntityCloneConfigActionTest.php b/core/tests/Drupal/KernelTests/Core/Recipe/EntityCloneConfigActionTest.php index 9c3764d3869..9974819bf0b 100644 --- a/core/tests/Drupal/KernelTests/Core/Recipe/EntityCloneConfigActionTest.php +++ b/core/tests/Drupal/KernelTests/Core/Recipe/EntityCloneConfigActionTest.php @@ -93,9 +93,9 @@ class EntityCloneConfigActionTest extends KernelTestBase { } /** - * Tests cloning entity displays, which have specialized logic for that. + * Tests wildcard support, which allows positional tokens in the clone's ID. */ - public function testCloneEntityDisplay(): void { + public function testCloneWithWildcards(): void { $this->container->get(ModuleInstallerInterface::class)->install(['node']); $this->createContentType(['type' => 'alpha']); $this->createContentType(['type' => 'beta']); @@ -112,17 +112,9 @@ class EntityCloneConfigActionTest extends KernelTestBase { // Use the action to clone the default view displays to the `rss` view mode. /** @var \Drupal\Core\Config\Action\ConfigActionManager $manager */ $manager = $this->container->get('plugin.manager.config_action'); - $manager->applyAction('cloneAs', 'core.entity_view_display.node.alpha.default', 'node.alpha.rss'); - $manager->applyAction('entity_method:core.entity_view_display:createCopy', 'core.entity_view_display.node.beta.default', 'rss'); + $manager->applyAction('cloneAs', 'core.entity_view_display.node.*.default', 'node.%.rss'); $this->assertFalse($display_repository->getViewDisplay('node', 'alpha', 'rss')->isNew()); $this->assertFalse($display_repository->getViewDisplay('node', 'beta', 'rss')->isNew()); - - // Ensure that this also works with wildcards. - $this->assertTrue($display_repository->getViewDisplay('node', 'alpha', 'search_result')->isNew()); - $this->assertTrue($display_repository->getViewDisplay('node', 'beta', 'search_result')->isNew()); - $manager->applyAction('entity_method:core.entity_view_display:createCopy', 'core.entity_view_display.node.*.default', 'search_result'); - $this->assertFalse($display_repository->getViewDisplay('node', 'alpha', 'search_result')->isNew()); - $this->assertFalse($display_repository->getViewDisplay('node', 'beta', 'search_result')->isNew()); } }