block_editor-1.0.x-dev/src/Hook/ThemeHooks.php
src/Hook/ThemeHooks.php
<?php
namespace Drupal\block_editor\Hook;
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
use Drupal\Core\Entity\ContentEntityInterface;
use Drupal\Core\Hook\Attribute\Hook;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\block_editor\Service\EntityManager;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Theme-related hooks for Block Editor.
*/
class ThemeHooks implements ContainerInjectionInterface {
/**
* The current route match.
*/
protected RouteMatchInterface $routeMatch;
/**
* The Block Editor entity manager.
*/
protected EntityManager $entityManager;
/**
* Constructs a new ThemeHooks instance.
*/
public function __construct(RouteMatchInterface $route_match, EntityManager $entity_manager) {
$this->routeMatch = $route_match;
$this->entityManager = $entity_manager;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('current_route_match'),
$container->get('block_editor.entity_manager')
);
}
/**
* Implements hook_theme().
*
* Registers Block Editor form template.
*/
#[Hook('theme')]
public function theme(): array {
return [
'block_editor_form' => [
'render element' => 'form',
'template' => 'form--block-editor',
],
];
}
/**
* Implements hook_theme_suggestions_page_alter().
*
* Adds Block Editor theme suggestions for edit and add form pages.
*/
#[Hook('theme_suggestions_page_alter')]
public function themeSuggestionsPageAlter(array &$suggestions, array $variables): void {
$route_name = $this->routeMatch->getRouteName();
// Check if this is a Block Editor route.
if (!$route_name || !str_starts_with($route_name, 'block_editor.entity.')) {
return;
}
// Extract entity type and bundle information.
$info = $this->extractEntityInfo();
if (!$info) {
return;
}
['entity_type_id' => $entity_type_id, 'bundle' => $bundle] = $info;
// Add theme suggestions in order of specificity (least to most specific).
// Most specific suggestions should be added last.
$new_suggestions = [
'page__block_editor',
'page__' . $entity_type_id . '__block_editor',
'page__' . $bundle . '__' . $entity_type_id . '__block_editor',
];
// Insert before the last suggestion to maintain proper priority.
array_splice($suggestions, -1, 0, $new_suggestions);
}
/**
* Implements hook_theme_suggestions_html_alter().
*
* Adds Block Editor theme suggestions for HTML wrapper.
*/
#[Hook('theme_suggestions_html_alter')]
public function themeSuggestionsHtmlAlter(array &$suggestions, array $variables): void {
$route_name = $this->routeMatch->getRouteName();
// Check if this is a Block Editor route.
if (!$route_name || !str_starts_with($route_name, 'block_editor.entity.')) {
return;
}
// Extract entity type and bundle information.
$info = $this->extractEntityInfo();
if (!$info) {
return;
}
['entity_type_id' => $entity_type_id, 'bundle' => $bundle] = $info;
// Add theme suggestions in order of specificity.
$new_suggestions = [
'html__block_editor',
'html__' . $entity_type_id . '__block_editor',
'html__' . $bundle . '__' . $entity_type_id . '__block_editor',
];
// Insert before the last suggestion to maintain proper priority.
array_splice($suggestions, -1, 0, $new_suggestions);
}
/**
* Implements hook_theme_suggestions_block_editor_form_alter().
*
* Adds entity type and bundle-specific theme suggestions for Block Editor
* forms.
*/
#[Hook('theme_suggestions_block_editor_form_alter')]
public function themeSuggestionsBlockEditorFormAlter(array &$suggestions, array $variables): void {
// Get form element.
$form = $variables['form'] ?? [];
// Get entity type and bundle from form attributes.
$entity_type_id = $form['#block_editor_entity_type'] ?? NULL;
$bundle = $form['#block_editor_bundle'] ?? NULL;
if (!$entity_type_id || !$bundle) {
return;
}
// Add theme suggestions in order of specificity.
$suggestions[] = 'form__block_editor';
$suggestions[] = 'form__' . $entity_type_id . '__block_editor';
$suggestions[] = 'form__' . $bundle . '__' . $entity_type_id . '__block_editor';
}
/**
* Extracts entity type and bundle information from the current route.
*
* Works for both add and edit forms.
*
* @return array|null
* Array with 'entity_type_id' and 'bundle' keys, or NULL if not found.
*/
protected function extractEntityInfo(): ?array {
// For edit forms, the entity is already loaded.
foreach ($this->routeMatch->getParameters() as $parameter) {
if ($parameter instanceof ContentEntityInterface) {
return [
'entity_type_id' => $parameter->getEntityTypeId(),
'bundle' => $parameter->bundle(),
];
}
}
// For add forms, we need to get the entity type from the route.
$route_name = $this->routeMatch->getRouteName();
// Extract entity type from route name.
// Pattern: block_editor.entity.{entity_type}.add_form or edit_form.
if (preg_match('/^block_editor\.entity\.([^.]+)\.(add_form|edit_form)$/', $route_name, $matches)) {
$entity_type_id = $matches[1];
// For add forms, we need to get the bundle from route parameters.
// Get the bundle parameter mapping from the entity manager's
// configuration.
$bundle_parameter_mapping = $this->entityManager->getSupportedEntityTypeMappings();
if (isset($bundle_parameter_mapping[$entity_type_id])) {
$bundle_param_name = $bundle_parameter_mapping[$entity_type_id];
$bundle_id = $this->routeMatch->getParameter($bundle_param_name);
if ($bundle_id) {
return [
'entity_type_id' => $entity_type_id,
'bundle' => is_string($bundle_id) ? $bundle_id : $bundle_id->id(),
];
}
}
}
return NULL;
}
}
