Utiliser le Layout builder programmaticallement

Par Le Barman - Lundi 1 octobre 2018
Tags
Layout builder
Plugin
Vignette

Ce petit article part d'un cas précis. En effet nous utilisons fréquemment les profils pour créer des install Drupal prêtes à l'emploi. Or généralement une fois un profil en place, les premiers besoins sont souvent les mêmes: changer le layout de certaines pages et réagencer certains blocs.

Pour ce faire, Lightning proposait le module Panelizer, intéressant mais peu intuitif même pour quelqu'un d'habitué. Or depuis l'initiative d'amélioration Layout , une alternative similaire et mieux pensée que Panelizer est apparue en expérimental: Layout Builder. Nous n'allons pas ici présenter ce module en détail, il est assez simple d'utilisation et il existe déjà pas mal de vidéos et d'articles le présentant.

Le plugin de storage

Layout Builder déclare un nouveau type de plugin, le section storage. Pour faire simple une section correspond à une zone dans laquelle sera appliqué un layout donné.

section

Il déclare aussi 2 implémentations de ce plugin:

  • Default Section Storage
  • Overrides Section Storage

Pour faire simple le default s’applique à partir du moment où on déclare une entité par exemple un type de contenu 'basic page' comme éligible au layout builder et le Overrides s'applique lorsque chaque 'basic page' peut disposer de son propre layout builder.

choix du plugin utilisé pour le section storage
Choix du plugin à utiliser pour le section storage d'un type de contenu 'basic page'.

Une section et ses composants

Une section est donc caractérisée par son layout et par ses composants (souvent des blocs mais pas que) placés au sein de ce layout. Tout cela est assez intuitif et simple à mettre en place via l'éditeur. Mais comment le faire automatiquement? Ces sections ne sont pas des configurations comme les views par exemple. Ce sont des données à part entière, on ne peut donc pas en faire des fichiers de conf .yml placés dans un dossier install ou optionnal d'un module ou d'un profil.
Il n'y a pas d'interface pour le moment, les classes Section et SectionComponent se trouvent respectivement dans:

\Drupal\layout_builder\Section;
\Drupal\layout_builder\SectionComponent;

Construction d'une Section sur une page

Pour manipuler une section, il est nécessaire de passer par le plugin  de storage de section souhaité, c'est à dire Default ou Overrides. Or pour cela il faut utiliser le manager de plugins dédié au storage de section. Là il se peut que la phrase ne veuille plus dire grand chose mais ce dernier déclaré par le service.yml du module de layout builder se situe dans  Drupal\layout_builder\SectionStorage\SectionStorageManager. Concrètement cela donne:

//Chargement du manager de plugins dédiés au storage de sections.
$sectionStorageManager = \Drupal::service('plugin.manager.layout_builder.section_storage');

//Instanciation du plugin souhaité (default ou overrides).
$plugin = $sectionStorageManager->createInstance('overrides');

Ensuite et c'est là que pour le moment c'est un peu foireux, il faut initialiser la liste des sections de l'entité (NB: Vérifiez bien auparavant que votre entité est marquée comme 'enable' au layout builder et que chaque élément de cette entité peut avoir un layout spécifique, comme sur la capture plus haut).

/**
* @var Drupal\layout_builder\Plugin\SectionStorage\OverridesSectionStorage
* La liste des sections se récupère par l'ID de l'entité, si cette entité est un node et son id 18  alors ce sera 'node.18'.
*/
$my_entity_id = 18;
$section_storage = $plugin->setSectionList($plugin->getSectionListFromId('node.' . $my_entity_id));
$section_storage = $plugin->setSectionList();

On va ensuite pouvoir créer et placer le composants. Les composants sont marqués par un uuid. Il ne sont pour le moment pas crées automatiquement il faut donc penser à les générer.

//Initialisation du générateur de uuids.
$uuidGen = new UuidGenerator();
//Initialisation de la section, on passe en id le nom du layout souhaité, dans notre cas il s'agit du 'layout_onecol'.
$section = new Section('layout_onecol');

//On créé la configuration du composant souhaité (notre composant sera un bloc carrousel issu d'une view).
$compoConf = [
  'id' => 'views_block:carousel_news-block_1',
  'label' => '',
  'provider' => 'views',
  'label_display' => 0,
  'views_label' => '',
  'items_per_page' => 'none',
  'context_mapping' => [],
  'additional' => [],
  'weight' => 0
];

//On instancie le composant et on le place dans la région du layout souhaitée ('content' dans notre cas).
$component = new SectionComponent($uuidGen->generate(), 'content', $compoConf);
//On ajoute le composant à la section.
$section->insertComponent(0, $component);

//Création d'autres composants si besoin...

//Enregistrement de la section:
$section_storage->appendSection($section);
$section_storage->save();

Et voila!
Évidement le code risque d'évoluer sachant qu'on est encore sur du module expérimental mais la finalité de ce module est une vraie plus-value et pouvoir l'exploiter dans un profil Drupal est assez intéressant.

Le code dans son ensemble, qui peut être intégré dans un hook_install().

use Drupal\layout_builder\Section;
use Drupal\layout_builder\SectionComponent;
use Drupal\Component\Uuid\Php as UuidGenerator;
use Drupal\layout_builder\Entity\LayoutBuilderEntityViewDisplay;

/**
 * Implements hook_install().
 */
function MON_MODULE_install() {

  #On rend le type de contenu page  éligible aux layout builder.
  $lb = LayoutBuilderEntityViewDisplay::load('node.page.default');
  $lb->enableLayoutBuilder()
      ->setOverridable()
      ->save();

  //Chargement du manager de plugins dédiés au storage de sections.
  $sectionStorageManager = \Drupal::service('plugin.manager.layout_builder.section_storage');

  //Instanciation du plugin souhaité (default ou overrides).
  $plugin = $sectionStorageManager->createInstance('overrides');

  /**
  * @var Drupal\layout_builder\Plugin\SectionStorage\OverridesSectionStorage
  * La liste des sections se récupère par l'ID de l'entité, si cette entité est un node et son id 18  alors ce sera 'node.18'.
  */
  $my_entity_id = 18;
  $section_storage = $plugin->setSectionList($plugin->getSectionListFromId('node.' . $my_entity_id));
  $section_storage = $plugin->setSectionList();

  //Initialisation du générateur de uuids.
  $uuidGen = new UuidGenerator();
  //Initialisation de la section, on passe en id le nom du layout souhaité, dans notre cas il s'agit du 'layout_onecol'.
  $section = new Section('layout_onecol');

  //On créé la configuration du composant souhaité (notre composant sera un bloc carrousel issu d'une view).
  $compoConf = [
    'id' => 'views_block:carousel_news-block_1',
    'label' => '',
    'provider' => 'views',
    'label_display' => 0,
    'views_label' => '',
    'items_per_page' => 'none',
    'context_mapping' => [],
    'additional' => [],
    'weight' => 0
  ];

  //On instancie le composant et on le place dans la région du layout souhaitée ('content' dans notre cas).
  $component = new SectionComponent($uuidGen->generate(), 'content', $compoConf);
  //On ajoute le composant à la section.  
  $section->insertComponent(0, $component);

  //Création d'autres composants si besoin...

  //Enregistrement de la section:
  $section_storage->appendSection($section);
  $section_storage->save();
}

À la bonne votre!


Le barman

Ajouter un commentaire

L'e-mail est obligatoire mais restera privé.