Creating custom configuration for a block in Drupal 8

Blocks in Drupal 8 are instances of the block plugin that can be displayed in regions on your page. Default block implementation comes with the certain set of configurations. You can extend these with custom configurations using the API’s provided with the Drupal core PluginManager.

In our case, we had a requirement to create a custom block with a custom configuration i.e. the custom block must have a configuration allowing the user to select one or more taxonomy terms and a combination of content type and taxonomy term should be used to either hide or display our block based on the taxonomy tags attached to the article.

For Example: If I have an article with a reference field of type taxonomy with a vocabulary “entertainment” and the terms associated are TV, Shows, Movies. When we want to display a newsletter subscription block only for article content type and only when the article is tagged to “Movies” then we choose Article Category as “Movies” and content type as Article under block configurations.

Existing System

We can configure the block accordingly with the admin panel as well.We can place the block in the region and by block configuration, we can use URL’s where the block can be displayed. In my requirement, I have to make sure that the URLs are in a meaningful format i.e. instead of node/2 or node/3, I have to make sure that the URL looks like article/taxonomy-term/title-of-the-page. By this, I can restrict the pages in block configuration by placing article/tv/*.

The Disadvantage Of This System:

There is a disadvantage of this system i.e. the URL probabilities have to be checked. If there are more than 3 or 4 taxonomy terms and each article content type uses more than 3 terms, the mix and match become difficult.

For example, A article page is created with the taxonomy terms as movies, tv, and one added taxonomy term sports. Then the block must be placed in pages with the terms sports and tv. For this  the page restriction must be given in all probable ways such as article/tv/*,article/sports/*,article/movies-tv-sports/*. For every mapping, a restriction must be given.

Block Configuration With Custom Field

Instead, we can create a user flexible outcome by following few modifications in our code.

I created a custom block where a contact form is displayed.To that custom block, we add a form field where the taxonomy terms are rendered.

 * @file
 * Contains \Drupal\certification\Plugin\Block\ContactBlock.
namespace Drupal\certification\Plugin\Block;
use Drupal\Core\Block\BlockBase;
use Drupal\Core\Form\FormInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Entity\EntityTypeManager;
 * Provides a 'contact' block.
 * @Block(
 *   id = "contact_block",
 *   admin_label = @Translation("Contact Us"),
 *   category = @Translation("Certification")
 * )
class ContactBlock extends BlockBase {
   * {@inheritdoc}
  public function build() {
    $form = \Drupal::formBuilder()->getForm('Drupal\certification\Forms\WorkForm');
    return $form;
    * {@inheritdoc}
   public function blockForm($form, FormStateInterface $form_state) {
     $form = parent::blockForm($form, $form_state);
     $config = $this->getConfiguration();
     //query to get taxonomy terms from database
      $vid = 'entertainment';
     $query =\Drupal::entityTypeManager()->getStorage('taxonomy_term')->loadTree($vid);
     $taxonomies = array();
     foreach($query  as $term){
       $taxonomies[$term->tid] = $term->name;
     //entertainment field where the taxonomy terms are displayed in form of checkboxes
     $form['entertainment'] = [
       '#type' => 'checkboxes',
       '#title' => t('Entertainment'),
       '#description' => t('Select a Category Where the block has to be displayed '),
       '#options' => $taxonomies,
       '#default_value' =>  isset($config['entertainment']) ? $config['entertainment'] : []
     return $form;
    * {@inheritdoc}
   public function blockSubmit($form, FormStateInterface $form_state) {
     //setting value for entertainment field
     $this->setConfigurationValue('entertainment', $form_state->getValue('entertainment'));

Before the form field, the entity type manager gets the values of taxonomy name , id and vid(category of vocabulary). In the form field, the taxonomy terms are rendered as checkboxes which can be clickable by the end user.

After the CustomBlock.php is modified, Next step is to write a hook for it.

 * Implements hook_block_access().
function contact_block_access(\Drupal\block\Entity\Block $block, $operation, \Drupal\Core\Session\AccountInterface $account) {
$node = \Drupal::routeMatch()->getParameter('node');
$node_categories = [];
// Checking if it is an instance.
if ($node instanceof \Drupal\node\NodeInterface) {
  if ($node->hasField('field_category')) {
    // Getting target id of page.
    $node_categories = array_map(function($val) {
      return $val['target_id'];
    }, $node->get('field_category')->getValue());

if ($operation == 'view' && $block->getPluginId() == 'contact_block') {
  // Settings of configuration form.
  $block_settings = $block->get('settings');
  // Filtering only entertainment.
  $en_settings = array_filter($block_settings['entertainment']);
  // Count categories exists.
  if (count($node_categories)) {
    // Intersect target id and block id.
    if (!count(array_intersect($node_categories, $en_settings))) {
      // Restrict.
      return AccessResult::forbidden();
  else {
    // Restrict.
    return AccessResult::forbidden();
// Show the block.
return AccessResult::neutral();

For this hook, we use four namespaces those are Block, NodeInterface, AccountInterface, and AccessResult.

Namespace: You can think of it as a way of organizing classes into folders and subfolders and the namespace as the path to the file. If you try and create the same file with the same name in the same folder, you will get an error. You could change the name of the file, but if you really want to keep the same file name, you would most likely create a subfolder and put the file in there. This makes the file unique because it has a different path. Namespacing works in the same way.

Block Uses two API’s Block Plugin API and Block Entity API for extending the block.

NodeInterface  is used in different scenarios few of them are : check data value access ,checks if the current translation of the entity has unsaved changes,Checks whether the current translation is affected by the current revision,Gets the timestamp of the last entity change for the current translation and changes across all translations, Gets and Sets the node title, adds cache tags,Adds,checks and returns the translation object etc. In this scenario it is used to see if the term exists in the node (article) or not.

 AccountInterface  is used for role id for anonymous users,authenticated users,returns the display name,email id of the account, The timestamp when the account last accessed the site,Returns a list of roles,Checks whether a user has a certain permission.

AccessResult is used for creating access result if the permissions are present, it is neutral otherwise it is forbidden ,it is used to get,set and reset cache max age limit,cache tags,cache contexts.

The block taxonomy id is checked with node taxonomy id and if both of them intersect the block is displayed in the region. otherwise, the block is forbidden and not displayed in that region.



The taxonomy term Movies is selected with content type as Article.So the block will be displayed in the article pages where movies is used as a tag which you can see is displayed in the below screenshot

Below screenshot shows the article which is not tagged to “Movies” where the contact block is not displayed for the user.

As you saw from the above-listed scenario you can use the Drupal core API’s and update the block with the custom configuration in addition to the default configurations which are provided by Drupal. Similarly, you could introduce custom configuration for your requirement very easily.

About The Author

Leave a Reply