I have a drop down in my article content type which lets the user select which teaser template to use for that article.

I'm trying to change the template in themename_preprocess_node(), since this is where I know what template is assigned to that specific article.

My problem is that I am struggling to specify which twig template to render.

How can I achieve what I am trying to do?


You can't change the template in preprocess, there's a separate hook for that, hook_theme_suggestions_template()

This is what node is doing for the node template:

 * Implements hook_theme_suggestions_HOOK().
function node_theme_suggestions_node(array $variables) {
  $suggestions = array();
  $node = $variables['elements']['#node'];
  $sanitized_view_mode = strtr($variables['elements']['#view_mode'], '.', '_');

  $suggestions[] = 'node__' . $sanitized_view_mode;
  $suggestions[] = 'node__' . $node->bundle();
  $suggestions[] = 'node__' . $node->bundle() . '__' . $sanitized_view_mode;
  $suggestions[] = 'node__' . $node->id();
  $suggestions[] = 'node__' . $node->id() . '__' . $sanitized_view_mode;

  return $suggestions;

You can provide something similar. Note that when you do this in a template, you have to use the alter hook, like this example from the bartik theme:

 * Implements hook_theme_suggestions_HOOK_alter() for form templates.
function bartik_theme_suggestions_form_alter(array &$suggestions, array $variables) {
  if ($variables['element']['#form_id'] == 'search_block_form') {
    $suggestions[] = 'form__search_block_form';
  • Thanks @Berdir, this has definitely pushed me in the correct direction - I will mark your answer as correct - and also post my solution below. – Janey Feb 16 '16 at 13:18

This is how I ended up adding a theme suggestion based on a field (field_teaser_template) from the article.

   * Implements hook_theme_suggestions_HOOK_alter() for node templates.
  function themename_theme_suggestions_node_alter(array &$suggestions, array $vars) {
    $node = $vars['elements']['#node'];

    if ($node->hasField('field_teaser_template') && $node->field_teaser_template->value) {
      $template_name = $node->field_teaser_template->value;
      $suggestions[] = 'node__teaser__' . $template_name;
    return $suggestions;
  • Note that $node->field_teaser_template->value will fail if a node doesn't have that field. Remove the isset(), that doesn't really help, instead check with hasField: $node->hasField('field_teaser_template') && $node->field_teaser_template->value. Also, you might want to enforce a certain prefix for you templates, like 'node__teaser__' . $template_name. I guess your field is a list field, but still, someone might end up adding user or something completely else in there and it would use a completely unrelated template... – Berdir Feb 16 '16 at 14:14
  • Thank you for your improvements - much appreciated. I will amend my post above to include your suggestions, in case someone else finds it helpful. – Janey Feb 16 '16 at 14:24

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.