Last updated October 28, 2013. Created by jwilson3 on June 21, 2013.
Edited by skt, jenlampton. Log in to edit this page.

This document was used during much of the Twig conversion process for Drupal 8 and could be useful to you too for updating your own themes and modules to use the Twig templating engine in Drupal 8.

Note: All Twig work is now being done in the Drupal core issue queue. Only use the Twig conversion sandbox to find previously converted templates and functions.

Steps for Core contributors:

  • Find core issues to post and review patches.
  • Do not apply patches to the sandbox
  • Do not create patches for the sandbox.
  • Only use the sandbox to test and/or retrieve previously converted code.
  • First: Watch this YouTube video for an overview of this process.


First, Clone Drupal 8.x:

git clone -b 8.x d8

The current working version of Drupal will be installed in the folder ‘d8’ (name it whatever you like)

  1. Install Drupal as normal (using the Standard install profile).
  2. Uncomment all 3 Twig settings (debugging, cache, auto_reload) in settings.php.


Theme functions

Convert a theme function to a template file & preprocess function:

  1. Identify the file your theme function came from ( a core/modules/color/?)
  2. Create a X.html.twig template file for your theme function:
    • Name your new file appropriately
    • Remove theme_ from the start of your function and end the file name in .html.twig
    • Convert underscores (“_”) to hyphens (“-”).
    • Examples:
      • theme_link() becomes link.html.twig
      • theme_user_signature() becomes user-signature.html.twig
  3. Place your new Twig template in the templates folder in the stark theme (in the sandbox):
    • for functions that came from specific module, stark/templates/comment, etc
    • for functions that came from, stark/templates/
    • for functions that came from, stark/templates/
  4. Go to the Drupal 8 API documentation and search for your function.
  5. Add a PHP-style docblock at the top of the file, and wrap it in Twig comments {# #}
    • Add an @file line at the very top.
    • Copy the definition of the function just below the @file line. Rewrite “Returns HTML ...” as “Default theme implementation ...”. Rewrite it to fit on one line.
    • Add an “Available variables:” line (replace the @param variables)
    • Copy the variables specified under ‘Parameters’ in docs on
    • Remove the @see template_preprocess() line, if it exists.
    • Add an @see template_preprocess_THEME_HOOK() line.
    • Add an @ingroup themeable line (see docblock example below).
  6. Copy the source code for your function below the doc block (see example below)
  7. Change the PHP code into mostly HTML and print statements
    1. Remove PHP code from around the HTML, examples:
      • function whatever() {
      • // …
      • return $output; }
    2. Remove PHP print statements and replace with {{ }}
      • Convert $variables into simple names:
        $variables['title'] becomes {{ title }}
      • Replace array syntax with dot syntax:
        $variables['page']['tabs'] becomes {{ page.tabs }}
    3. Remove PHP logic and replace with {% %} twig syntax.
      <?php foreach $items as $item ?> becomes
      {% for item in items%}
    4. Replace PHP comments with twig syntax comments: {# #}
    5. Replace t() functions around literals with the t filter:
      {{ 'text in quotes'|t }}
    6. Move all PHP logic for variables to a preprocess function. (for instructions on preprocessing, see below.)
  8. If, as you do this, you notice things you want to improve, like consolidating seemingly redundant templates into a single one, or improving the markup or variable names, make a note of that in this spreadsheet or create an issue on our sandbox. For example:

Convert or consolidate to preprocess functions

  1. Preprocess functions will replace all theme functions.
  2. If your template file has PHP logic in it that affects the variables that are being printed, that code will need to be moved to a preprocess function.
  3. If your template began as a theme function, the theme function will need to be converted to a preprocess function.
  4. In the case that some theme functions already have related preprocess functions, the variable handling code in those theme functions needs to be moved into preprocess.
  5. Do not add a line to your hook_theme implementation telling Drupal to use a template file instead of a theme function.
  1. Rename theme_YOURFUNCTION to template_preprocess_YOURFUNCTION.
  2. Pass the $variables by reference by adding an ampersand.  i.e. theme_select($variables) becomes template_preprocess_select(&$variables).
  3. Edit the function to handle only the variable processing logic; Remove any markup (i.e. $output).

If there are missing functions in your twig templates...

If you need access to a filter or function in your Twig template that is not working yet, please add it to this open issue. Keep in mind that most PHP or Drupal functions should be moved to preprocess functions instead. Only if you think a theme dev will need access to this function should it remain in the template.


PHP code from!includes!

function theme_link($variables) {
'<a href="' . check_plain(url($variables['path'], $variables['options'])) . '"' . drupal_attributes($variables['options']['attributes']) . '>' . ($variables['options']['html'] ? $variables['text'] : check_plain($variables['text'])) . '</a>';

Twig template (file name: link.html.twig)

* @file
* Default theme implementation to display a link.
* Available variables:
* - text: The link text for the anchor tag.
* - url: The complete URL being linked to, such as
*   "/node/34" or "".
* - attributes: Remaining HTML attributes for the containing element.
* @see template_preprocess_link()
* @ingroup themeable
<a href="{{ url }}" class="{{ attributes.class }}"{{ attributes }}>{{ text }}</a>

Changes to system.module (preprocess function)

* Prepares variables for link templates.
* Default template: link.html.twig.
* @param array $variables
*   An associative array containing:
*     - text: The translated link text for the anchor tag.
*     - path: The internal path or external URL being linked to.
*     - options: An associative array of additional options.
function template_preprocess_link(&$variables) {
  $variables['url'] = url($variables['path'], $variables['options']);


Andriy Podanenko: How should variables be renamed
jen: Add your own opening and closing Twig comment markers {# and #}.
jen: Follow the twig comment markers with the standard doxygen PHP docblock markers.
jen: Copy and Paste this definition from
James Wilson: If copying the definition from a *function* should rewrite "Returns HTML ..." as "Default theme implementation"
jen: Copy and paste the "Parameters" from
James Wilson: Remove dollar sign from variable names, if you need to refer to another variable from within the doc block use single quotes around the variable. [See policy discussion here]
jen: You "print" variables in twig with the {{ }} syntax
jen: Attributes are "drillable" so that you can reference classes like this
jen: Most functions, like url(), should be removed from the template file and added into a preprocess instead.

Looking for support? Visit the forums, or join #drupal-support in IRC.