How to create dynamic layouts using derivatives in Drupal 8 & 9
if you wanted to create a flexible layout builder, you'd give the site administrator some user interface to declare a new layout, and the configuration for each layout would be saved as a config entity. Then you'd register a layout class that used a "deriver" to dynamically register a layout plugin for each of those saved config entities.
Article how to create custom configuration entity type
So, first you'd register the layout class, for example:
<?php
namespace Drupal\mymodule\Plugin\Layout;
use Drupal\Core\Layout\LayoutDefault;
/**
* A layout from our flexible layout builder.
*
* @Layout(
* id = "flexible_layout",
* deriver = "Drupal\mymodule\Plugin\Deriver\FlexibleLayoutDeriver",
* admin_label = @Translation("Flexible layout"),
* category = @Translation("Flexible layout category"),
* )
*/
class FlexibleLayout extends LayoutDefault {
/**
* {@inheritdoc}
*/
public function build(array $regions) {
$render_array = parent::build($regions);
// Since this is a flexible layout builder, you probably need to do
// something special to render the layout, so we override the ::build()
// method which is responsible for creating a render array.
return $render_array;
}
}
Now, here is what an example deriver could look like:
namespace Drupal\mymodule\Plugin\Deriver;
use Drupal\Component\Plugin\Derivative\DeriverBase;
use Drupal\mymodule\Plugin\Layout\FlexibleLayout;
use Drupal\Core\Layout\LayoutDefinition;
/**
* Makes a flexible layout for each layout config entity.
*/
class FlexibleLayoutDeriver extends DeriverBase {
/**
* {@inheritdoc}
*/
public function getDerivativeDefinitions($base_plugin_definition) {
// Here we need to magically get a list of the config entities.
// I leave this as an exercise for the reader. :-)
$config_entities = [];
// Now we loop over them and declare the derivatives.
foreach ($config_entities as $entity) {
// Here we fill in any missing keys on the layout annotation.
$this->derivatives[$entity->id()] = new LayoutDefinition([
'class' => FlexibleLayout::class,
'label' => $entity->label(),
'category' => $entity->getCategory(),
'regions' => $entity->getRegions(),
]);
}
return $this->derivatives;
}
}
Other example how deriver could look like:
<?php
namespace Drupal\mymodule\Plugin\Deriver;
use Drupal\Component\Plugin\Derivative\DeriverBase;
use Drupal\mymodule\Plugin\Layout\FlexibleLayout;
use Drupal\Core\Layout\LayoutDefinition;
/**
* Makes a flexible layout for each layout config entity.
*/
class FlexibleLayoutDeriver extends DeriverBase
{
/**
* {@inheritdoc}
*/
public function getDerivativeDefinitions($base_plugin_definition)
{
for ($i = 0; $i < 3; $i++) {
$this->derivatives["flexible_layout" . $i] = new LayoutDefinition([
'class' => FlexibleLayout::class,
'label' => "flexible layout " . $i,
'category' => "Custom",
'regions' => ['main' => ['label' => 'Main content']],
'template' => 'flexible-layout-' . $i,
'path' => drupal_get_path('module', 'mymodule') . "/layouts/flexible-layout",
]);
}
return $this->derivatives;
}
}
Our custom layouts are like this:
Useful links:
https://www.drupal.org/docs/drupal-apis/layout-api/how-to-register-layouts#using-derivatives