Inline block rendering with Pinto
Pinto Block provides a way to take over rendering of inline blocks, as powered by Core's Block Content (block_content.module) module. Pinto provides a clean way to centralize all the pieces needed to display data from a Block Content, while receiving context of the Layout Builder entity. Since Pinto Block-enhanced components are regular Pinto components, the components may be used outside of Layout Builder context. This way, Drupal's hook_preprocess, theme suggestions, and scattered Twig files, can be avoided.
You'll start this guide a ready-made Drupal installation, with Pinto, Layout Builder, and Block Content, configured, where a Block Content type has been created, and blocks from Block Content can already be placed.
This guide will also assist in setting up bundle classes, and modify a pre-existing Pinto component. Follow Quick Start for a fast way of setting up Pinto and a simple component.
Summary of steps:
- Create a bundle class
- Create a Pinto component
- Add Pinto Block glue to Pinto component
- Associate bundle class with the Pinto component
Set up bundle classes
Bundle classes are supported by all maintained versions of Drupal. They allow adding custom PHP behavior to bundles, where a class represents one or more bundles.
What are bundles?
A bundle is a sub-type of an entity, for example node has node types, media have media types, terms have taxonomy etc.
Bundle classes are Pinto Blocks' way of cleanly discovering and associating with a Block Content bundle.
The most straightforward way to set up bundle classes is by installing BCA.
Create a class in a custom module, under the Entity namespace:
namespace Drupal\my_module\Entity;
use Drupal\bca\Attribute\Bundle;
use Drupal\block_content\Entity;
#[Bundle(entityType: 'block_content', bundle: 'bundleMachineName', label: new TranslatableMarkup('MyBundle'))]
final class MyBundle extends BlockContent {}Replace bundleMachineName with the machine name of a bundle.
Replace MyBundle with a relevant class name and label.
Alterative: Core only, without BCA module.
Alternatively, to set up bundle class association without BCA, only core.
/**
* Implements hook_entity_bundle_info_alter().
*/
function my_module_entity_bundle_info_alter(array &$bundles): void {
$bundles['ENTITY_TYPE']['bundleMachineName']['class'] = \Drupal\my_module\Entity\MyBundle::class;
}The hook_entity_bundle_info_alter hook is used instead of #[Bundle] attribute
Augment a component class
Modify an existing component class, implementing BlockBundleInterface:
namespace Drupal\my_site_ds;
use Drupal\block_content\BlockContentInterface;
use Drupal\pinto\Object\DrupalInvokableSlotsTrait;
use Drupal\pinto_block\BlockBundleInterface;
use Drupal\pinto_block\ObjectContextInterface;
class MyComponent implements BlockBundleInterface {
use DrupalInvokableSlotsTrait;
public function __construct(
public string $str,
public int $number,
) {
}
public static function createForLayoutBuilderBlockContent(
BlockContentInterface $blockContent,
ObjectContextInterface $objectContext,
): static {
return new static(
// Transfer relevant data from the Block Content entity or Layout Builder entity.
// E.g:
(string) $blockContent->label(),
(int) $blockContent->id(),
);
}
}Associate Bundle Class with the Pinto component
Add a \Drupal\pinto_block\Attribute\PintoBlock attribute to the bundle class.
The $objectClassName argument is a class-string for the object.
namespace Drupal\my_module\Entity\BlockContent;
use Drupal\bca\Attribute\Bundle;
use Drupal\block_content\Entity\BlockContent;
use Drupal\my_site_ds\MyComponent;
use Drupal\pinto_block\Attribute\PintoBlock;
#[PintoBlock(objectClassName: MyComponent::class)]
#[Bundle(entityType: 'block_content', bundle: 'bundleMachineName', label: new TranslatableMarkup('MyBlockBundle'))]
final class MyBlockBundle extends BlockContent {}View the inline block
Now, when a inline block of type MyBlockBundle is rendered by Layout Builder, MyComponent::createForLayoutBuilderBlockContent will be called, allowing you to fully specify the HTML, CSS, and JavaScript or the inline block/block content.
Bonus topics
$blockContent context
Context provided by \Drupal\pinto_block\BlockBundleInterface::createForLayoutBuilderBlockContent($blockContent) allows you to transfer data for the relevant block content entity (\Drupal\block_content\Entity\BlockContent) to the Pinto component, and thusly the Twig template.
$objectContext context
Context provided by \Drupal\pinto_block\BlockBundleInterface::createForLayoutBuilderBlockContent($objectContext) provides further context. $objectContext is always an instance of \Drupal\pinto_block\ObjectContext:
INFO
entity and viewMode will be added to \Drupal\pinto_block\BlockBundleInterface when PHP 8.4 is minimum, as interfaces may now define properties.
$objectContext->entity: a\Drupal\Core\Entity\ContentEntityInterfaceinstance of the Layout Builder-enabled host entity.$objectContext->viewMode: astringrepresenting the view mode.