Objectives & prerequisites
- Learn how to define basic blocks in code.
- Encounter new concepts: plugins, annotations, attributes, and docblocks.
Coded Blocks are Plugin Blocks
Not to be confused with Content Blocks (blocks created through the administration interface), coded blocks are plugins. More specifically: block plugins, a new concept introduced in Drupal 8.
There are a few dozen plugin types in Drupal core, of which Block is one.
For now, all you need to know is that blocks are plugins and must follow a few rules.
Plugin Blocks use Annotations / Attributes
As of Drupal 8 you need to use an annotation to correctly declare a block. Until PHP 8, annotations were not part of the PHP programming language, so frameworks relied on external libraries to make annotations possible. Drupal, for instance, relies on the Doctrine/Annotations package.
In the mean time PHP has evolved and natively supports annotations, which it names "PHP Attributes".
As of Drupal 10.2 core has started to add support for PHP Annotations, with the aim of replacing all annotations with attributes, starting with Block plugins and Action plugins.
As a result, at the time of writing (Drupal 10.3) you can choose to use either the annotation or the attribute syntax when declaring new blocks, but we strongly suggest you only use the attribute syntax, as annotations are going to slowly disappear. Always write forward-facing code if you can!
Docblocks
A docblock is a block of source code comments, constructed and formatted in a pre-defined way.
To avoid confusion: the 'block' in 'docblock' refers to 'a block of comments', not with the fact that this course chapter discusses Drupal blocks. Every single Drupal PHP source code file contains numerous docblocks to document Drupal's source code in a structured, uniform way.
Here's an example from Drupal's source code:
Drupal's Docblocks provide insight in what the file, class, or method provides, which parameters it accepts, what it returns, and more.
For now, all you need to know is that to define a block, your class must be preceded by a docblock that contains an annotation.
Creating a block
Let's start by looking at the typical file structure for defining a basic Drupal block. Don't paste of these examples into your demo module yet - we'll get to that.
The following example shows how to create a block using the annotation syntax. Though you can still use this syntax, we recommend that you do NOT, as it is being replaced with the Attribute syntax.
The annotation syntax shown below is added for historical context and to illustrate the difference.
When you create your own blocks, please use the Attribute syntax instead.
Here is a demo using annotation:
And here is a demo using attributes:
At first glance, the above code is similar to the controller classes you've created a few times now in this course.
Let's start at the top:
1. Declare namespace
namespace Drupal\my_module\Plugin\Block;Since you're creating a block, and blocks are plugins, your namespace needs to end in \Plugin\Block, which indicates that your class file must live in src/Plugin/Block/:
my_module/
├─ src/
│ ├─ Plugin/
│ │ ├─ Block/
│ │ │ ├─ MyBlock.php2. Import BlockBase namespace
Blocks extend BlockBase, so you need to import that namespace:
use Drupal\Core\Block\BlockBase;3.a Add a Block Annotation
Your block class won't be complete without providing a @Block annotation. If you don't provide the annotation, your block will not work correctly, or even be listed among the available blocks.
In PHP, annotations must be provided as part of a docblock, so annotations are comment and code at the same time:
The @Block annotation:
/**
* [...]
*
* @Block(
* id = "my_module_my_demo_block",
* admin_label = @Translation("My demo block"),
* )
*/This annotation:
- Injects additional functionality into your class (which functionality exactly is not relevant at this time)
- Sets the machine name (internal identifier) of the block to 'my_module_my_demo_block'.
- Sets the human-readable name of this block to 'My demo block', and makes that name translatable.
→ It's important to repeat that in PHP, annotations must be declared as part of a block of comments, but they are actual code. This may change in later versions of PHP, but for now, this is how annotations work.
3.b Add a Block Attribute
To start we need to import a few more classes to provide some functionality for building our block:
use Drupal\Core\Block\Attribute\Block;(Used to provide the block attribute class or "block attribute" for short)use Drupal\Core\StringTranslation\TranslatableMarkup;(Used for handling translatable strings)
Your block class won't be complete without providing a #[Block] attribute. If you don't provide the block attribute, your block will not work correctly, or even be listed among the available blocks.
As of PHP 8, attributes can be used instead of annotations. They serve a similar purpose to annotations in previous versions of PHP:
The #[Block] attribute:
/**
* This is a demo block.
*/
#[Block(
id: "goodbye_block",
admin_label: new TranslatableMarkup("My goodbye block"),
category: new TranslatableMarkup("My Block Demo")
)]This attribute:
- Injects additional functionality into your class (which functionality exactly is not relevant at this time)
- Sets the machine name (internal identifier) of the block to 'goodbye_block'.
- Sets the human-readable name of this block to 'My goodbye block', and makes that name translatable.
- Categorizes this block under ‘My Block Demo’.
→ It's important to repeat that as of PHP 8, attributes must be declared using the #[...] syntax, which is actual code and not a comment, unlike annotations in previous versions.
4. Extend BlockBase and implement build()
Your class must extend BlockBase and must implement the build() method.
Whenever a block is being prepared for display, the Block Manager will assume your class has a build() method and will try to execute it. Without a build() method your block won't work.
Return a render array
Just like a page controller method needs to return a render array, so does build():
return [
'#markup' => $this->t('This is my demo block'),
];
Going further
Most of the blocks you create in code, such as the example above, will be relatively basic blocks without custom configuration forms or special visibility rules. If you want to add these things, you'll have to implement the appropriate methods, such as BlockForm() along with build(), though that is outside the scope of this course.
→ If you're feeling adventurous, look up the class definition for BlockBase and interfaces, such as BlockPluginInterface, that it implements. This will show you other class methods you can use and/or implement.
5. Clear cache
After you've added your block class file in the right directory, and made sure your custom module is enabled:
- clear cache
- verify that your block is discovered and works correctly by assigning it to a region via Manage > Structure > Block Layout.
Summary
- Blocks are plugins.
- Blocks must use the
[...]/Plugin/Block namespace. - Block class definitions must live in
[...]/src/Plugin/Block/. - Blocks must extend BlockBase.
- Blocks must use the #[
Block]Attribute. Alternatively they can also use the outdated annotation syntax instead. - Blocks must implement a
build()method.