6

I am using Layout Builder (Drupal 8.7.1)

I have a block in several Layouts. How can I programmatically remove all instances of this block and update all layouts without the message "This block is broken or missing. You may be missing content or you might need to enable the original module." ?

2 Answers 2

11
+100

here it is, tried it with a custom content block and a views block

i executed the code in php/devel from devel_php module

$storage = \Drupal::entityTypeManager()->getStorage('entity_view_display');
foreach ($storage->loadMultiple() as $display) {
  foreach ($display->getSections() as $section) {
    foreach ($section->getComponents() as $component) {
      // Custom views block
      // $to_delete_plugin_id = 'views_block:my_news-block_1';
      // Custom block
      $to_delete_plugin_id = 'block_content:fb4ad848-0f3c-4296-a6ba-1a9da886335b';
      if ($component->getPluginId() == $to_delete_plugin_id) {
        $section->removeComponent($component->getUuid());
        $display->save();
      }
    }
  }
}

for a particular node :

// This can be adapted to be used for a set of nodes
$node = node_load(42);
$display = $node->layout_builder__layout;

foreach ($display->getSections() as $section) {
  foreach ($section->getComponents() as $component) {
    // Custom views block
    // $to_delete_plugin_id = 'views_block:my_news-block_1';
    // Custom block
    $to_delete_plugin_id = 'block_content:fb4ad848-0f3c-4296-a6ba-1a9da886335b';
    if ($component->getPluginId() == $to_delete_plugin_id) {
      $section->removeComponent($component->getUuid());
      $node->save();
    }
  }
} 

Hope this helps :)

2
  • Thank you, but, how can I iterate over each overridden layout, I check "Allow each content item to have its layout customized." and every Node that I created has your own blocks in their layout.
    – rpayanm
    May 21, 2019 at 18:28
  • 1
    Hi, i edited my answer to add an example of how to do this for a targeted node (and so for a selected set of nodes using a foreach)
    – izus
    May 22, 2019 at 15:40
5

Assuming you're using Layout Builder on a Node, and you're using "overrides" to allow each content to have it's own unique layout, the data you're looking for is in the node__layout_builder__layout table. You can look there and see that it stores a reference to the "ID" of the entity, and the UUID of the content. So, in the case of a block, because you may have deleted the instance, it will fail to find the UUID of this block content, and display the warning message.

I figured this would make a good contrib project, so I've created "Layout Builder Block Sanitizer", and released a dev version that allows you to go to a form, type in a node ID, and it will scan each section on that node automatically for "block_content" that no longer exists, and remove it. Let me know if this helps out. As I've noted on the project page, this could definitely scale up and improve quite a bit from the current state, but should possibly help you out in this situation.

Check out the project here: https://www.drupal.org/project/layout_builder_block_sanitizer

1
  • I've just updated it this morning to include a basic batching process, so you could theoretically press the button on /lbbs/sanitizer, and it will run the sanitization on all nodes. Also, the code itself should give you an idea of how to do this programmatically if you're wanting to do a different implementation. All the logic to sanitize is taking place in the LayoutBuilderBlockSanitizerManager service. I'm in the process now of adding some functional testing. Feel free to open up issues for the project. May 22, 2019 at 12:33

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.