Porting blocks to Drupal 8 plugins

PIYUESH KUMAR   |  15th October, 2014

Plugins in Drupal 8 might sound as a new term for those who have not worked with pluggable entities like ctools in Drupal 7. As the name states Plug + in, its something that can be attached & removed easily, can fit into any context.

Drupal 8 has a  nice ecosystem built around plugins now. Those intereseted in knowing more about Drupal 8 Plugin system, here is an interesting video from Drupalcon Portland:

In this article, we are going to talk about only one kind of Plugin which is Block. You couldn't place a block into multiple regions in Drupal 7(without using a contrib module). With blocks being pluggable now, this is solved right in the core. 

For Drupal system to recognize a block, in Drupal 7 we had hook_block_info().This has been replaced with annotation-based discovery method in Drupal 8. Lets go through the porting process step by step. The major steps involved while writing a custom block plugin are as follows:

Directory Structure & where should the code be placed?:

Directory

 

Annotation Based Discovery:

Annotation Example

@Block(
  id = "demo_block",
  subject = @Translation("demo_module: Demo Block"),
  admin_label = @Translation("demo_module - Demo Block")
)

Read the complete deabte & detail on why use annotation based-discovery & the performance gains: https://www.drupal.org/node/1882526

Extending Blockbase Class:

SearchInterestBlock.php

namespace Drupal\demo_module\Plugin\Block;
use Drupal\Core\Block\BlockBase;
class DemoBlock extends BlockBase {
...
}

With OOPs in Drupal8, there is a base class that core provides for creating a custom block plugin on top of it. Details on Api available at https://api.drupal.org/api/drupal/core!lib!Drupal!Core!Block!BlockBase.php/class/BlockBase/8

Setting Default Configuration:

namespace Drupal\demo_module\Plugin\Block;
use Drupal\Core\Block\BlockBase;
class DemoBlock extends BlockBase {
/**
 * {@inheritdoc}
 */
  public function defaultConfiguration() {
    return array(
      'display_message' => 'no message set',
    );
  }
}

Controlling Access:

namespace Drupal\demo_module\Plugin\Block;
use Drupal\Core\Block\BlockBase;
class DemoBlock extends BlockBase {
 /**
  * {@inheritdoc}
  */
  protected function blockAccess(AccountInterface $account) {
    return $account->hasPermission('access content');
  }
}

Block Configuration Form:

namespace Drupal\demo_module\Plugin\Block;
use Drupal\Core\Block\BlockBase;
class DemoBlock extends BlockBase {
 /**
  * {@inheritdoc}
  */
  public function blockForm($form, FormStateInterface $form_state) {
    $form['display_message'] = array(
      '#type' => 'textfield',
      '#title' => t('Display message'),
      '#default_value' => $this->configuration['display_message'],
    );
    return $form;
  }
 
  /**
   * {@inheritdoc}
   */
  public function blockSubmit($form, FormStateInterface $form_state) {
    $this->configuration['display_message'] = $form_state->getValue('display_message');
  }
}

Block render callback:

namespace Drupal\demo_module\Plugin\Block;
use Drupal\Core\Block\BlockBase;
class DemoBlock extends BlockBase {
  /**
   * {@inheritdoc}
   */
  public function build() {
    return array(
      '#children' => $this->configuration['display_message'],
    );
  }
}

NOTE: Build function must return an array that can be passed to render function to generate HTML. You cannot renturn a static string from build function.

Looking for a Drupal partner ?

We are drupal 8 ready