Provide a way to opt-out of inline blocks in layout builder based on context

Created on 2 April 2023, about 1 year ago
Updated 14 June 2023, about 1 year ago

Problem/Motivation

Layout builder provides the option to create inline blocks.

In core, LB is only used for nodes, so there's a quite specific use case. However, LB is nice :_) and people is extending it. There is the dashboards contrib module, the dashboard initiative to bring LB based dashboards in core, and some other modules extending and using the LB ecosystem.

Layout builder restrictions is a contrib popular module that allows to restrict which blocks are available, including restricting inline blocks, or some of them. But for that, it needs to override two controllers from LB. That makes it incompatible with other solutions that might want to do a similar thing, as they compete for the controller swap.

E.g. Dashboard initiative is considering controlling the allowed blocks based on the section_storage type (see https://www.drupal.org/project/3327580/issues/3351705#comment-14993944 πŸ“Œ [Policy] Research about best way to limit the selectable blocks on dashboards Needs review ). That might make it incompatible with layout_builder_restrictions.

Proposed resolution

Provide a way so ChooseBlockController::build/::inlineBlockList allow custom/contrib to opt-out from inline blocks (or some of their bundles) based on whatever conditions (e.g. the section_storage for dashboard, a setting for layout_builder_restrictions)

Remaining tasks

Discuss if it's the way forward.

(taken directly from layout_builder_restrictions, but rename suggestions appreciated).

(as well we might find a better name)

Implement tests for the new hook.

Make a preliminar MR to layout_builder_restriction to ensure the approach works.

User interface changes

None.

API changes

TBD. Probably API additions. Shouldn't be API changes. Definitely no BC changes.

Data model changes

None.

Release notes snippet

TBD

✨ Feature request
Status

Needs work

Version

11.0 πŸ”₯

Component
Layout builderΒ  β†’

Last updated 21 minutes ago

Created by

πŸ‡ͺπŸ‡ΈSpain penyaskito Seville πŸ’ƒ, Spain πŸ‡ͺπŸ‡Έ, UTC+2 πŸ‡ͺπŸ‡Ί

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Comments & Activities

Not all content is available!

It's likely this issue predates Contrib.social: some issue and comment data are missing.

  • Issue created by @penyaskito
  • πŸ‡ͺπŸ‡ΈSpain penyaskito Seville πŸ’ƒ, Spain πŸ‡ͺπŸ‡Έ, UTC+2 πŸ‡ͺπŸ‡Ί

    This would be much easier if we added a method to SectionStorageInterface and we let the section storage decide if it wants inline blocks or not. As that would break BC, not sure if the best way is to add a new interface instead.

    We would make SectionStorageBase implement that interface and provide the current behavior as default.

    Is that our best option?

  • @penyaskito opened merge request.
  • πŸ‡ͺπŸ‡ΈSpain penyaskito Seville πŸ’ƒ, Spain πŸ‡ͺπŸ‡Έ, UTC+2 πŸ‡ͺπŸ‡Ί

    Added inlineBlocksAllowedInContext which would fulfill layout builder restrictions requirements and dashboards/dashboard.

    However for layout builder restrictions to work without overriding the ChooseBlockController controller, it would need to swap the section storage class with hook_entity_type_alter, This might be worse than actually swapping the controller. So a hook might be the best alternative,

    This might be looked as an unnecessary indirection, but only found twice a hook or alter in a controller in core: hook_system_themes_page_alter and hook_help.

    And this way a module providing a section storage can opt-out without having to implement any hooks.

  • πŸ‡ͺπŸ‡ΈSpain penyaskito Seville πŸ’ƒ, Spain πŸ‡ͺπŸ‡Έ, UTC+2 πŸ‡ͺπŸ‡Ί

    Updated issue summary with proposed resolution in the MR. Clarified problem/motivation.

  • πŸ‡ͺπŸ‡ΈSpain penyaskito Seville πŸ’ƒ, Spain πŸ‡ͺπŸ‡Έ, UTC+2 πŸ‡ͺπŸ‡Ί

    Created πŸ“Œ [PP-1] Use hook instead of overriding controllers (#3351758) Postponed . Patch is green locally for layout_builder_restrictions with these changes.

  • Status changed to Needs review about 1 year ago
  • πŸ‡ͺπŸ‡ΈSpain penyaskito Seville πŸ’ƒ, Spain πŸ‡ͺπŸ‡Έ, UTC+2 πŸ‡ͺπŸ‡Ί

    This is ready for review.

  • Status changed to Needs work about 1 year ago
  • πŸ‡ΊπŸ‡ΈUnited States smustgrave

    Feel free to move back to NR if I got this wrong.

    But testing on 10.1.x
    Turned layout builder on and enabled for basic page content type
    added

    function layout_builder_layout_builder_allowed_inline_blocks_alter(array &$inline_blocks, SectionStorageInterface $section_storage, array $context) {
      // Don't allow custom basic blocks.
      if (($index = array_search('inline_block:basic', $inline_blocks)) !== FALSE) {
        unset($inline_blocks[$index]);
      }
    }
    

    just for testing with xdebug on.
    In layout builder when I click add block
    This hook gets called 11 times with the variables never changing.

    That expected?

  • πŸ‡ͺπŸ‡ΈSpain penyaskito Seville πŸ’ƒ, Spain πŸ‡ͺπŸ‡Έ, UTC+2 πŸ‡ͺπŸ‡Ί

    Good question.

    That hook ends up called for each category, as getBlockLinks() is called once per category.
    We cannot assume if there are or not inline blocks in a given category, or if all the inline blocks are in the same category, as someone could modify the categories in hook_plugin_filter_TYPE__CONSUMER_alter (aka hook_plugin_filter_block__layout_builder_alter).

    We could do something as:

      protected function getBlockLinks(SectionStorageInterface $section_storage, int $delta, $region, array $blocks) {
        $links = [];
        $hasBlockLinks = array_reduce($blocks, function ($found, $item) {
          return $found || $item['id'] === 'inline_block';
        });
        $allowed_inline_blocks = [];
        if ($hasBlockLinks) {
          $allowed_inline_blocks = $section_storage->inlineBlocksAllowedInContext($delta, $region);
        }
    
        foreach ($blocks as $block_id => $block) {
          if ($block['id'] === 'inline_block' && !in_array($block_id, $allowed_inline_blocks)) {
            continue;
          }
    

    To check that in each category and prevent some calls. However I'm not sure if that's premature optimization. Being fair I don't expect many implementations on the hook aside of layout_builder_restrictions, given that now any custom section storage could implement the inlineBlocksAllowedInContext method itself with this patch.

    Also, in most cases (or at least layout_builder_restrictions) will only process config on their hook implementation, and the config objects will be in memory between calls.

  • πŸ‡ΊπŸ‡ΈUnited States smustgrave

    Is there a way to tell which category I’m in? Or if this API is meant to disable inline blocks across the board?

  • πŸ‡ͺπŸ‡ΈSpain penyaskito Seville πŸ’ƒ, Spain πŸ‡ͺπŸ‡Έ, UTC+2 πŸ‡ͺπŸ‡Ί

    You can check $block['category'] for each block definition.

    In the hook, you could load all the blocks and use the categories for filtering which ones you want to allow. In any case the plugin system has caching mechanisms.

  • πŸ‡ͺπŸ‡ΈSpain penyaskito Seville πŸ’ƒ, Spain πŸ‡ͺπŸ‡Έ, UTC+2 πŸ‡ͺπŸ‡Ί

    Take into account that this would be used only for restricting inline blocks creation (or which bundles you want to allow).
    For the general use case of "other" blocks there is already hook_plugin_filter_TYPE__CONSUMER_alter (hook_plugin_filter_block__layout_builder_alter).

  • πŸ‡ΊπŸ‡ΈUnited States Dave Reid Nebraska πŸ‡ΊπŸ‡Έ

    Would it be easier and simpler to just check what the results of $this->blockManager->getFilteredDefinitions() and see if there are any inline blocks available as a result? We're already calling it in \Drupal\layout_builder\Controller\ChooseBlockController::build(), so it would be fairly easy to link those up rather than adding a new API for inlineBlocksAllowedInContext()?

Production build 0.69.0 2024