class NodeThemeHooks
Hook implementations for the node module.
Hierarchy
- class \Drupal\node\Hook\NodeThemeHooks
Expanded class hierarchy of NodeThemeHooks
1 file declares its use of NodeThemeHooks
- node.module in core/
modules/ node/ node.module
File
-
core/
modules/ node/ src/ Hook/ NodeThemeHooks.php, line 20
Namespace
Drupal\node\HookView source
class NodeThemeHooks {
public function __construct(protected readonly RouteMatchInterface $routeMatch, protected readonly RendererInterface $renderer, protected readonly EntityTypeManagerInterface $entityTypeManager) {
}
/**
* Implements hook_theme().
*/
public function theme() : array {
return [
'node' => [
'render element' => 'elements',
'initial preprocess' => static::class . ':preprocessNode',
],
'node_add_list' => [
'variables' => [
'content' => NULL,
],
'initial preprocess' => static::class . ':preprocessNodeAddList',
],
'node_edit_form' => [
'render element' => 'form',
],
// @todo Delete the next three entries as part of
// https://www.drupal.org/node/3015623
'field__node__title' => [
'base hook' => 'field',
],
'field__node__uid' => [
'base hook' => 'field',
],
'field__node__created' => [
'base hook' => 'field',
],
];
}
/**
* Implements hook_theme_suggestions_HOOK().
*/
public function themeSuggestionsNode(array $variables) : array {
$suggestions = [];
$node = $variables['elements']['#node'];
$sanitized_view_mode = strtr($variables['elements']['#view_mode'], '.', '_');
$suggestions[] = 'node__' . $sanitized_view_mode;
$suggestions[] = 'node__' . $node->bundle();
$suggestions[] = 'node__' . $node->bundle() . '__' . $sanitized_view_mode;
$suggestions[] = 'node__' . $node->id();
$suggestions[] = 'node__' . $node->id() . '__' . $sanitized_view_mode;
return $suggestions;
}
/**
* Implements hook_preprocess_HOOK() for node field templates.
*/
public function preprocessFieldNode(&$variables) : void {
// Set a variable 'is_inline' in cases where inline markup is required,
// without any block elements such as <div>.
if ($variables['element']['#is_page_title'] ?? FALSE) {
// Page title is always inline because it will be displayed inside <h1>.
$variables['is_inline'] = TRUE;
}
elseif (in_array($variables['field_name'], [
'created',
'uid',
'title',
], TRUE)) {
// Display created, uid and title fields inline because they will be
// displayed inline by node.html.twig. Skip this if the field
// display is configurable and skipping has been enabled.
// @todo Delete as part of https://www.drupal.org/node/3015623
/** @var \Drupal\node\NodeInterface $node */
$node = $variables['element']['#object'];
$skip_custom_preprocessing = $node->getEntityType()
->get('enable_base_field_custom_preprocess_skipping');
$variables['is_inline'] = !$skip_custom_preprocessing || !$node->getFieldDefinition($variables['field_name'])
->isDisplayConfigurable('view');
}
}
/**
* Prepares variables for node templates.
*
* Default template: node.html.twig.
*
* Most themes use their own copy of node.html.twig. The default is located
* inside "/core/modules/node/templates/node.html.twig". Look in there for the
* full list of variables.
*
* By default this function performs special preprocessing of some base fields
* so they are available as variables in the template. For example 'title'
* appears as 'label'. This preprocessing is skipped if:
* - a module makes the field's display configurable via the field UI by means
* of BaseFieldDefinition::setDisplayConfigurable()
* - AND the additional entity type property
* 'enable_base_field_custom_preprocess_skipping' has been set using
* hook_entity_type_build().
*
* @param array $variables
* An associative array containing:
* - elements: An array of elements to display in view mode.
* - node: The node object.
* - view_mode: View mode; e.g., 'full', 'teaser', etc.
*
* @see hook_entity_type_build()
* @see \Drupal\Core\Field\BaseFieldDefinition::setDisplayConfigurable()
*/
public function preprocessNode(&$variables) : void {
$variables['view_mode'] = $variables['elements']['#view_mode'];
// The teaser variable is deprecated.
$variables['deprecations']['teaser'] = "'teaser' is deprecated in drupal:11.1.0 and is removed in drupal:12.0.0. Use 'view_mode' instead. See https://www.drupal.org/node/3458185";
$variables['teaser'] = $variables['view_mode'] == 'teaser';
// The 'metadata' variable was originally added to support RDF, which has
// now been moved to contrib. It was needed because it is not possible to
// extend the markup of the 'submitted' variable generically.
$variables['deprecations']['metadata'] = "'metadata' is deprecated in drupal:11.1.0 and is removed in drupal:12.0.0. There is no replacement. See https://www.drupal.org/node/3458638";
$variables['node'] = $variables['elements']['#node'];
/** @var \Drupal\node\NodeInterface $node */
$node = $variables['node'];
$skip_custom_preprocessing = $node->getEntityType()
->get('enable_base_field_custom_preprocess_skipping');
// Make created, uid and title fields available separately. Skip this custom
// preprocessing if the field display is configurable and skipping has been
// enabled.
// @todo https://www.drupal.org/project/drupal/issues/3015623
// Eventually delete this code and matching template lines. Using
// $variables['content'] is more flexible and consistent.
$submitted_configurable = $node->getFieldDefinition('created')
->isDisplayConfigurable('view') || $node->getFieldDefinition('uid')
->isDisplayConfigurable('view');
if (!$skip_custom_preprocessing || !$submitted_configurable) {
$variables['date'] = !empty($variables['elements']['created']) ? $this->renderer
->render($variables['elements']['created']) : '';
$variables['author_name'] = !empty($variables['elements']['uid']) ? $this->renderer
->render($variables['elements']['uid']) : '';
unset($variables['elements']['created'], $variables['elements']['uid']);
}
if (isset($variables['elements']['title']) && (!$skip_custom_preprocessing || !$node->getFieldDefinition('title')
->isDisplayConfigurable('view'))) {
$variables['label'] = $variables['elements']['title'];
unset($variables['elements']['title']);
}
$variables['url'] = !$node->isNew() ? $node->toUrl('canonical')
->toString() : NULL;
// The 'page' variable is set to TRUE in two occasions:
// - The view mode is 'full' and we are on the 'node.view' route.
// - The node is in preview and view mode is either 'full' or 'default'.
$variables['page'] = $variables['view_mode'] == 'full' && node_is_page($node) || isset($node->in_preview) && in_array($node->preview_view_mode, [
'full',
'default',
]);
// Helpful $content variable for templates.
$variables += [
'content' => [],
];
foreach (Element::children($variables['elements']) as $key) {
$variables['content'][$key] = $variables['elements'][$key];
}
if (isset($variables['date'])) {
// Display post information on certain node types. This only occurs if
// custom preprocessing occurred for both of the created and uid fields.
// @todo https://www.drupal.org/project/drupal/issues/3015623
// Eventually delete this code and matching template lines. Using a
// field formatter is more flexible and consistent.
$node_type = $node->type->entity;
$variables['author_attributes'] = new Attribute();
$variables['display_submitted'] = $node_type->displaySubmitted();
if ($variables['display_submitted']) {
if (theme_get_setting('features.node_user_picture')) {
// To change user picture settings (e.g. image style), edit the
// 'compact' view mode on the User entity. Note that the 'compact'
// view mode might not be configured, so remember to always check the
// theme setting first.
if ($node_owner = $node->getOwner()) {
$variables['author_picture'] = $this->entityTypeManager
->getViewBuilder('user')
->view($node_owner, 'compact');
}
}
}
}
}
/**
* Prepares variables for list of available node type templates.
*
* Default template: node-add-list.html.twig.
*
* @param array $variables
* An associative array containing:
* - content: An array of content types.
*
* @see \Drupal\node\Controller\NodeController::addPage()
*/
public function preprocessNodeAddList(&$variables) : void {
$variables['types'] = [];
if (!empty($variables['content'])) {
foreach ($variables['content'] as $type) {
$variables['types'][$type->id()] = [
'type' => $type->id(),
'add_link' => Link::fromTextAndUrl($type->label(), Url::fromRoute('node.add', [
'node_type' => $type->id(),
]))
->toString(),
'description' => [
'#markup' => $type->getDescription(),
],
];
}
}
}
/**
* Implements hook_preprocess_HOOK() for HTML document templates.
*/
public function preprocessHtml(&$variables) : void {
// If on an individual node page or node preview page, add the node type to
// the body classes.
if (($node = $this->routeMatch
->getParameter('node')) || $node = $this->routeMatch
->getParameter('node_preview')) {
if ($node instanceof NodeInterface) {
$variables['node_type'] = $node->getType();
}
}
}
/**
* Implements hook_preprocess_HOOK() for block templates.
*/
public function preprocessBlock(&$variables) : void {
if ($variables['configuration']['provider'] == 'node') {
switch ($variables['elements']['#plugin_id']) {
case 'node_syndicate_block':
$variables['attributes']['role'] = 'complementary';
break;
}
}
}
}
Members
Title Sort descending | Modifiers | Object type | Summary |
---|---|---|---|
NodeThemeHooks::preprocessBlock | public | function | Implements hook_preprocess_HOOK() for block templates. |
NodeThemeHooks::preprocessFieldNode | public | function | Implements hook_preprocess_HOOK() for node field templates. |
NodeThemeHooks::preprocessHtml | public | function | Implements hook_preprocess_HOOK() for HTML document templates. |
NodeThemeHooks::preprocessNode | public | function | Prepares variables for node templates. |
NodeThemeHooks::preprocessNodeAddList | public | function | Prepares variables for list of available node type templates. |
NodeThemeHooks::theme | public | function | Implements hook_theme(). |
NodeThemeHooks::themeSuggestionsNode | public | function | Implements hook_theme_suggestions_HOOK(). |
NodeThemeHooks::__construct | public | function |
Buggy or inaccurate documentation? Please file an issue. Need support? Need help programming? Connect with the Drupal community.