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:
/**
* Implements hook_ENTITY_TYPE_access() for entity type "block".
*/
function mymodule_block_access(\Drupal\block\Entity\Block $block, $operation, \Drupal\Core\Session\AccountInterface $account) {
if ($operation == 'update' && $block->getPluginId() == 'custom_block_plugin_id') {
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 (\Drupal::currentUser()->hasPermission('administer blocks')) {
return;
}
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;
}
}
}