From time to time, I have the need to take a Twig template and a set of variables, render the template, replacing all the variables within, and then get the output as a string. For example, if I want to have a really simple email template in a custom module which has a variable for first_name
, so I can customize the email before sending it via Drupal or PHP, I could do the following in Drupal 7:
<?php
$body = theme_render_template(drupal_get_path('module', 'my_module') . '/templates/email-body.tpl.php', array(
'first_name' => 'Jane',
));
send_email($from, $to, $subject, $body);
?>
In Drupal 8, there is no theme_render_template()
function, since the template engine was switched to Twig in this issue. And until today, there was no change record indicating the fact that the handy theme_render_template()
had been replaced by a new, equally-handy twig_render_template()
function! Thanks to some help from Tim Plunkett, I was able to find this new function, and after he pushed me to do it, I created a new change record to help future-me next time I go looking for theme_render_template()
in Drupal 8: theme_render_template changed to twig_render_template.
In Drupal 8, it's extremely similar to Drupal 7, although there are two additions I made to make it functionally equivalent:
<?php
$markup = twig_render_template(drupal_get_path('module', 'my_module') . '/templates/email-body.html.twig', array(
'my-variable' => 'value',
// Needed to prevent notices when Twig debugging is enabled.
'theme_hook_original' => 'not-applicable',
));
// Cast to string since twig_render_template returns a Markup object.
$body = (string) $markup;
send_email($from, $to, $subject, $body);
?>
If you are rendering a template outside of a normal page request (e.g. in a cron job, queue worker, Drush command, etc.) the Twig theme engine might not be loaded. If that's the case, you'll need to manually load the Twig engine using:
<?php
// Load the Twig theme engine so we can use twig_render_template().
include_once \Drupal::root() . '/core/themes/engines/twig/twig.engine';
?>
I shall go forth templating ALL THE THINGS now!
Comments
What's do you thing about using renderer service?
Using the service requires a render array and/or a bunch of other scaffolding that I do not want to have to set up to just take a template, take some variables, and run the template through the template engine.
Note that if you're considering doing something like this for anything that would render on a Drupal page, then just don't. The technique outlined in this blog post should only be used if you're doing something like what I'm doing—I'm generating a configuration payload from some variables from Drupal nodes and then passing that along to an external service.
Agree. Thanks for the good article!
Hi Jeff -- thanks for all the great content (has been very helpful on different projects!)
I have a content type that has about twenty percent Fords and eighty percent Chevys. If it's a Ford, then I want the system to automatically create a twig template which will allow me to put a small blue label at the top of the page, 'FORD Content.' If it's a Chevy, Chrysler or any other content, no template is necessary. The choice of Ford, Chevy, etc. is made by the content author from a dropdown field in the /node/add/automobile page.
Can I use this mechanism to achieve that? Or should I use something else? This content will be rendered on a Drupal page, and you said in the post that in that case, we just shouldn't?
It would probably be better to use something like views or a custom block instead of this technique, because that way the rendering would not be as complicated/custom.
You could have a block that appears on the page and has certain content for certain values of a field on the node.