
Porting blocks to Drupal 8 plugins
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?:

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.