2012-11-03 17:36:10 +00:00
<?php
/**
* @file
* Handles integration of Twig templates with the Drupal theme system.
*/
2015-08-17 07:34:08 +00:00
use Drupal\Component\Utility\Html;
2015-10-01 23:25:03 +00:00
use Drupal\Core\Render\Markup;
2014-03-11 17:19:24 +00:00
use Drupal\Core\Extension\Extension;
2012-11-03 17:36:10 +00:00
/**
* Implements hook_theme().
*/
function twig_theme($existing, $type, $theme, $path) {
2017-03-04 01:20:24 +00:00
$templates = drupal_find_theme_functions($existing, [$theme]);
2013-05-29 07:41:16 +00:00
$templates += drupal_find_theme_templates($existing, '.html.twig', $path);
return $templates;
2012-11-03 17:36:10 +00:00
}
/**
* Implements hook_extension().
*/
function twig_extension() {
2013-01-30 03:11:25 +00:00
return '.html.twig';
2012-11-03 17:36:10 +00:00
}
/**
2015-11-25 22:34:40 +00:00
* Includes .theme file from themes.
*
* @param \Drupal\Core\Extension\Extension $theme
* The theme extension object.
2012-11-03 17:36:10 +00:00
*/
2014-03-11 17:19:24 +00:00
function twig_init(Extension $theme) {
Issue #340723 by ParisLiakos, sun, Berdir, glennpratt, Cottser, swentel, alexpott, tstoeckler, Xano, tim.plunkett, BassistJimmyJam | beejeebus: Make modules and installation profiles only require .info.yml files.
2014-03-17 14:43:29 +00:00
$theme->load();
2012-11-03 17:36:10 +00:00
}
/**
2014-10-04 13:15:51 +00:00
* Implements hook_render_template().
*
2013-02-19 08:59:05 +00:00
* Renders a Twig template.
2012-11-03 17:36:10 +00:00
*
2015-12-10 14:19:31 +00:00
* If the Twig debug setting is enabled, HTML comments including the theme hook
2013-02-19 08:59:05 +00:00
* and template file name suggestions will surround the template markup.
2012-11-03 17:36:10 +00:00
*
2015-02-05 09:24:24 +00:00
* @param string $template_file
2013-02-19 08:59:05 +00:00
* The file name of the template to render.
2015-02-05 09:24:24 +00:00
* @param array $variables
2012-11-03 17:36:10 +00:00
* A keyed array of variables that will appear in the output.
*
2015-10-01 23:25:03 +00:00
* @return string|\Drupal\Component\Render\MarkupInterface
2013-02-19 08:59:05 +00:00
* The output generated by the template, plus any debug information.
2012-11-03 17:36:10 +00:00
*/
2015-02-05 09:24:24 +00:00
function twig_render_template($template_file, array $variables) {
Issue #1825952 by Fabianx, joelpittet, bdragon, heddn, chx, xjm, pwolanin, mikey_p, ti2m, bfr, dags, cilefen, scor, mgifford: Turn on twig autoescape by default
2014-07-18 09:05:22 +00:00
/** @var \Twig_Environment $twig_service */
2014-03-27 05:31:37 +00:00
$twig_service = \Drupal::service('twig');
2015-03-01 13:02:11 +00:00
$output = [
'debug_prefix' => '',
'debug_info' => '',
'rendered_markup' => '',
'debug_suffix' => '',
];
Issue #2226207 by lauriii, mgbellaire, Cottser, m1r1k, Mark Carver, LinL, rachel_norfolk, rteijeiro, skwashd, davidhernandez, euphoric_mv: Make 'template' the default output option for hook_theme().
2014-10-08 11:06:17 +00:00
try {
2015-03-01 13:02:11 +00:00
$output['rendered_markup'] = $twig_service->loadTemplate($template_file)->render($variables);
Issue #2226207 by lauriii, mgbellaire, Cottser, m1r1k, Mark Carver, LinL, rachel_norfolk, rteijeiro, skwashd, davidhernandez, euphoric_mv: Make 'template' the default output option for hook_theme().
2014-10-08 11:06:17 +00:00
}
2015-06-23 16:24:29 +00:00
catch (\Twig_Error_Runtime $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;
}
2014-03-27 05:31:37 +00:00
if ($twig_service->isDebug()) {
2013-02-19 08:59:05 +00:00
$output['debug_prefix'] .= "\n\n<!-- THEME DEBUG -->";
2015-08-17 07:34:08 +00:00
$output['debug_prefix'] .= "\n<!-- THEME HOOK: '" . Html::escape($variables['theme_hook_original']) . "' -->";
2014-03-04 21:04:23 +00:00
// 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;
}
2013-02-19 08:59:05 +00:00
if (!empty($variables['theme_hook_suggestions'])) {
$extension = twig_extension();
$current_template = basename($template_file);
$suggestions = $variables['theme_hook_suggestions'];
2014-03-04 21:04:23 +00:00
// 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'];
}
2013-08-13 21:20:54 +00:00
foreach ($suggestions as &$suggestion) {
2013-02-19 08:59:05 +00:00
$template = strtr($suggestion, '_', '-') . $extension;
$prefix = ($template == $current_template) ? 'x' : '*';
$suggestion = $prefix . ' ' . $template;
}
2015-08-17 07:34:08 +00:00
$output['debug_info'] .= "\n<!-- FILE NAME SUGGESTIONS:\n " . Html::escape(implode("\n ", $suggestions)) . "\n-->";
2013-02-19 08:59:05 +00:00
}
2015-08-17 07:34:08 +00:00
$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";
2013-02-19 08:59:05 +00:00
}
2015-08-13 11:33:54 +00:00
// This output has already been rendered and is therefore considered safe.
2015-10-01 23:25:03 +00:00
return Markup::create(implode('', $output));
2012-11-03 17:36:10 +00:00
}
/**
2014-03-07 18:29:14 +00:00
* Removes child elements from a copy of the original array.
2012-11-03 17:36:10 +00:00
*
2014-03-07 18:29:14 +00:00
* Creates a copy of the renderable array and removes child elements by key
2014-09-18 14:27:00 +00:00
* specified through filter's arguments. The copy can be printed without these
2014-03-07 18:29:14 +00:00
* elements. The original renderable array is still available and can be used
* to print child elements in their entirety in the twig template.
2012-11-03 17:36:10 +00:00
*
2015-02-05 09:24:24 +00:00
* @param array|object $element
2014-03-07 18:29:14 +00:00
* The parent renderable array to exclude the child items.
2017-09-05 13:19:41 +00:00
* @param string[] ...
2014-03-07 18:29:14 +00:00
* The string keys of $element to prevent printing.
*
* @return array
* The filtered renderable array.
2019-01-22 12:46:01 +00:00
*
* @deprecated in Drupal 8.7.x and will be removed before 9.0.0. Use
* \Drupal\Core\Template\TwigExtension::withoutFilter() instead.
2012-11-03 17:36:10 +00:00
*/
2014-03-07 18:29:14 +00:00
function twig_without($element) {
2019-01-22 12:46:01 +00:00
@trigger_error('twig_without() is deprecated in Drupal 8.7.x and will be removed before Drupal 9.0.0. Use \Drupal\Core\Template\TwigExtension::withoutFilter(). See https://www.drupal.org/node/3011154.', E_USER_DEPRECATED);
/** @var \Drupal\Core\Template\TwigExtension $extension */
$extension = \Drupal::service('twig.extension');
return call_user_func_array([$extension, 'withoutFilter'], func_get_args());
2012-11-03 17:36:10 +00:00
}