Score:0

How to programmatically save a node's layout?

us flag

Not sure if this is the best approach but it does work well.. almost.

I am using the Layout Builder Modal module which, in layout builder, opens block configuration in a modal. This is great but I would like to extend this capability to the front end so that I can configure a layout block without having to go into the node's layout.

If I simply place the contextual link which this module creates on to my node page; sure enough it opens the required modal and allows me to change the configuration of the specific block. On submit, the block config is changed and the modal closes, but the layout isn't saved to use this new block config. This can be seen when I go to the node layout and it states there are changes pending. If I now save the layout I see my block config changes.

How can I programmatically force the node's layout to be saved?

Score:2
bd flag

While this is not an actual answer to your question "How can I programmatically force the node's layout to be saved?", I wanted to point you to the Layout Builder IPE module, that I have created to solve a similar use-case as yours: Provide editing possibilities directly from the view page of a node.

If this is not an option for you, then the programatic solution probably evolves around:

  1. hooking into the form submit
  2. adding your custom submit handler
  3. grab the block config somehow
  4. update the OverridesSectionStorage for the node
  5. save the node
  6. delete the temporary storage for the layout builder of that node

At least that's what I recall. While working on Layout Builder IPE, I found that whole structure a bit complicated to be honest, which was the main reason to try and get this done once in a more generic way.

Update Some more details I looked up that might help with this:

To get the sections for a layout builder enabled node you can use LayoutEntityHelperTrait::getSectionStorageForEntity, e.g.:

$section_storage = $this->getSectionStorageForEntity($node);
$sections = $section_storage->getSections();

This $sections variable is an array of sections, each section containing section components. You can iterate over them until you find the block you are looking for and do what you need to do to update the configuration (untested code):

foreach ($sections as $delta => $section) {
  foreach ($section->getComponents() as $component) {
    // Each component is an object of type \Drupal\layout_builder\SectionComponent.
    // To identify the block you can use the plugin id (or the UUID if
    // multiple blocks of the same type exist). 
    $plugin_id = $component->getPluginId();
    if ($plugin_id == 'BLOCK_PLUGIN_ID') {
      $configuration = $component->get('configuration');
      // Update the configuration, and then update the component.
      $component->setConfiguration($configuration);
    }
  }
}

Once the necessary changes have been made, the sections can be saved back to the node by using this:

$node->get(OverridesSectionStorage::FIELD_NAME)->setValue($sections);

And to clear the tempstore something like this should work, though this should be using DI obviously:

\Drupal::service('layout_builder.tempstore_repository')->delete($section_storage);
cn flag
Comments are not for extended discussion; this conversation has been [moved to chat](https://chat.stackexchange.com/rooms/136485/discussion-on-answer-by-berliner-how-to-programmatically-save-a-nodes-layout).
mangohost

Post an answer

Most people don’t grasp that asking a lot of questions unlocks learning and improves interpersonal bonding. In Alison’s studies, for example, though people could accurately recall how many questions had been asked in their conversations, they didn’t intuit the link between questions and liking. Across four studies, in which participants were engaged in conversations themselves or read transcripts of others’ conversations, people tended not to realize that question asking would influence—or had influenced—the level of amity between the conversationalists.