load(); } /** * 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 (\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; } if ($twig_service->isDebug()) { $output['debug_prefix'] .= "\n\n"; $output['debug_prefix'] .= "\n"; // 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"; } $output['debug_info'] .= "\n\n"; $output['debug_suffix'] .= "\n\n\n"; } // This output has already been rendered and is therefore considered safe. return Markup::create(implode('', $output)); } /** * Removes child elements from a copy of the original array. * * Creates a copy of the renderable array and removes child elements by key * specified through filter's arguments. The copy can be printed without these * elements. The original renderable array is still available and can be used * to print child elements in their entirety in the twig template. * * @param array|object $element * The parent renderable array to exclude the child items. * @param string[] $args, ... * The string keys of $element to prevent printing. * * @return array * The filtered renderable array. */ function twig_without($element) { if ($element instanceof ArrayAccess) { $filtered_element = clone $element; } else { $filtered_element = $element; } $args = func_get_args(); unset($args[0]); foreach ($args as $arg) { if (isset($filtered_element[$arg])) { unset($filtered_element[$arg]); } } return $filtered_element; }