Essential APIs - Block
From Block API Overview on Drupal.org updated July 2024: Blocks in Drupal 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 specific use case of block placement and visibility control.
The Block Plugin API remains part of the core plugin system, allowing developers to define reusable, programmatically-created blocks by extending the BlockBase class. Plugins are defined in code and registered via annotations.
The Block Entity API is part of the Custom Block module (renamed as Block Content module). It allows site builders and content editors to manage blocks as content entities with revisions, fields, and translations.
Make sure you understand the Plugin API before continuing.
Steps for setting up a custom block:
- Create block plugin using annotations
- Extend the
Drupal\Core\Block\BlockBase
class - Implement the necessary methods from the
Drupal\Core\Block\BlockPluginInterface
Example from Block API Overview:
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'));
}
}
}
Related Drupal Hooks for the Block API
- hook_block_access()
- Purpose: Control block access dynamically based on custom conditions.
- Use Case: Restrict blocks to specific user roles or permissions.
- hook_block_view_alter()
- Purpose: Alter the render array of a block before it is displayed on the page.
- Use Case: Modify block content dynamically, add classes, or insert extra elements.
- Block specific: hook_block_build_BASE_BLOCK_ID_alter()
- hook_block_alter()
- Purpose: Modify block objects after they are loaded from storage.
- Use Case: Change block properties such as title, configuration, or settings dynamically.
- Block specific: hook_block_view_BASE_BLOCK_ID_alter()
Older Drupal 7 Hooks
- hook_block_configure_alter
- hook_block_info_alter
- hook_block_list_alter
Additional information for Hooks provided by the Block module
Questions
General
What are the different APIs that make up what is commonly referred to as the Block API and what are their purpose?
Block Plugin API and the Block Entity API: The Block Plugin API is a stand-alone reusable API, and the Block Entity API which is a Drupal use case of the block placement and visibility control.
What are the 3 steps of creating a custom block?
- Create a block plugin using annotations
- Extend the Drupal\Core\Block\BlockBase class
- Implement the methods from the Drupal\Core\Block\BlockPluginInterface interface needed for your use case
Backend Developer (Advanced)
Which method must be implemented when creating a custom block plugin?
build()
When creating a custom block plugin, how do you define its administrative label?
Using an annotation in the block plugin class
If a block needs to display dynamic content based on the current node being viewed, which caching mechanism should you use?
Override the getCacheContexts() method to add the route context
public function getCacheContexts() {
// This example breaks bubbling of cacheable metadata
return ['url.path', 'url.query_args'];
}