How to Create a Custom Block that Embeds Nodes in Drupal 8

Written by Roberto Montero Published in This is a journey of epic proportions, not suited for the faint of heart. The other day we were looking for a way to embed a certain entity type and set the view mode, well a node, but it could've been any other entity type.

Now this may seem like a fairly easy task at first, but you will need to reach into your pocket of Drupal 8 skills to solve this one. You will need to know about Plugins, Dependency Injection, Interfaces, you name it. So the journey begins with creating a php file for the block plugin. Easy, right? Open up your IDE, find your custom module (let's call this one project Foo module Bar) and create the file for the block (let's name it Node Embed Block) so /foo/modules/custom/bar/src/Plugin/Block/NodeEmbedBlock.php and then we start the fun.

As you may already know, the Block Plugin extends the BlockBase class.  You'll need your basic methods: build(), blockForm(), blockValidate() [optional] and your blockSubmit().

Assuming you already know how to create a Block plugin and how to put the respective pieces into each function (won't bore you to death with the details) let's skip to the good parts.

Entity Autocomplete: Sure having a text field that takes the NID of the node you want to render sounds effective enough. Much simpler than creating an AJAX callback to do some sort of fancy autocomplete, right? Wrong! All that cool work has already been done for you and all you have to do to leverage it is call this new field type: entity_autocomplete check it out on the blockForm() function in the code below.

Dependency Injection: For the view modes, there's a class that has all that I want (\Drupal\Core\Entity\EntityDisplayRepositoryInterface), but it's not part of my block class. Solution? Dependency injection.

For this we will have to tweak the module a little bit. First we need to declare which classes we're using:

Now we're ready to extend the block plugin a little bit more by telling PHP that our class implements the ContainerFactoryPluginInterface. And that means that we need to add two more methods to our class: public function __construct() to assign the class that we want to use  $this->entityDisplayRepository = $entity_display_repository; and public static function create() to create the container and inject our dependency: $container->get('entity_display.repository')

Again, see the code below for the implementation details, for instance in the __construct() function you will need to specify the type of the class you're expecting.

But now that we have all the pieces fitting together, to get the view modes we can now call something like this:

And now the code:
[null, null, {"document_url": "http://rob.cr/blog/how-create-custom-block-embeds-nodes-drupal-8", "unformatted_src": "http://rob.cr/sites/default/files/field/image/37136101-lego-wallpaper_0.jpg", "src": "http://rob.cr/sites/default/files/field/image/37136101-lego-wallpaper_0.jpg", "formatted_filename": "lego wallpaper", "alt_text": "How to Create a Custom Block that Embeds Nodes in Drupal 8", "rendered_width": 1920, "rendered_height": 1439}, null, {"document_url": "http://rob.cr/blog/how-create-custom-block-embeds-nodes-drupal-8", "unformatted_src": "http://roberto-montero.com/sites/default/files/node_embed.png", "src": "http://roberto-montero.com/sites/default/files/node_embed.png", "formatted_filename": "node embed"}, null, {"document_url": "http://rob.cr/blog/how-create-custom-block-embeds-nodes-drupal-8", "unformatted_src": "https://assoc.drupal.org/files/da_individual_original.png", "src": "https://assoc.drupal.org/files/da_individual_original.png", "formatted_filename": "da individual original", "alt_text": "Rob Montero, Drupal Association Individual Member"}, null, null, null]