Skip to content

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:

  1. Create a bundle class
  2. Create a Pinto component
  3. Add Pinto Block glue to Pinto component
  4. 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:

php
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.

php
/**
 * 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:

php
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.

php
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\ContentEntityInterface instance of the Layout Builder-enabled host entity.
  • $objectContext->viewMode: a string representing the view mode.