Block API overview

Last updated on
9 January 2017

Overview

Blocks in Drupal 8 are actually made up of two separate API structures to create a user experience similar to what Drupal has maintained in past iterations. These two APIs are the Block Plugin API, which is a stand-alone reusable API and the Block Entity API which is a Drupal 8 specific use case of block placement and visibility control.

Creating Block Plugin API blocks

Creating blocks defined in your module's code requires studying and understanding the Plugin API, and more specifically Annotations based plugin discovery. Which is the mechanism that Drupal 8 uses to locate the code that defines your block.

Creating a custom block defined by your module involves the following steps:

Make your block visible to Drupal and your users

Assuming a module name of fax; following the PSR-4 standard the code for your custom block(s) should be placed into fax/src/Plugin/Block/ and named based on the class it contains. If we're going to define the class FaxBlock this file would be fax/src/Plugin/Block/FaxBlock.php

In your FaxBlock.php file define a new class named FaxBlock like the following example:

namespace Drupal\fax\Plugin\Block;

use Drupal\Core\Block\BlockBase;

/**
 * Provides a 'Fax' block.
 *
 * @Block(
 *   id = "fax_block",
 *   admin_label = @Translation("Fax block"),
 * )
 */
class FaxBlock extends BlockBase {
  // Override BlockPluginInterface methods here.
}

The 'id' property in the annotation defines the unique, machine readable ID of your block, and the name of the block as it will be seen by other code. The 'admin_label' annotation defines the human readable name of the block that will be used when displaying your block in the administration interface. The available annotation properties can be found in \Drupal\Core\Block\Annotation\Block (the public properties).

The two most common methods to override:

BlockPluginInterface::build() - which is expected to return a render array which is the content you want your block to display.

BlockBase::access() - which controls the block's visibility and can be used to display or not display the block depending on custom logic. It is expected to return an AccessResult object.

Add custom configuration options to your block

You can also add custom configuration options to the block configuration form by overriding the BlockPluginInterface::blockForm() and BlockPluginInterface::blockSubmit() methods and then using the BlockBase::setConfigurationValue() and BlockBase::getConfiguration().

In this example we're adding a new textfield in our blockForm() method, and then saving the user entered data in the blockSubmit() method. You can also see how the data is made accessible to your code in the way that the current value is retrieved and used in the blockForm() method.

use Drupal\Core\Block\BlockBase;
use Drupal\Core\Form\FormBuilderInterface;
use Drupal\Core\Form\FormStateInterface;
/**
 * Provides a 'Fax' block.
 *
 * @Block(
 *   id = "fax_block",
 *   admin_label = @Translation("Fax block"),
 * )
 */
class FaxBlock extends BlockBase {

  // Access  method here ...

  /**
   * {@inheritdoc}
   */
  public function build() {
  
  $config = $this->getConfiguration();
    $fax_number = isset($config['fax_number']) ? $config['fax_number'] : '';
    return array(
      '#markup' => $this->t('The fax number is @number!', array('@number' => $fax_number)),
    );  
  }

  /**
   * {@inheritdoc}
   */
  public function blockForm($form, FormStateInterface $form_state) {
    $form = parent::blockForm($form, $form_state);

    // Retrieve existing configuration for this block.
    $config = $this->getConfiguration();

    // Add a form field to the existing block configuration form.
    $form['fax_number'] = array(
      '#type' => 'textfield',
      '#title' => t('Fax number'),
      '#default_value' => isset($config['fax_number']) ? $config['fax_number'] : '',
    );
    
    return $form;
  }

  /**
   * {@inheritdoc}
   */
  public function blockSubmit($form, FormStateInterface $form_state) {
    // Save our custom settings when the form is submitted.
    $this->setConfigurationValue('fax_number', $form_state->getValue('fax_number'));
  }

  /**
   * {@inheritdoc}
   */
  public function blockValidate($form, FormStateInterface $form_state) {
    $fax_number = $form_state->getValue('fax_number');

    if (!is_numeric($fax_number)) {
      $form_state->setErrorByName('fax_block_settings', t('Needs to be an integer'));
    }
  }
}

You could also use the BlockBase::getConfiguration() method in your build() method to retrieve the configuration data and display it to your users. Or in the access() method of your block to perform more complicated logic to determine if the block should be displayed or not.

Tags