Part of meta-issue #1788918: [GTD] [META] Prepare for Twig main engine core inclusion until December 1

At the A designer-friendly theme system in Drupal 8? session in Munich, it seemed like the presenters were not sure whether D8/Twig could support preprocess functions as we use them today to alter variables before they are sent to the tpl file. I personally use them a lot in themes. Core does too.

Core themes examples:

// garland theme
function garland_preprocess_comment(&$vars) {
  $vars['submitted'] = $vars['created'] . ' — ' . $vars['author'];
}

// bartik theme
function bartik_preprocess_node(&$variables) {
  if ($variables['view_mode'] == 'full' && node_is_page($variables['node'])) {
    $variables['classes_array'][] = 'node-full';
  }
}

Core modules examples:

// toolbar.module
function toolbar_preprocess_html(&$vars) {
  if (isset($vars['page']['page_top']['toolbar']) && user_access('access toolbar')) {
    $vars['classes_array'][] = 'toolbar';
    if (!_toolbar_is_collapsed()) {
      $vars['classes_array'][] = 'toolbar-drawer';
    }
  }
}

// overlay.module
function overlay_preprocess_html(&$variables) {
  if (overlay_get_mode() == 'child') {
    // Add overlay class, so themes can react to being displayed in the overlay.
    $variables['classes_array'][] = 'overlay';
  }
}

// shortcut.module
function shortcut_preprocess_page(&$variables) {
  // Only display the shortcut link if the user has the ability to edit
  // shortcuts and if the page's actual content is being shown (for example,
  // we do not want to display it on "access denied" or "page not found"
  // pages).
  if (shortcut_set_edit_access() && ($item = menu_get_item()) && $item['access']) {
    $link = $_GET['q'];
    $query_parameters = drupal_get_query_parameters();
    if (!empty($query_parameters)) {
     $link .= '?' . drupal_http_build_query($query_parameters);
    }
    $query = array(
     'link' => $link,
     'name' => drupal_get_title(),
    );
    $query += drupal_get_destination();

    $shortcut_set = shortcut_current_displayed_set();

    // Check if $link is already a shortcut and set $link_mode accordingly.
    foreach ($shortcut_set->links as $shortcut) {
      if ($link == $shortcut['link_path']) {
        $mlid = $shortcut['mlid'];
        break;
      }
    }
    $link_mode = isset($mlid) ? "remove" : "add";

    if ($link_mode == "add") {
      $query['token'] = drupal_get_token('shortcut-add-link');
      $link_text = shortcut_set_switch_access() ? t('Add to %shortcut_set shortcuts', array('%shortcut_set' => $shortcut_set->title)) : t('Add to shortcuts');
      $link_path = 'admin/config/user-interface/shortcut/' . $shortcut_set->set_name . '/add-link-inline';
    }
    else {
      $query['mlid'] = $mlid;
      $link_text = shortcut_set_switch_access() ? t('Remove from %shortcut_set shortcuts', array('%shortcut_set' => $shortcut_set->title)) : t('Remove from shortcuts');
      $link_path = 'admin/config/user-interface/shortcut/link/' . $mlid . '/delete';
    }

    if (theme_get_setting('shortcut_module_link')) {
      $variables['title_suffix']['add_or_remove_shortcut'] = array(
        '#attached' => array('css' => array(drupal_get_path('module', 'shortcut') . '/shortcut.css')),
        '#prefix' => '<div class="add-or-remove-shortcuts ' . $link_mode . '-shortcut">',
        '#type' => 'link',
        '#title' => '<span class="icon"></span><span class="text">' . $link_text . '</span>',
        '#href' => $link_path,
        '#options' => array('query' => $query, 'html' => TRUE),
        '#suffix' => '</div>',
      );
    }
  }
}

Comments

scor’s picture

Title: Check if we still support preprocess functions with Twig » Check if we can still support preprocess functions with Twig
Cameron Tod’s picture

jenlampton’s picture

Title: Check if we can still support preprocess functions with Twig » [meta] What will preprocess functions look like with Twig?
Issue tags: +Twig

The question isn't "can we still have preprocess functions". The question is "what will preprocess functions look like?" Will they be exactly the same? Renamed? Changed to only be called be on-demand?

Preprocess functions solve an order-of-execution problem for us. They allow one module delay the time at which stuff in the theme layer can be tampered with. We will most likely still need something like that. But we aren't sure what - exactly - that will look like. We currently have three phases:
1) creation - this is when variables get created and added for the first time into the "stuff" that the theme layer prints out (hook_theme).
2) modification - this is when stuff created by one module can be altered by another (or by a theme) (preprocess)
and 3) execution, this is when that stuff actually gets printed out.

The question is really if we need to still have three separate phases, or if our 2nd 'preprocess' phase could possibly happen at the same time as our 3rd phase making it more of a mid-process (or maybe just 'process')? and potentially saving some processing, if we can skip that step when it's not needed.

For the short term - it will remain the preprocess you know and love. We'll see how much we can get done before we start trying to tamper with what we know already works! :)

jenlampton’s picture

accidental double post :/

bstoppel’s picture

I don't understand all of the inner working of Drupal and Twig, but aren't theming preprocess functions a relic of the phptemplate engine?

Will the "prepocess" functions that Twig uses be a mix of Filters, Functions, Tags, Globals, etc that can extend Twig? http://twig.sensiolabs.org/doc/advanced.html

jenlampton’s picture

Not yet.

For now we'll be using them to get rid of all the PHP logic used in preparing variables for printing in the templates. The first step is to clean up our template files so that all they'll need to do is actually print the data needed. Preprocess will still be the layer where that data gets prepared.

We will have some filters and functions available in the template files (things like t we won't be able to get away from) but the whole point is to make the template files *just print markup*. All the magic that needs to go into generating that markup - the stuff that we do need a programing language to construct - should remain done in PHP and be moved to a more suitable place in the theme layer.

jenlampton’s picture

Project: Drupal core »
Version: 8.x-dev »
Component: theme system » Twig engine (twig_engine branch)

Stealing this issue for the twig sandbox.

catch’s picture

Project: » Drupal core
Version: » 8.x-dev
Component: Twig engine (twig_engine branch) » theme system
Priority: Normal » Major

Not sure why this was moved to the Twig sandbox, if we're going to implement Twig in core we need to fix these issues in core.

webchick’s picture

It seems to be we've already figured this out, and the answer is "they look the same." Am I wrong?

steveoliver’s picture

Not really. I think the differences are in the form of best practices:

1. Return render arrays instead of calling render() in preprocess; Vars printed in templates are render()ed by Twig.
2. Likewise, defer calls to filters like t() to Twig templates; Try to avoid calling these in preprocess.
3. Minor, and not specific to Twig, but rather the theme cleanup in D8, but preprocess docblocks have a more standardized format.

See Twig coding standards and #1913208: [policy] Standardize template preprocess function documentation.

Did I miss anything?

steveoliver’s picture

Priority: Major » Normal
Status: Active » Needs review
Issue tags: +Needs issue summary update

To fill in the blanks between the original post and comment #10, here are a few other notes about preprocess:

1. There are some workarounds we've done, and optimizations we've yet to do or are in development to allow for 10.1 above. See #1920886: drupal_render() should check if it's rendering a 'render element' and if so call drupal_render_children() (inline) instead.
2. To summarize #10, we basically are taking the 'process' out of preprocess, and being clear about "preparing variables". We're actually working to kill #process. See #1843650: Remove the process layer (hook_process and hook_process_HOOK).

So yeah, things have basically worked themselves out to answer the question(s) here, I believe. So I'll change priority for and status for now and let someone else close or change this in case I'm missing anything. Maybe an issue summary?

star-szr’s picture

Status: Needs review » Fixed
Issue tags: -Needs issue summary update

I think at the very least we've answered the question posed in the OP, tentatively closing. IMO the issue summary here is probably not the best place to document the differences that @steveoliver pointed out.

Fabianx’s picture

Priority: Normal » Major
Status: Fixed » Postponed (maintainer needs more info)

I'd rather see this postponed than fixed:

BECAUSE:

for example we found that template_preprocess puts a certain overhead on this.

With all converted to twig, we can do much more things that have not been possible before.

Example:

Change Attribute() to use a render like array (array('#typecast' => 'Attribute', 'class'= > ...)) instead of an object, which is way faster in terms of performance to lazy create. (see for example: http://www.lionsad.de/xhprof-kit/xhprof/xhprof_html/?symbol=template_pre... for 200 calls, it is 6 ms)

That would be a good candidate for example.

catch’s picture

Status: Postponed (maintainer needs more info) » Postponed

Is it possible to get proof of concepts for this up now prior to 100% conversion? I'm thinking if we had enough conversions in a branch to render a particular page 100% with twig for profiling.

jenlampton’s picture

Status: Postponed » Closed (duplicate)

I think we have an answer to this question over here, so I'm going to close this issue as a duplicate of #1886448: Rewrite the theme registry into a proper service.

jenlampton’s picture

Issue summary: View changes

Updated issue summary.

scor’s picture

Any Twig experts around willing to confirm what the current situation is, and if https://gist.github.com/jenlampton/5654283 is a valid description of the reality. I doubt we can give a definite answer to the OP until Drupal 8 reaches a more stable status beyond beta.

star-szr’s picture

@scor - the current situation is we have 1 and 2 (and I suppose 5) from that gist. Work was done on 3 and 4 but we ended up pushing that to 9.x, and we still have preprocess.