Extra Block Types (EBT) - New Layout Builder experience❗

Extra Block Types (EBT) - styled, customizable block types: Slideshows, Tabs, Cards, Accordions and many others. Built-in settings for background, DOM Box, javascript plugins. Experience the future of layout building today.

Demo EBT modules Download EBT modules

❗Extra Paragraph Types (EPT) - New Paragraphs experience

Extra Paragraph Types (EPT) - analogical paragraph based set of modules.

Demo EPT modules Download EPT modules

Scroll

Best Practices for Twig – Preprocess Functions and Templates

13/04/2025, by Ivan

Menu

To make Drupal 8 theming as performant as possible and provide more flexibility in Twig templates, follow these best practices:

This guide is intended to help Drupal developers with experience in Drupal 7 move away from functions like theme() or drupal_render(), which should no longer be used in Drupal 8+. The “before” examples are generally written in a Drupal 7 style.

Returning Render Arrays from Preprocess Functions

Always return render arrays instead of calling theme() or drupal_render() in preprocess functions.

Twig renders everything automatically, so there is no need to call drupal_render() or theme() within a preprocess function. Instead, pass render arrays to the template to allow more control than already-rendered HTML strings.

Removing theme() from a preprocess function:

// Before - passing a string of rendered HTML to the template.
$variables['table'] = theme('table', ['header' => $header, 'rows' => $rows]);

// After - passing a render array to the template.
$variables['table'] = [
  '#theme' => 'table',
  '#header' => $header,
  '#rows' => $rows,
];

Removing drupal_render() from a preprocess function is simply a matter of removing the call:

// Before, unnecessary call to drupal_render().
$variables['teaser'] = drupal_render($node_teaser);

// After, with drupal_render() removed.
$variables['teaser'] = $node_teaser;
// Before, unnecessary call to drupal_render().
$row[] = drupal_render($display['title']);

// After, with drupal_render() removed.
$row[]['data'] = $display['title'];

Call Filters and Utility Functions in Templates

While render arrays provide a flexible structure for data all the way to the template, not every variable requires a render array. To pass raw data to templates as long as possible, theme developers should call filters like t, and utility functions like url() directly in Twig templates. Doing this can reduce unnecessary function calls and provide more clarity in the template logic.

Before:

In the preprocess function:

$variables['no_content_text'] = t('You have not created any content types yet. Go to the content type creation page to add a new content type.', array('@create-content' => url('admin/structure/types/add')));

In the template:


 

{{ no_content_text }}

After:

In the template:


 

{{ 'You have not created any content types yet. Go to the content type creation page to add a new content type.'|t({'@create-content': url('admin/structure/types/add')}) }}

Show / Hide and Remove drupal_render_children and element_children

If hide() was called in the original template and drupal_render_children was used to render "the rest" of the data, you should split those into separate variables during preprocessing.

Before (PHPTemplate file):


Use the Twig filter without to hide specific elements. Render others as usual where needed.

After (Twig template):


 
{{ form|without('advanced', 'actions') }}
{{ form.advanced }}

Alternate Method (No Longer Required)

Preprocess everything into separate variables and pass them to the template. You may need to strip things out from the full element (in this case, the form) before rendering the rest. Then print everything in place in the template.

Before (preprocess):

function template_preprocess_node_edit_form(&$variables) {
  $form = $variables['form'];
  
  $variables['advanced'] = $form['advanced'];
  $variables['actions'] = $form['actions'];
  unset($form['advanced'], $form['actions']);
  $variables['form'] = drupal_render_children($form);
}

After (Twig template):


 
{{ form }}
{{ advanced }}

Drupal’s online documentation is © 2000-2020 by the individual contributors and can be used in accordance with the Creative Commons License, Attribution-ShareAlike 2.0. PHP code is distributed under the GNU General Public License.