19

In Drupal 6, I could control block visibility using PHP code in the block UI configuration like:

<?php return MYMODULE_abc() || MYMODULE_def() ; ?>

These functions looked up the current node, taxonomy, etc. to decide on whether to display the block. This PHP option is gone in Drupal 8, but there is a $visibility field in BlockBase. Can I use this to programmatically set the visibility at runtime?

4
  • 1
    You should declare a custom condition plugin instead. Search the core for @Condition to find working examples.
    – Eyal
    Jun 6, 2016 at 21:13
  • Generally writing PHP code into the database is bad practice and shoulder be avoided as much as possible.
    – Eyal
    Jun 6, 2016 at 21:14
  • 1
    The php filter module has been removed from D8. In general it is a bad idea to use php entered in the UI and executed in this way. It is a bad idea because missing a ; could cripple a whole site and then I will get hired to search the db to find the missing ; This has happened, Jun 7, 2016 at 1:22
  • Agreed! Is moved as much code as I could into the module, and glad that I can do this with pure code in D8!
    – Nic
    Jun 7, 2016 at 6:22

6 Answers 6

25

A working code snippet how to use hook_block_access(). Here I retrieve the condition from a field of the current node:

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

/**
 * Implements hook_block_access().
 */
function MYMODULE_block_access(Block $block, $operation, AccountInterface $account) {

  if ($operation === 'view' && $block->getPluginId() === 'MYBLOCK') {

    $node = \Drupal::routeMatch()->getParameter('node');

    $hero_image_exists = FALSE;

    if ($node instanceof NodeInterface) {
      if ($node->hasField('field_hero_image')) {
        if (!$node->get('field_hero_image')->isEmpty()) {
          $hero_image_exists = TRUE;
        }
      }
    }

    return AccessResult::forbiddenIf($hero_image_exists === FALSE)->addCacheableDependency($block);
  }

  return AccessResult::neutral();
}

Thanks @Insasse for sharing the following gem in the comments. For programmatically created custom blocks you can control visibility directly from inside the block class via blockAccess():

class MyBlock extends BlockBase {
  /**
   * {@inheritdoc}
   */
  public function build() {
    return [
      '#markup' => $this->t('This is a simple block!'),
    ];
  }

  /**
   * {@inheritdoc}
   */
  protected function blockAccess(AccountInterface $account) {
    return AccessResult::allowedIfHasPermission($account, 'access content');
  }

}

Source: How to Programmatically Create a Block in Drupal 8

3
  • 1
    You could even write the access check in your block class -> webwash.net/programmatically-create-block-drupal-8
    – DiDebru
    Aug 31, 2018 at 7:01
  • 1
    but should access be checked if we only want to determine if a block needs to be visible? I think the original question was not about access rules, but about visibility rules
    – Pere
    Nov 24, 2020 at 14:33
  • 1
    @Pere – In the hook you do if ($operation === 'view') and in the docs you'll find for blockAccess: Indicates whether the block should be shown. It's all about visibility. 🙂
    – leymannx
    Nov 24, 2020 at 15:13
8

Lacking the php filter in Drupal 8, this will no longer be possible from the UI.

The only option is to use the block api.

hook_block_access is your best canidate. From there you can check the $operation and return an AccessResult based on your conditions.

Just like in the UI only this time putting the php into a module.

5

For 8.2.x you need to create a Condition Plugin and implement the ContextProviderInterface.

See an example from D.O. but it is somehow outdated (because BlockEvent and BlockSubscriberBase removed in favor of a context repository service).

It would nice also to use Drupal console to generate the plugin:

drupal generate:plugin:condition
5

Here is the Drupal 8 solution: Block Exclude Pages.

This module adds an exclude pages filter for blocks.

To exclude specific pages after the wild card or in between wildcards, simply prefix the path pattern with a prefixed '!' in the block page visibility configuration.

This works for visibility set to "show for the listed pages", in this case, the exclude paths will hide the block on pages that match the despite the wildcard set to show.

Or the other way around, if the page list is set to "hide for the listed pages" the excluded paths will show the block on pages where the pattern matches despite the wild card set to hide.

Block Exclude Pages screenshot

1

to extend block visibility possibilities you can try this patch:

https://www.drupal.org/project/drupal/issues/923934#comment-12401360

it introduces the AND / OR conjunction operator for the visibility conditions so you can say oh I want this block visible if it is of my_content_type OR user has admin role OR the url starts with my/path/to/* etc.. also the conditions could be negated so you can set a lot of conditions at which you don't want your block to be visible

also if you use the Drupal Commerce module you can try the above by installing the https://www.drupal.org/project/commerce_quick_purchase module note that being installed the module exposes this functionality for all blocks on the system even if you don't use the block provided by the module see more

https://github.com/drugan/commerce_quick_purchase#block-visibility

additionally you can create your own condition plugin see example from the module

https://cgit.drupalcode.org/commerce_quick_purchase/tree/src/Plugin/Condition

1

Drupal 8, 9 and 10 have an improved 'path' condition for all content that implement Drupal Conditions: Condition Path

It allows included and excluded paths simultaneously to control block or other content visibility. It acts like the mentioned Block Exclude Pages module, but is more generic and leverages the Drupal Condition plugin API.

Your Answer

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

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