Problem/Motivation

Reusable block support was deprecated in 9.1.2 and reintroduced as deprecated-only in 9.1.3 (#3587714: Revert Reusable Block Support Removal Until Later Release) to provide a migration window. The original removal (#3516918: Remove Reusable Block Support) committed to migration tooling ("needs to be explored and implemented") but none was delivered.

Sites with existing reusable block content need an automated path for converting placements to inline equivalents before the code is permanently removed. Without tooling, operators must manually recreate each reusable block placement in Layout Builder — a process that is error-prone and does not scale for sites with many placements.

Steps to reproduce

  1. Install Patternkit 9.1.3 with enable_reusable_blocks: true.
  2. Create reusable Patternkit block entities and place them in Layout Builder layouts.
  3. Upgrade to 9.2.0.
  4. Observe: reusable block placements render as Drupal's broken block. No automated conversion path exists.

Proposed resolution

Provide a Drush migration command and re-execute the reusable block code removal for the 9.2.0 release.

1. Migration command

drush patternkit:migrate:reusable

Converts reusable block placements (UUID-based derivatives) to inline pattern-based equivalents using a targeted identification strategy.

Constraint: Full database scans of all Layout Builder layouts are not feasible on large sites. The command uses an entity-first approach:

  • Query patternkit_block entities for reusable entries (by reusable column or UUID cross-reference against known pattern derivative IDs).
  • Use entity UUIDs as targeted lookup keys against Layout Builder section storage (layout_builder__layout field tables) and block.block.* config entities.
  • Convert matched placements without loading every entity with layout overrides.

This reduces significantly reduces the scope of what needs to be loaded and traversed for the process.

2. Dry-run mode

--dry-run flag reports what would be migrated without making changes.

3. Code removal

Re-execute the reusable block code removal (restoring the scope of commit dff037f against the 9.2.0 branch state).

4. Update hooks

  • patternkit_update_10309 drops the reusable column (restored from no-op status in 9.1.3).
  • Consider a new update hook that documents the migration step or provides a pre-update requirements check.

5. Change record

Publish a change record for the 9.2.0 removal confirming migration tooling availability and documenting the upgrade path.

Remaining tasks

  • Implement drush patternkit:migrate:reusable with targeted identification.
  • Add --dry-run audit mode.
  • Handle config entity migration (block.block.*).
  • Handle translations and define revision policy.
  • Re-execute code removal.
  • Restore patternkit_update_10309.
  • Publish 9.2.0 change record.
  • Update upgrade documentation.
  • Review and test the merge request.
  • CI validation.

User interface changes

The reusable block checkbox, deprecation warnings, and reusable block administration pages are removed. Layouts that previously displayed reusable blocks will show inline equivalents after migration, or Drupal's broken block placeholder if migration was not run.

API changes

  • The PatternkitBlock derivative loader no longer produces UUID-based derivative definitions for reusable block entities.
  • ReusableBlockHooks and associated route subscriber are removed.
  • The enable_reusable_blocks service parameter is removed.
  • A new Drush command patternkit:migrate:reusable is added (available before the removal to allow pre-upgrade migration).

Data model changes

The reusable column is dropped from the patternkit_block entity base table via patternkit_update_10309. Existing patternkit_block entity rows (with pattern_id, data, and revision fields) are preserved; orphaned entities can optionally be cleaned up after migration.

Release notes snippet

Reusable block support has been removed in Patternkit 9.2.0. Sites that used reusable Patternkit blocks should run drush patternkit:migrate:reusable before upgrading to convert reusable block placements to inline equivalents. A --dry-run flag is available to preview changes before applying them. See the change record for detailed upgrade instructions.

Comments

slucero created an issue.

slucero’s picture

MR !190 (#3587714) is open for 9.1.3 and establishes the migration window. The following summarizes what this issue will need to clean up and implement for 9.2.0.

Update hook number

The next available hook is patternkit_update_10311. Hooks 10308–10310 are used by the 9.1.3 migration window.

Required guard pattern for the removal hook

patternkit_update_10310 may restore the reusable column on sites that had it dropped prematurely. The 9.2.0 removal hook must guard against a missing field definition to handle all upgrade paths:

function patternkit_update_10311(): string {
  $edm = \Drupal::entityDefinitionUpdateManager();
  $definition = $edm->getFieldStorageDefinition('reusable', 'patternkit_block');
  if ($definition) {
    $edm->uninstallFieldStorageDefinition($definition);
    return t('Removed reusable field storage from patternkit_block.');
  }
  return t('No schema change: reusable field storage was already absent.');
}

Files to delete

  • src/Hook/ReusableBlockHooks.php
  • src/EventSubscriber/PatternkitReusableBlocksRouteSubscriber.php
  • src/Plugin/Block/PatternkitBlock.php
  • src/Plugin/Derivative/PatternkitBlock.php
  • tests/src/Functional/ReusableBlocksEnabledTest.php
  • tests/src/Functional/ReusableBlocksDisabledTest.php
  • tests/src/Kernel/ReusableBlockHooksRequirementsTest.php
  • tests/src/Kernel/ReusableBlocksUpdateHooksTest.php (10308–10310 tests are no longer relevant)

Files to modify

  • patternkit.module: remove patternkit_entity_type_alter, patternkit_local_tasks_alter, and patternkit_menu_local_actions_alter hook bridges; remove the ReusableBlockHooks delegate from patternkit_contextual_links_alter
  • patternkit.install: remove patternkit_requirements()
  • patternkit.services.yml: remove enable_reusable_blocks parameter and patternkit.subscriber.route.reusable_blocks service
  • patternkit.links.action.yml, patternkit.links.contextual.yml, patternkit.links.task.yml, patternkit.routing.yml: remove all reusable block routes and links (each marked @todo Remove … #3587730)
  • src/PatternkitEnvironment.php: remove FEATURE_ENABLE_REUSABLE_BLOCKS constant
  • src/Entity/PatternkitBlock.php: remove reusable base field definition and @see references to ReusableBlockHooks and PatternkitReusableBlocksRouteSubscriber
  • phpstan-baseline.neon: remove all suppression entries added for the deprecated reusable block classes. The globalDrupalDependencyInjection.useDependencyInjection entry for src/FormElement/PatternkitJson.php is unrelated and should be retained.

Migration tooling

patternkit_update_10308 (9.1.3) logs a warning for each placed config block whose plugin could not be resolved, rather than halting. Sites that have accumulated unresolvable plugin references will have these warnings in their logs after the 9.1.3 upgrade. The migration tooling for this issue should surface these cases and help operators remove or convert reusable block entities before upgrading.

Minimum viable scope: a Drush command that lists all reusable block entities with their placement status. A conversion path (reusable → standard block content) would reduce data loss risk but scope can be confirmed during design.

Change record

A 9.2.0 change record should be authored at release time. After it is published, update node/3517440 with a link to it.