CommentThemeHooks.php
Namespace
Drupal\comment\HookFile
-
core/
modules/ comment/ src/ Hook/ CommentThemeHooks.php
View source
<?php
namespace Drupal\comment\Hook;
use Drupal\Core\Datetime\DateFormatterInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Extension\ThemeSettingsProvider;
use Drupal\Core\Hook\Attribute\Hook;
use Drupal\Core\Link;
use Drupal\Core\Render\Element;
use Drupal\Core\Render\RendererInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\Core\Url;
/**
* Hook implementations for comment.
*/
class CommentThemeHooks {
use StringTranslationTrait;
public function __construct(protected DateFormatterInterface $dateFormatter, protected RendererInterface $renderer, protected EntityTypeManagerInterface $entityTypeManager, protected ThemeSettingsProvider $themeSettingsProvider) {
}
/**
* Implements hook_theme().
*/
public function theme() : array {
return [
'comment' => [
'render element' => 'elements',
'initial preprocess' => static::class . ':preprocessComment',
],
'field__comment' => [
'base hook' => 'field',
],
];
}
/**
* Prepares variables for comment templates.
*
* By default this function performs special preprocessing of some base fields
* so they are available as variables in the template. For example 'subject'
* appears as 'title'. 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().
*
* Default template: comment.html.twig.
*
* @param array $variables
* An associative array containing:
* - elements: An associative array containing the comment and entity
* objects. Array keys: #comment, #commented_entity.
*/
public function preprocessComment(array &$variables) : void {
/** @var \Drupal\comment\CommentInterface $comment */
$comment = $variables['elements']['#comment'];
$commented_entity = $comment->getCommentedEntity();
$variables['comment'] = $comment;
$variables['commented_entity'] = $commented_entity;
$variables['threaded'] = $variables['elements']['#comment_threaded'];
$skip_custom_preprocessing = $comment->getEntityType()
->get('enable_base_field_custom_preprocess_skipping');
// Make created, uid, pid and subject 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 = $comment->getFieldDefinition('created')
->isDisplayConfigurable('view') || $comment->getFieldDefinition('uid')
->isDisplayConfigurable('view');
if (!$skip_custom_preprocessing || !$submitted_configurable) {
$account = $comment->getOwner();
$username = [
'#theme' => 'username',
'#account' => $account,
];
$variables['author'] = $this->renderer
->render($username);
$variables['author_id'] = $comment->getOwnerId();
$variables['new_indicator_timestamp'] = $comment->getChangedTime();
$variables['created'] = $this->dateFormatter
->format($comment->getCreatedTime());
// Avoid calling DateFormatterInterface::format() twice on the same
// timestamp.
if ($comment->getChangedTime() == $comment->getCreatedTime()) {
$variables['changed'] = $variables['created'];
}
else {
$variables['changed'] = $this->dateFormatter
->format($comment->getChangedTime());
}
if ($this->themeSettingsProvider
->getSetting('features.comment_user_picture')) {
// To change user picture settings (for instance, image style), edit the
// 'compact' view mode on the User entity.
$variables['user_picture'] = $this->entityTypeManager
->getViewBuilder('user')
->view($account, 'compact');
}
else {
$variables['user_picture'] = [];
}
$variables['submitted'] = $this->t('Submitted by @username on @datetime', [
'@username' => $variables['author'],
'@datetime' => $variables['created'],
]);
}
if (isset($comment->in_preview)) {
$variables['permalink'] = Link::fromTextAndUrl($this->t('Permalink'), Url::fromRoute('<front>'))
->toString();
}
else {
$variables['permalink'] = Link::fromTextAndUrl($this->t('Permalink'), $comment->permalink())
->toString();
}
if (($comment_parent = $comment->getParentComment()) && (!$skip_custom_preprocessing || !$comment->getFieldDefinition('pid')
->isDisplayConfigurable('view'))) {
// Fetch and store the parent comment information for use in templates.
$account_parent = $comment_parent->getOwner();
$variables['parent_comment'] = $comment_parent;
$username = [
'#theme' => 'username',
'#account' => $account_parent,
];
$variables['parent_author'] = $this->renderer
->render($username);
$variables['parent_created'] = $this->dateFormatter
->format($comment_parent->getCreatedTime());
// Avoid calling DateFormatterInterface::format() twice on same timestamp.
if ($comment_parent->getChangedTime() == $comment_parent->getCreatedTime()) {
$variables['parent_changed'] = $variables['parent_created'];
}
else {
$variables['parent_changed'] = $this->dateFormatter
->format($comment_parent->getChangedTime());
}
$permalink_uri_parent = $comment_parent->permalink();
$attributes = $permalink_uri_parent->getOption('attributes') ?: [];
$attributes += [
'class' => [
'permalink',
],
'rel' => 'bookmark',
];
$permalink_uri_parent->setOption('attributes', $attributes);
$variables['parent_title'] = Link::fromTextAndUrl($comment_parent->getSubject(), $permalink_uri_parent)
->toString();
$variables['parent_permalink'] = Link::fromTextAndUrl($this->t('Parent permalink'), $permalink_uri_parent)
->toString();
$variables['parent'] = $this->t('In reply to @parent_title by @parent_username', [
'@parent_username' => $variables['parent_author'],
'@parent_title' => $variables['parent_title'],
]);
}
else {
$variables['parent_comment'] = '';
$variables['parent_author'] = '';
$variables['parent_created'] = '';
$variables['parent_changed'] = '';
$variables['parent_title'] = '';
$variables['parent_permalink'] = '';
$variables['parent'] = '';
}
if (!$skip_custom_preprocessing || !$comment->getFieldDefinition('subject')
->isDisplayConfigurable('view')) {
if (isset($comment->in_preview)) {
$variables['title'] = Link::fromTextAndUrl($comment->getSubject(), Url::fromRoute('<front>'))
->toString();
}
else {
$uri = $comment->permalink();
$attributes = $uri->getOption('attributes') ?: [];
$attributes += [
'class' => [
'permalink',
],
'rel' => 'bookmark',
];
$uri->setOption('attributes', $attributes);
$variables['title'] = Link::fromTextAndUrl($comment->getSubject(), $uri)
->toString();
}
}
// Helpful $content variable for templates.
foreach (Element::children($variables['elements']) as $key) {
$variables['content'][$key] = $variables['elements'][$key];
}
// Set status to a string representation of comment->status.
if (isset($comment->in_preview)) {
$variables['status'] = 'preview';
}
else {
$variables['status'] = $comment->isPublished() ? 'published' : 'unpublished';
}
// Add comment author user ID. Necessary for the comment-by-viewer library.
$variables['attributes']['data-comment-user-id'] = $comment->getOwnerId();
// Add anchor for each comment.
$variables['attributes']['id'] = 'comment-' . $comment->id();
}
/**
* Implements hook_preprocess_HOOK() for block templates.
*/
public function preprocessBlock(&$variables) : void {
if ($variables['configuration']['provider'] == 'comment') {
$variables['attributes']['role'] = 'navigation';
}
}
/**
* Implements hook_preprocess_HOOK() for field templates.
*
* Prepares variables for comment field templates.
*
* Default template: field--comment.html.twig.
*
* @param array $variables
* An associative array containing:
* - element: An associative array containing render arrays for the list of
* comments, and the comment form. Array keys: comments, comment_form.
*/
public function preprocessField(&$variables) : void {
$element = $variables['element'];
// We need to check for the field type even though we are using the comment
// theme hook suggestion. This is because there may be a bundle or field
// with the same name.
if ($element['#field_type'] == 'comment') {
// Provide contextual information.
$variables['comment_display_mode'] = $element[0]['#comment_display_mode'];
$variables['comment_type'] = $element[0]['#comment_type'];
// Append additional attributes from the first field item.
$variables['attributes'] += $variables['items'][0]['attributes']->storage();
// Create separate variables for the comments and comment form.
$variables['comments'] = $element[0]['comments'];
$variables['comment_form'] = $element[0]['comment_form'];
}
}
}
Classes
| Title | Deprecated | Summary |
|---|---|---|
| CommentThemeHooks | Hook implementations for comment. |
Buggy or inaccurate documentation? Please file an issue. Need support? Need help programming? Connect with the Drupal community.