Note: This article assumes that you have a baseline understanding of what the Configuration System is and how it can be used in Drupal 8. If you aren’t familiar with these topics, I recommend reading Configuration Management in Drupal 8: The Key Concepts, or watching A Practical Guide to Configuration Management in Drupal 8. (You can also read the corresponding blog post.) This article also assumes that you are working with multiple environments to facilitate the development of a single site, typically dev, stage and prod. If you’re using a single environment you will not be deploying blocks, and likely don’t need to worry about the topics covered in this post.
Drupal 8’s Configuration System (CS) is excellent in many ways, but it can make the deployment of custom blocks difficult. This is because custom blocks are a bit of a gray area in the configuration management paradigm. Block placement is considered configuration, which means that it is managed by the CS. Custom block content, just like any other content entity in Drupal 8, cannot be managed directly by the CS, or any other system in core. If special consideration is not paid, this disconnect can lead to broken blocks during deployments. When block placement is accidentally deployed without the corresponding content, you will see this message:
This block is broken or missing. You may be missing content or you might need to enable the original module.
The lack of a mechanism to handle this in Drupal core leaves us with several possible remedies.
Create block on production ahead of time
This solution requires you to log onto your upstream site and create block content before a deployment. As long as you leave the block disabled, it will not show up until you deploy the corresponding configuration to place it.
- Quick: Create block content through the UI and go about your day.
- Simple: Don’t worry about using a system to automate custom block deployment (or the associated technical overhead).
- Familiar: Nearly all Drupal users will be familiar with the approach as it relies solely on Drupal core.
- Manual: Each deployment has one or more manual steps where block content must be created by hand. This takes an increasing amount of time as the list of environments / blocks to be deployed grows.
- Error Prone: It’s harder to rely on block deltas (bid) as it’s possible for them to change between environments due to typos or id conflicts. This may be unlikely, but it’s possible.
- Multi-step Deployments: If the custom block that you are deploying is based on a new custom block type (aka you needed to add fields to your block), you will need to deploy the custom block type configuration before you can create the custom block upstream.
Before we start, it’s important to note that all automated approaches will take longer initially due to time required to configure the chosen solution. Whether or not an automated approach is time effective for you depends on the frequency that you will be deploying custom blocks. If you only need to deploy a single custom block, the manual solution might be best. If you will need to deploy many custom blocks to many different environments, an automated approach might make more sense.
Update hooks are functions provided by modules that are only meant to be run once. This functionality, provided by Drupal core, is a great fit for our use case. An update hook to create a simple custom block can be found in the Drupal core issue related to this topic.
- No overhead: We’re relying on functionality provided by Drupal core, so there is no extra system to add or maintain.
- Tedious: If you need to deploy many blocks, writing a new update hook in order to create each one will be tedious. You can write some helper functions to mitigate this, but you still need to write some custom code in order to deploy each new block.
- Content in code: The update hook above makes the block’s initial content part of the site’s repository / code base. After the initial deployment, this code becomes clutter.
Default Content Module
This approach is conceptually very similar to the update hook method mentioned above, except it leverages the default content module in order to save you from writing many tedious update hooks. This module provides several Drush commands that automatically export content entities, including custom blocks, to hal + json files on your system. Then you can commit the exported entities to your code base and deploy them along with your block placement configuration.
Note: as of writing this module has 2 downfalls that will hinder its use in the manner described above. First, content entities are only imported when the module is enabled, making multiple block deployments over time more difficult. Second, a fatal error is thrown when trying to import content that already exists on the system. Luckily, the Drupal community is awesome and there are patches available to solve both issues (first, second).
- Quick: Export content entities with a single Drush command
- Robust: The module is capable of handling fairly complex entities, including entity relationships. Also, it’s not limited to blocks, all major content entities are fair game.
- Automated: Deployments are totally automated with this system, requiring no extra steps.
- Content in code: Just like with the update hook option above, you are committing content to your code base
- Overhead: If you’re a purist, you may not like the idea of using a contributed module to do something that could be handled by core functionality
Recreate Block Content
The Recreate Block Content module takes a different approach than default content. Instead of exporting content to your code base, this module creates a placeholder block with no content, which will take the place of any missing block content, effectively preventing the broken block handler from rearing its ugly head.
- Clean code base: No content mixed in with code
- Manual steps: You will need to update the placeholder blocks with real content each time you deploy.
Fixed Block Content
The Fixed Block Content module serves a similar purpose to the default content module, with a few key differences.
- Instead of exporting content to your code base, it relies on the default field values that you create when setting up your block type configuration. This is great because there is no duplication of content. Default field values are already part of core.
- It does not rely on an amalgamation of content and config, instead it relies solely on the CS to store default content.
- If any of the fixed blocks that you create are ever deleted, this module will recreate them automatically.
- Everything can be managed through the UI, unlike default content. This is a big win for site builders.
- Unified: Everything is handled by the CS
- Durable: You can’t accidentally delete a fixed block. This could be good or bad depending on how you view it, but I consider this a positive.
- UI Friendly: Power to the site builder!
- Automated: No manual deployment steps
- Less flexible: If you want to create several blocks of the same type, they will all be created with the same default content. You can change this after you deploy, but this is still not as flexible as the default content module.