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.