Problem/Motivation

#2249303: Implement fallback plugin for Block plugins introduced:

  1. \Drupal\Core\Block\Plugin\Block\Broken
  2. class BlockManager extends DefaultPluginManager implements BlockManagerInterface, FallbackPluginManagerInterface {
    …
      public function getFallbackPluginId($plugin_id, array $configuration = []) {
        return 'broken';
      }
    …
    }
    

Which means that ANY invalid block plugin ID in a block config entity automatically falls back to this broken block plugin.

The primary purpose was to make it possible to install block config entities while the corresponding block_content content entity does not yet exist, and hence allow referencing block_content:<UUID> block plugins to automatically fall back to the broken plugin ID.

But … this is VERY broad. Too broad in many cases. So broad that it makes validating block config entities less meaningful 😞 This became clear in #3362457-17: Fix all PluginExistsConstraint constraint violations in tests.

But changing this is hard now, because there could be other block plugins in contrib/custom that have similar #2248369: [meta] Deploying configuration that depends on content-style needs. Still, we should aim to narrow this.

Steps to reproduce

See #3362457-17: Fix all PluginExistsConstraint constraint violations in tests: run \Drupal\Tests\block\Kernel\BlockValidationTest::testInvalidPluginId() and observe how a nonsencial plugin ID does not trigger any validation errors.

For contrast, see \Drupal\Tests\editor\Kernel\EditorValidationTest::testInvalidPluginId(), where a validation error is triggered.

Proposed resolution

  1. Simple but more disruptive:
      public function getFallbackPluginId($plugin_id, array $configuration = []) {
        // Provide fallback for `block_content:*` blocks.
        // @see \Drupal\block_content\Plugin\Block\BlockContentBlock
        // @see \Drupal\block_content\Plugin\Derivative\BlockContent
        if (str_starts_with($plugin_id, 'block_content:')) {
          return 'broken';
        }
    
        // No fallback for anything else.
        return $plugin_id;
      }
    
  2. More complex but less disruptive:
      public function getFallbackPluginId($plugin_id, array $configuration = []) {
        // Provide fallback for content-dependent block plugins.
        // @see \Drupal\block_content\Plugin\Block\BlockContentBlock
        // @see \Drupal\block_content\Plugin\Derivative\BlockContent
        foreach ($this->getContentDependentBlockPluginTypes() as $base_plugin_id) {
          if (str_starts_with($plugin_id, "$base_plugin_id:")) {
            return 'broken';
          }
        }
    
        // No fallback for anything else.
        return $plugin_id;
      }

    This needs some mechanism to identify the content-dependent block plugin types to allow contrib/custom block types to get the same behavior. Suggestion: do this via an annotation on block plugin types.

Remaining tasks

TBD

User interface changes

TBD

API changes

TBD

Data model changes

TBD

Release notes snippet

TBD

Comments

Wim Leers created an issue. See original summary.

Version: 11.x-dev » main

Drupal core is now using the main branch as the primary development branch. New developments and disruptive changes should now be targeted to the main branch.

Read more in the announcement.