Restrict custom block visibility in Drupal - Bhimmu
Safeguard your content beyond the roles and permission, restrict custom block visibility in Drupal 10 programmatically using custom module
Why do you need to restrict custom block visibility
Recently I was working in a feature where I was making an external API request to fetch data and load it in a custom block. The content has visibility logic based on role and a subscription user has in the third party app.
Here I can not simply show or hide the block because part of content is common to all the users of same role but one portion of the block has different content which can not be displayed to other users of the same role.
How to restrict custom block visibility
A block plugin can be created by extending BlockBase class which uses BlockPluginTrait. This Trait can be found here web/core/lib/Drupal/Core/Block/BlockPluginTrait.php
You have to implement blockAccess method in your custom block to control the custom block visibility.
/**
* Indicates whether the block should be shown.
*
* Blocks with specific access checking should override this method rather
* than access(), in order to avoid repeating the handling of the
* $return_as_object argument.
*
* @param \Drupal\Core\Session\AccountInterface $account
* The user session for which to check access.
*
* @return \Drupal\Core\Access\AccessResultInterface
* The access result.
*
* @see self::access()
*/
protected function blockAccess(AccountInterface $account): AccessResult {
// @todo Evaluate the access condition here.
return AccessResult::allowedIf(TRUE);
}
In this function we can write our own logic and return the object of AccessResult class. It can return following methods.
AccessResult::isAllowed()
/**
* Checks whether this access result indicates access is explicitly allowed.
*
* Call this method to check whether someone has access, to convert an access
* result object to boolean.
*
* @return bool
* When TRUE then isForbidden() and isNeutral() are FALSE.
*/
public function isAllowed();
AccessResult::isForbidden()
/**
* Checks whether this access result indicates access is explicitly forbidden.
*
* Call this when optimizing an access checker (for hook_entity_access() or a
* route requirement): if this is TRUE, the final result will be forbidden and
* no further checking is necessary.
*
* Do not use this method to decide whether someone has access, to convert an
* access result to boolean: just because this returns FALSE, the end result
* might be neutral which is not allowed. Always use isAllowed() for this.
*
* @return bool
* When TRUE then isAllowed() and isNeutral() are FALSE.
*/
public function isForbidden();
AccessResult::isNeutral()
/**
* Checks whether this access result indicates access is not yet determined.
*
* @return bool
* When TRUE then isAllowed() and isForbidden() are FALSE.
*
* @internal
*/
public function isNeutral();
There are two other methods which give the opprtunity to restrict custom block visibility by combining set of condition.
# web/core/lib/Drupal/Core/Access/AccessResultInterface.php
orIf(AccessResultInterface $other);
andIf(AccessResultInterface $other);
Conclusion
Blocks can be useful to show content in specific area of your page, based on different cache logic, highly dynamic content based on different context and you can control it as per your need.
Full block example code.
<?php
namespace Drupal\knight\Plugin\Block;
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Block\BlockBase;
use Drupal\Core\Database\Connection;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Messenger\MessengerInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\Core\Session\AccountInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Provides a bhimmu block block.
*
* @Block(
* id = "knight_bhimmu_block",
* admin_label = @Translation("Bhimmu Block"),
* category = @Translation("Custom"),
* )
*/
final class BhimmuBlock extends BlockBase implements ContainerFactoryPluginInterface {
/**
* Constructs the plugin instance.
*/
public function __construct(
array $configuration,
$plugin_id,
$plugin_definition,
private readonly EntityTypeManagerInterface $entityTypeManager,
private readonly MessengerInterface $messenger,
private readonly Connection $connection,
) {
parent::__construct($configuration, $plugin_id, $plugin_definition);
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition): self {
return new self(
$configuration,
$plugin_id,
$plugin_definition,
$container->get('entity_type.manager'),
$container->get('messenger'),
$container->get('database'),
);
}
/**
* {@inheritdoc}
*/
public function build(): array {
$build['content'] = [
'#markup' => $this->t('It works!'),
];
return $build;
}
/**
* {@inheritdoc}
*/
protected function blockAccess(AccountInterface $account): AccessResult {
// @todo Evaluate the access condition here.
return AccessResult::allowedIf(TRUE);
}
}