twigsuggest.module in Twig Template Suggester 8
Twig Template Suggester module hook implementations.
File
twigsuggest.moduleView source
<?php
/**
* @file
* Twig Template Suggester module hook implementations.
*/
use Drupal\block\Entity\Block;
/**
* Implements hook_theme_suggestions_HOOK() for block templates.
*
* * Suggest region-specific block templates.
*
* Note: To suggest block type (bundle) specific block templates, use Block Type
* Templates module, https://www.drupal.org/project/block_type_templates
*
* @TODO https://www.drupal.org/project/twigsuggest/issues/3007447
*/
function twigsuggest_theme_suggestions_block(array $variables) {
$suggestions = [];
// Prevent PHP notices if contrib modules create blocks without this ID.
if (isset($variables['elements']['#id']) || !empty($variables['elements']['#id'])) {
if ($block = Block::load($variables['elements']['#id'])) {
$suggestions[] = 'block__' . $block
->getRegion();
$suggestions[] = 'block__' . $block
->getRegion() . '__' . $variables['elements']['#id'];
if ($block
->get('settings') && ($provider = $block
->get('settings')['provider'])) {
// I'm pretty sure core is already providing provider as a suggestion.
// $suggestions[] = 'block__' . $provider;.
$base_plugin = $variables['elements']['#base_plugin_id'];
if ($base_plugin !== $provider) {
$suggestions[] = 'block__' . $base_plugin;
}
$suggestions[] = 'block__' . $provider . '__' . $block
->getRegion();
if ($variables['elements']['#base_plugin_id'] != $provider) {
$suggestions[] = 'block__' . $base_plugin . '__' . $block
->getRegion();
}
if (isset($variables['elements']['content']['#menu_name'])) {
$menu_name = str_replace("-", "_", $variables['elements']['content']['#menu_name']);
$suggestions[] = 'block__' . $provider . '__' . $menu_name . '__' . $block
->getRegion();
if ($base_plugin !== $provider) {
$suggestions[] = 'block__' . $base_plugin . '__' . $menu_name . '__' . $block
->getRegion();
}
}
}
}
}
return $suggestions;
// @TODO decide whether to prefix these suggestions. Probably best to be
// consistent but if i were to *not* prefix one, it would actually probably be
// bundles (content type, block type, etc.). Block Type Templates gets around
// this by prefacing its suggestions more intelligibly with 'block-content'
// (as types only applies to custom, content blocks) so giving it suggestions
// like this: block--block-content-{{ machine-name-of-block-type }}.html.twig
// but the code floating out there everywhere from Jeff Burnz (he recommends
// Block Type Templates module over this earlier code snippet of his) does
// preface with bundle:
// if (isset($variables['elements']['content']['#block_content'])) {
// array_splice($suggestions, 1, 0, 'block__bundle__' .
// $variables['elements']['content']['#block_content']->bundle());
// }
}
/**
* Implements hook_theme_suggestions_HOOK_alter() for layout templates.
*
* Fix suggestion of entity type specific layout templates.
*/
function twigsuggest_theme_suggestions_layout_alter(array &$suggestions, array $variables) {
// Sometimes this can be helpful but othertimes apparently not so this hook
// is disabled by default but can be enabled in settings.php:
// $config['twigsuggest.settings']['alternate_ds_suggestions'] = TRUE;.
if (!\Drupal::config('twigsuggest.settings')
->get('alternate_ds_suggestions')) {
return;
}
// Although this appears to be done by default it's actually broken, as seen
// in this bug report: https://www.drupal.org/project/drupal/issues/2881195
// Apparently using two underscores/dashes will make it work despite the
// double-listing (layout--onecol is there twice) still happening.
if (isset($variables['content']) && is_array($variables['content']) && isset($variables['content']['#ds_configuration']) && $variables['theme_hook_original'] != 'ds_entity_view') {
$layout_id = $variables['content']['#ds_configuration']['layout']['id'];
$layout_id_len = strlen($layout_id);
foreach ($suggestions as $key => $suggestion) {
if (strpos($suggestion, $layout_id) === 0) {
$base_suggest = str_replace('_', '__', $layout_id);
$suggestions[$key] = substr_replace($suggestion, $base_suggest, 0, $layout_id_len);
}
}
}
}
/**
* Implements hook_theme_suggestions_HOOK() for container templates.
*
* Add suggestions, as by default none are provided.
*/
function twigsuggest_theme_suggestions_container(array $variables) {
$suggestions = [];
$element = $variables['element'];
// We cannot count on template_preprocess_container having run, so we copy
// its logic here to provide templates for forms (has parents) or not forms.
// Special handling for form elements.
if (isset($element['#array_parents'])) {
$suggestions[] = 'container__has_parent';
}
else {
$suggestions[] = 'container__no_parent';
}
if (isset($element['#type']) && $element['#type'] != 'container') {
$suggestions[] = 'container__' . $element['#type'];
}
if (isset($element['#type']) && $element['#type'] == 'container' && isset($element['children']['#type'])) {
$suggestions[] = 'container__' . $element['children']['#type'];
}
if (isset($element['#type']) && $element['#type'] == 'view') {
$suggestions[] = 'container__view__' . $element['#name'];
$suggestions[] = 'container__view__' . $element['#name'] . '__' . $element['#display_id'];
}
elseif (isset($element['widget'][0]['#type']) && $element['widget'][0]['#type'] === 'managed_file') {
$suggestions[] = 'container__file';
$suggestions[] = 'container__file__' . $element['widget']['#field_name'];
}
// Additional module-specific container templates.
if (isset($element['#group'])) {
$suggestions[] = 'container__' . str_replace('-', '_', $element['#group']);
}
if (isset($element['#webform_key'])) {
$suggestions[] = 'container__' . str_replace('-', '_', $element['#webform_key']);
}
return $suggestions;
}
/**
* Implements hook_theme_suggestions_HOOK() for form element templates.
*
* Add suggestions, as by default none are provided.
*/
function twigsuggest_theme_suggestions_form_element(array $variables) {
$suggestions = [];
$element = $variables['element'];
if (isset($element['#id'])) {
$suggestions[] = 'form_element__' . str_replace('-', '_', $element['#id']);
}
if (isset($element['#type'])) {
$suggestions[] = 'form_element__' . $element['#type'];
}
// Additional module-specific container templates.
if (isset($element['#webform_id'])) {
$suggestions[] = 'form_element__webform__' . str_replace('-', '_', $element['#webform_id']);
}
return $suggestions;
}
/**
* Implements hook_theme_suggestions_HOOK() for form input element templates.
*/
function twigsuggest_theme_suggestions_input(array $variables) {
$suggestions = [];
$element = $variables['element'];
if (isset($element['#id'])) {
$suggestions[] = 'input__' . $element['#id'];
}
return $suggestions;
}
/**
* Implements hook_theme_suggestions_HOOK() for user templates.
*
* Add template suggestions based on highest user role following the same
* pattern as for nodes. @see https://www.drupal.org/node/2354645
*
* user--[role|uid]--[viewmode].html.twig
*/
function twigsuggest_theme_suggestions_user(array $variables) {
$suggestions = [];
$view_mode = $variables['elements']['#view_mode'];
/** @var \Drupal\user\Entity\User $user */
$user = $variables['elements']['#user'];
$roles = $user
->getRoles();
$highest_role = end($roles);
$uid = $user
->id();
$suggestions[] = 'user__' . $uid;
$suggestions[] = 'user__' . $view_mode;
$suggestions[] = 'user__' . $highest_role;
$suggestions[] = 'user__' . $uid . '__' . $view_mode;
$suggestions[] = 'user__' . $highest_role . '__' . $view_mode;
return $suggestions;
}
/**
* Implements hook_theme_suggestions_HOOK() for the html template.
*
* Add additional template suggestion based on node type.
*/
function twigsuggest_theme_suggestions_html(array $variables) {
$suggestions = [];
/** @var \Drupal\node\Entity\Node $node */
if ($node = \Drupal::service('twigsuggest.helper_functions')
->getCurrentNode()) {
$suggestions[] = 'html__node__' . $node
->getType();
}
return $suggestions;
}
/**
* Implements hook_theme_suggestions_HOOK() for page templates.
*
* Add additional template suggestion based on node type.
*/
function twigsuggest_theme_suggestions_page(array $variables) {
$suggestions = [];
/** @var \Drupal\node\Entity\Node $node */
if ($node = \Drupal::service('twigsuggest.helper_functions')
->getCurrentNode()) {
$suggestions[] = 'page__node__' . $node
->getType();
}
return $suggestions;
}
/**
* Implements hook_theme_suggestions_HOOK() for field templates.
*/
function twigsuggest_theme_suggestions_field(array $variables) {
$suggestions = [];
$element = $variables['element'];
$field_name = $element['#field_name'];
$view_mode = $element['#view_mode'];
$entity_type = $element['#entity_type'];
$bundle = $element['#bundle'];
$suggestions[] = 'field__' . $field_name . '__' . $view_mode;
$suggestions[] = 'field__' . $entity_type . '__' . $field_name . '__' . $view_mode;
$suggestions[] = 'field__' . $entity_type . '__' . $bundle . '__' . $field_name . '__' . $view_mode;
return $suggestions;
}
/**
* Implements hook_theme_suggestions_HOOK_alter() for field templates.
*
* Add entity reference target type template suggestion.
*
* @see https://git.drupalcode.org/project/adaptivetheme/-/blob/8.x-3.x/at_core/includes/suggestions.inc
*/
function twigsuggest_theme_suggestions_field_alter(array &$suggestions, array $variables) {
// Add the entity reference type as a field template suggestion.
if (isset($variables['element']['#items']) && is_object($variables['element']['#items'])) {
$target_type = $variables['element']['#items']
->getSetting('target_type') ?: NULL;
if ($target_type !== NULL) {
array_splice($suggestions, 1, 0, 'field__entity_reference_type__' . $target_type);
}
}
}
/**
* Implements hook_theme_suggestions_HOOK() for taxonomy terms.
*
* Currently Drupal core's taxonomy term module only provides:
* * $suggestions[] = 'taxonomy_term__' . $term->bundle();
* * $suggestions[] = 'taxonomy_term__' . $term->id() . $term->bundle();
*
* This is a very basic template suggestion that should be in core:
* https://www.drupal.org/project/drupal/issues/2767243
*/
function twigsuggest_theme_suggestions_taxonomy_term(array $variables) {
$term = $variables['elements']['#taxonomy_term'];
// We allow dots in view modes?! But keeping this from discarded core patch.
$sanitized_view_mode = strtr($variables['elements']['#view_mode'], '.', '_');
$suggestions[] = 'taxonomy_term__' . $term
->bundle() . '__' . $sanitized_view_mode;
$suggestions[] = 'taxonomy_term__' . $sanitized_view_mode;
$suggestions[] = 'taxonomy_term__' . $term
->id() . '__' . $term
->bundle() . '__' . $sanitized_view_mode;
$suggestions[] = 'taxonomy_term__' . $term
->id() . '__' . $sanitized_view_mode;
return $suggestions;
}
/**
* Implements hook_theme_suggestions_HOOK_alter() for block templates.
*
* Remove duplicate template suggestions for blocks.
*/
function twigsuggest_theme_suggestions_block_alter(array &$suggestions, array $variables) {
$suggestions = array_unique($suggestions);
}
/**
* Implements hook_preprocess() for all templates.
*
* It's a variable themers should be able to rely on. Now from any template we
* can do things like <img src="{{ base_path ~ directory }}/images/icon.svg" />
*/
function twigsuggest_preprocess(&$variables, $hook) {
$variables['base_path'] = base_path();
}