Skip to content

Programmatic Block Operations

When to Use

Use in update hooks, migrations, or automated tasks when you need to load, create, modify, or place blocks via code rather than the UI.

Decision

Operation Code Gotcha
Load block plugin $plugin_manager->createInstance('plugin_id') Temporary; config not persisted
Load Block entity Block::load('entity_id') Load by Block ID, not plugin ID
Place block Block::create(['plugin' => '...'])->save() ID must be unique per theme
List all plugins $plugin_manager->getDefinitions() Returns all including derivatives
List placed blocks loadByProperties(['theme' => '...']) Returns disabled blocks too
Render block $plugin->build() + wrapper Bypasses access checks
Disable block $block->disable()->save() Sets status FALSE
Delete placement $block->delete() Only deletes placement, not plugin

Pattern

Loading and rendering block plugin:

$plugin_manager = \Drupal::service('plugin.manager.block');
$plugin = $plugin_manager->createInstance('system_branding_block', [
  'label' => 'My Branding',
]);
$build = $plugin->build();

Placing a block:

$block = Block::create([
  'id' => 'my_placed_block',
  'plugin' => 'system_powered_by_block',
  'theme' => 'olivero',
  'region' => 'footer',
  'weight' => 10,
  'settings' => ['label' => 'Powered by Drupal'],
]);
$block->save();

Creating and placing content block:

use Drupal\block_content\Entity\BlockContent;

$block_content = BlockContent::create([
  'type' => 'basic',
  'info' => 'My Content Block',
  'reusable' => TRUE,
  'body' => [
    'value' => '<p>Block content</p>',
    'format' => 'basic_html',
  ],
]);
$block_content->save();

$block = Block::create([
  'id' => 'olivero_my_content',
  'plugin' => 'block_content:' . $block_content->uuid(),
  'theme' => 'olivero',
  'region' => 'sidebar_first',
]);
$block->save();

Loading placed blocks by region:

$blocks = \Drupal::entityTypeManager()
  ->getStorage('block')
  ->loadByProperties([
    'theme' => 'olivero',
    'region' => 'header',
  ]);

Rendering block with wrapper:

$plugin_manager = \Drupal::service('plugin.manager.block');
$plugin = $plugin_manager->createInstance('system_branding_block');
$build = $plugin->build();
$build = [
  '#theme' => 'block',
  '#configuration' => $plugin->getConfiguration(),
  '#plugin_id' => $plugin->getPluginId(),
  'content' => $build,
];

Common Mistakes

  • Wrong: Confusing block plugin instances with Block config entities → Right: Plugins define behavior; entities define placement
  • Wrong: Not handling exceptions when loading blocks → Right: Block::load() returns NULL if not found; check before using
  • Wrong: Hardcoding entity IDs → Right: Use UUIDs for portability across environments
  • Wrong: Creating Block entities without checking if they exist → Right: Duplicate ID causes error; check first
  • Wrong: Rendering blocks without access checks → Right: Programmatic rendering bypasses blockAccess(); call manually if needed

See Also