0

I am creating a custom block plugin with custom configuration options (blockForm()).

I would like to allow content editors to edit the configuration of this block, without giving them "administer blocks" permission. Also, I don't want them to create new block instances..

I would like to avoid installing an additional module like block_permissions, as this would introduce a wide range of settings or permissions for all blocks, not just the specific block I am creating.

I also don't want this to be a "content" block with "fields". I want to know how this can be done with a custom plugin-based block.

EDIT / UPDATE
(based on responses and discussion)

The existing response is spot-on, if your goal is as described in the question.

However, the entire premise has one problem: The entire block placement will be exported to config, and overwritten on deployment. This means any user-controlled settings will be destroyed on next release. So this is not sustainable. A content block entity can be used to allow a proper split.

1

If a user doesn't have the admin permission for an entity type this doesn't mean you can't allow specific operations on specific existing entities.

For example, content editors you gave permission to administer content are also allowed to update blocks of your custom block plugin:

use Drupal\block\Entity\Block;
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Session\AccountInterface;

/**
 * Implements hook_ENTITY_TYPE_access() for entity type "block".
 */
function mymodule_block_access(Block $block, $operation, AccountInterface $account) {
  if ($operation == 'update'
    && $block->getPluginId() == 'custom_block_plugin_id'
    // The last condition is only needed if the trick from below is used with
    // `$block_entity->createDuplicate()->access('update')`.
    && $block->id() !== NULL
  ) {
    return AccessResult::allowedIfHasPermission($account, 'administer nodes');
  }
  return AccessResult::neutral();
}

You also need to alter the form not to redirect on submit to a page the user has no access to. Or link to the edit form with a destination query string pointing to a different page.


(EDIT by @donquixote)

If you want to restrict access to other elements on the page, you could do it like below.
This is a bit fragile, because it assumes a very specific structure of the form.

/**
 * Implements hook_form_FORM_ID_alter() for 'block_form'.
 */
function mymodule_form_block_form_alter(array &$form, FormStateInterface $form_state, string $form_id) {
  $form_object = $form_state->getFormObject();
  if (!$form_object instanceof BlockForm) {
    return;
  }
  /** @var Block $block_entity */
  $block_entity = $form_object->getEntity();
  if ($block_entity->getPluginId() !== 'custom_block_plugin_id') {
    return;
  }
  if ($block_entity->createDuplicate()->access('update')) {
    // The user has general access to update this block.
    return;
  }
  // The user was only given access via mymodule_block_access().
  // They should only edit the specific plugin settings, not change where the
  // block is placed.
  foreach (['visibility', 'id', 'weight', 'region'] as $key) {
    if (isset($form[$key])) {
      $form[$key]['#access'] = FALSE;
    }
  }
  foreach (['label', 'label_display'] as $key) {
    if (isset($form['settings'][$key])) {
      $form['settings'][$key]['#access'] = FALSE;
    }
  }
  foreach (['delete'] as $key) {
    if (isset($form['actions'][$key])) {
      $form['actions'][$key]['#access'] = FALSE;
    }
  }
}
12
  • Thanks, this works! However, now I also need hook_form_block_form_alter() to set '#access' => FALSE on all the elements I don't want them to edit. Which is most of the rest of this form.
    – donquixote
    Nov 24 at 13:18
  • The destination is fine already, because users will access this form through the contextual links.
    – donquixote
    Nov 24 at 13:19
  • Oops, I was assuming you would have to confirm the edits..
    – donquixote
    Nov 24 at 13:30
  • Let me know if the edit is ok, or feel free to modify it. I can also make it a separate answer, but I don't want to "steal" the "accepted answer" checkmark.
    – donquixote
    Nov 24 at 13:32
  • 1
    You can, if you want, alter the form elements in the custom block plugin directly by overriding buildConfigurationForm().
    – 4k4
    Nov 24 at 13:41

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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