Write Up: Twig theme sprint @ Twin Cities Drupal Camp

We encourage users to post events happening in the community to the community events group on https://www.drupal.org.
You are viewing a wiki page. You are welcome to join the group and then edit it. Be bold!

On May 20 chx, crell, c4rl, mlncn, stevector, Jerdavis, quicksketch, and jenlampton sprinted on creating a new theme layer for Drupal 8, using Twig, along with help from various members of The Nerdery, Tom Cox, and other Twin Cities Drupal Camp attendees.

The goal for this sprint was to rebuild comment.tpl.php and everything rendered through it, using Twig. This action would involve replacing theme functions (such as theme_username) as well as template files (such as comment.tpl.php) and also force us to reconsider if each template file truly deserved to be a template of it's own (comment-wrapper.tpl.php) or if some should be replaced with a generic wrapper.tpl.php that could be used almost everywhere.

The long term goals for the Drupal 8 theme layer is to reduce confusion with template files, and create something more along the lines of Jacine's components in core.

But before we decided to do anything too drastic, C4rl, mlncn, stevector and I decided to have a "quick meeting" to discuss Twig template inheritance, to think about how the new Blocks Everywhere initiative tied into what we were working on, and to figure out our new template file naming conventions.

Twig template inheritance

The fist downside we noticed to using Twig inheritance with Drupal, is an obvious conflict of the "block" namespace. Drupal uses the word "block" to mean 'something that you put onto a page' but in Twig, a "block" is more like a "region" in Drupal. It's a part of the page that can have stuff added into it, or more accurately, a part of the HTML that may be overridden by a "child template".

The "child templates" in Twig contain only the overrides for the parent template. This is very efficient, since with Twig you would not get yourself into the problem of having eight nearly identical copies of any template, but the model of child templates only containing the HTML that is different is drastically different than the approach we are taking now, and will be difficult for our current theme developers to adjust to.

But page templates may not be our responsibility any more, since page layouts will be managed by the Blocks Everywhere initiative, and may end up being "Plugins" for that system.* THIS HAS NOT YET BEEN DECIDED

So for now, let's look at a smaller piece of the puzzle. Here is a sample wrapper template we came up with, wrapper.twig:

<div class="{{ attributes.class }}" {{ attributes }}>

  {{ title.prefix }}
    {% if title %}
      <{{ title.element }} {{ title.attributes }}>{{ title }}</{{ title.element }}>
    {% endif %}
  {{ title.suffix }}

  {{ contents }}

</div>

This template could be used for many things, a block is the obvious example, but could also be used for a region, a node, a comment, and maybe even a field or a form element. Almost everything in Drupal follows this basic pattern, a containing element around a title and content. Okay, so where does the inheritance come in? Where in a Drupal block, would you place a Twig block? The child template model doesn't really work for Drupal's "blocks", or smaller pieces of HTML.

The Blocks Everywhere initiative

Speaking of blocks, things get a little more complicated when we take the Blocks Everywhere initiative (code name Scotch) into consideration. Everything in Drupal 8 is going to become a block: nodes themselves, fields on nodes, comments, fields on comments, everything.

In Drupal 7, there were regions that were specified by your theme (in yellow, below) and blocks could be placed into those regions (in red, below).

In Drupal 8, The blocks Everywhere initiative will be responsible for the layout of your pages, as well as the placement of content within. Smaller blocks (in red, below) can be placed into larger blocks (in orange, below), and any type of block can be placed into the layout of your page (in green, below).

So how does this change things at the theme level? If everything is a block, should everything be run through the block template file? How do we want to differentiate between different kinds of blocks at the template level?

One option is to use Twig inheritance, and let every module that needs to add something additional override the HTML that is output for the contents part of the Twig file above. But Drupal already has a solution to that problem, modules can simply add their output into a renderable (as D7 would call it) or a TemplateData Object (as D8 will call it) and the appropriate output will appear as part of contents.

We decided that from what we knew of Twig template inheritance, it wasn't a better approach than what Drupal already does. But, we also all agreed that we aren't Twig experts, and that we wanted to see more, from someone who really understands Twig, before we gave up on it completely.

New template file naming conventions

And speaking of template files, we're going to need some new naming conventions. if everything is going to be a block, can we just drop 'block' from the file names altogether, and assume that if no specific template is requested, we always default back to using the wrapper? And how do we want to differentiate between a field on a node and a field on a comment, or do we?

PHPTemplate to Twig

We also struggled with which files to keep and which files to loose. If everything is a block, we could, in theory, ship Drupal core with only one template file! However, that would make overriding that file very complicated, there would be too many naming conventions, and learning how to use it woud be nearly impossible. So, we need to reach a reasonable compromise. We decided to keep the templates everyone loves to override (like node.tpl.php) and eliminate the ones everyone loves to hate (comment-wrapper.tpl.php).

Here's a first pass at a potential mapping of PHPTemplate files to Twig files, this is in no way final, these were just our first, second, and maybe third ideas.

PHPTemplate Twig template Status
page.tpl.php - layouts provided by Sctotch
region.tpl.php - eliminated in favor of wrapper.twig
block.tpl.php block.twig same as wrapper.twig, but uses 'aside' HTML5 tag
node.tpl.php node.twig same as wrapper.twig, but uses 'article' HTML5 tag
comment.tpl.php comment.twig same as node.twig, here for ease of learning?
comment-wrapper.tpl.php - eliminated in favor of wrapper.twig
field.tpl.php - eliminated in favor of item_list.twig
forums.tpl.php - eliminated in favor of wrapper.twig
search-results.tpl.php - eliminated in favor of wrapper.twig, and item_list.twig
search-result.tpl.php - eliminated in favor of wrapper.twig

On a more technical note

At the end of the Theme Sprint in April at the Chapter Three offices, chx had discovered that the __toString method could not be used for two major reasons. One, __toString has very special rules about exceptions thrown: PHP immediately fatals with an unhelpful error and you have no idea where and what happened. Calling Twig's template rendering might throw exceptions -- for example for template syntax errors -- and so it would be extremely developer unfriendly to call Twig from __toString. Two, one can't pass parameters to __toString.

While the rest of us were debating about Twig inheritance and template files in the Bat Cave, chx was solving this problem by creating Drupal's own version of __toString, currently called render() that can both catch exceptions and accept parameters to produce different output.

Summary

We may have ended up with more questions after this sprint than answers, but chx did solve a big problem by creating a function that will flatten a TemplateData Object into a string cleanly.

Beyond that, we also established a few new questions that need to be answered:

  1. Can we use Twig template inheritance, or is what Drupal does already, better?
  2. How many template files could/should be removed?
  3. How do we want to name the new template files, and their overrides?

Next Steps

We ended the sprint by deciding to first re-write the existing comment rendering system in Twig, before we start throwing away the template files we will eventually get rid of. This will help us prove that we can do the theme layer in Twig, before we get blocked by too many decisions about what we should be doing to simplify things.

AttachmentSize
d8-blocks.png218 KB
d7-blocks.png182.86 KB

Comments

Thanks for the write ups Jen,

Jeff Burnz's picture

Thanks for the write ups Jen, really great to get up to speed with where this is heading, nice work.

Regarding templates - nodes, comments, users and terms are entities, so why not remove these bundle specific special cases and use a generic entity.twig template. If blocks become entities, there goes another one. Is that something we could do, anything to remove templates I think is a win, although as you say we need easy ways to differentiate at the bundle/block type level should we need to.

Eliminate redundant template files.

jessebeach's picture

I totally support ridding core of redundant template files. They only encourage CSS bloat and redundant micro-variations on what should be common, repeated structures. With fewer templates, we can leverage more abstract CSS definitions for component styling e.g. Nicole Sullivan's media object.

I realize many people spent significant time updating the existing core templates to HTML5, but we can't let that sunk effort cost keep us from further improvements from the theme system.

This is really exciting! Thank you everyone for putting thought and time into this effort.

Performance!!!

ardas's picture

Guys,

Do you realize that using any template engine other than PHPTemplate will make rendering slower because there will be more processing for that engine to turn it into a PHP/HTML template...

PHPTemplate is the lowest level engine possible and this is great!

Another disadvantage of any other engine is a need to study its syntax... the syntax of PHPTemplate is PHP which is better.


Regards,
Dmitry Kresin, ARDAS group - Drupal CMS web sites development, Software outsourcing

I'm with Dmitry here. I'm

betarobot's picture

I'm with Dmitry here. I'm really not sure why there should be another (and probably slower) template engine.

At the other hand why not to have both engines, so themer could chose what he wants.

as far as speed goes

jenlampton's picture

Actually using Twig as a template file should speed up the rendering of pages

Druapal 7 basically renders everything twice. The first time, it renders all the little stuff, and shoves it into the $page array. Then it carries that $page array around with it, adding a node here, a field there, blocks into here, comments down there, building it all up, inside-to-out. Then, after everything is ready, it renders the whole $page array down, outside-to-in, still allowing overrides, theme functions, and preprocessors to interrupt the process and change stuff before the final markup makes it to the page.

Twig would render things outside-to-in only. It doesn't need to assemble anything beforehand. It won't create a string for "username" until a template requires the printing of that username. Much like tokens, the variables only come into existence after the twig template file requests them.

That does sound proficient.

alexrayu's picture

That does sound proficient. Has there been a proposal to introduct it into D8 core yet?

as proposed here

podarok's picture

as proposed here http://dgo.to/1499460
there is a sandbox code from http://dgo.to/@chx here http://drupal.org/sandbox/chx/1541306


Andriy Podanenko
web: http://druler.com

There have initially been a

alexrayu's picture

There have initially been a few engines for Drupal. And they dropped out. For many reasons.
1. Because two are harder to maintain than one.
2. Because frameworks engines are slower.
3. Because using different engines adds to complication level.
4. And because from user side, when a user downloads a theme he likes and finds that it is written on some framework, we must either to ditch the theme or is forced to install a framework. Or has to port it to native.

Twig templates have many advantages

jessebeach's picture

Twig templates have a lot of advantages over PHP templates.

  1. We reduce the risk of security exploits being introduced by themers. Templates should not contain anything but display logic, but the temptation with PHP is to inject data manipulation logic.
  2. The Twig template syntax is very similar to other templating engines outside of Drupal, both client and server side. I think we'll be increasing access to new Drupal themers with this switch.
  3. Twig syntax works equally well on the server and the client. Check out this discussion for details: http://groups.drupal.org/node/232593

I can't speak to performance, but I believe the Twig templates are pre-compiled, like aggregated CSS and JS, so they're not referenced by source during requests.

I can speak to performance

JohnAlbin's picture

PHPTemplate is not the performance panacea you would think. Just look at field.tpl.php, or rather look at the theme_field() function. Drupal core doesn't implement the "field" theme hook as a template file because it is TOO SLOW. The theme_field() function is much faster.

The reason for this is best explained by Alex Bronstein who explained it to me. Fortunately, there's a mini-thread about Twig performance vs. PHPTemplate performance in a previous post. See http://groups.drupal.org/node/234793#comment-763478 and the follow-up comments.

Bottom line: twig's templates compiled into PHP classes are faster than PHPTemplate's tpl files.

  - John (JohnAlbin)

If Twig is faster than why

alexrayu's picture

If Twig is faster than why not. Having both systems and then seeing how it goes.