twig.engine

Same filename in other branches
  1. 8.9.x core/themes/engines/twig/twig.engine
  2. 10 core/themes/engines/twig/twig.engine
  3. 11.x core/themes/engines/twig/twig.engine

Handles integration of Twig templates with the Drupal theme system.

File

core/themes/engines/twig/twig.engine

View source
<?php


/**
 * @file
 * Handles integration of Twig templates with the Drupal theme system.
 */
use Drupal\Component\Utility\Html;
use Drupal\Core\Render\Markup;
use Drupal\Core\Extension\Extension;
use Twig\Error\RuntimeError;

/**
 * Implements hook_theme().
 */
function twig_theme($existing, $type, $theme, $path) {
    $templates = drupal_find_theme_functions($existing, [
        $theme,
    ]);
    $templates += drupal_find_theme_templates($existing, '.html.twig', $path);
    return $templates;
}

/**
 * Implements hook_extension().
 */
function twig_extension() {
    return '.html.twig';
}

/**
 * Implements hook_render_template().
 *
 * Renders a Twig template.
 *
 * If the Twig debug setting is enabled, HTML comments including the theme hook
 * and template file name suggestions will surround the template markup.
 *
 * @param string $template_file
 *   The file name of the template to render.
 * @param array $variables
 *   A keyed array of variables that will appear in the output.
 *
 * @return string|\Drupal\Component\Render\MarkupInterface
 *   The output generated by the template, plus any debug information.
 */
function twig_render_template($template_file, array $variables) {
    
    /** @var \Twig\Environment $twig_service */
    $twig_service = \Drupal::service('twig');
    $output = [
        'debug_prefix' => '',
        'debug_info' => '',
        'rendered_markup' => '',
        'debug_suffix' => '',
    ];
    try {
        $output['rendered_markup'] = $twig_service->loadTemplate($template_file)
            ->render($variables);
    } catch (RuntimeError $e) {
        // In case there is a previous exception, re-throw the previous exception,
        // so that the original exception is shown, rather than
        // \Twig\Template::displayWithErrorHandling()'s exception.
        $previous_exception = $e->getPrevious();
        if ($previous_exception) {
            throw $previous_exception;
        }
        throw $e;
    }
    if ($twig_service->isDebug()) {
        $output['debug_prefix'] .= "\n\n<!-- THEME DEBUG -->";
        $output['debug_prefix'] .= "\n<!-- THEME HOOK: '" . Html::escape($variables['theme_hook_original']) . "' -->";
        // If there are theme suggestions, reverse the array so more specific
        // suggestions are shown first.
        if (!empty($variables['theme_hook_suggestions'])) {
            $variables['theme_hook_suggestions'] = array_reverse($variables['theme_hook_suggestions']);
        }
        // Add debug output for directly called suggestions like
        // '#theme' => 'comment__node__article'.
        if (strpos($variables['theme_hook_original'], '__') !== FALSE) {
            $derived_suggestions[] = $hook = $variables['theme_hook_original'];
            while ($pos = strrpos($hook, '__')) {
                $hook = substr($hook, 0, $pos);
                $derived_suggestions[] = $hook;
            }
            // Get the value of the base hook (last derived suggestion) and append it
            // to the end of all theme suggestions.
            $base_hook = array_pop($derived_suggestions);
            $variables['theme_hook_suggestions'] = array_merge($derived_suggestions, $variables['theme_hook_suggestions']);
            $variables['theme_hook_suggestions'][] = $base_hook;
        }
        if (!empty($variables['theme_hook_suggestions'])) {
            $extension = twig_extension();
            $current_template = basename($template_file);
            $suggestions = $variables['theme_hook_suggestions'];
            // Only add the original theme hook if it wasn't a directly called
            // suggestion.
            if (strpos($variables['theme_hook_original'], '__') === FALSE) {
                $suggestions[] = $variables['theme_hook_original'];
            }
            foreach ($suggestions as &$suggestion) {
                $template = strtr($suggestion, '_', '-') . $extension;
                $prefix = $template == $current_template ? 'x' : '*';
                $suggestion = $prefix . ' ' . $template;
            }
            $output['debug_info'] .= "\n<!-- FILE NAME SUGGESTIONS:\n   " . Html::escape(implode("\n   ", $suggestions)) . "\n-->";
        }
        $output['debug_info'] .= "\n<!-- BEGIN OUTPUT from '" . Html::escape($template_file) . "' -->\n";
        $output['debug_suffix'] .= "\n<!-- END OUTPUT from '" . Html::escape($template_file) . "' -->\n\n";
    }
    // This output has already been rendered and is therefore considered safe.
    return Markup::create(implode('', $output));
}

Functions

Title Deprecated Summary
twig_extension Implements hook_extension().
twig_render_template Implements hook_render_template().
twig_theme Implements hook_theme().

Buggy or inaccurate documentation? Please file an issue. Need support? Need help programming? Connect with the Drupal community.