Have you ever stared at your computer screen with a deer-in-headlights expression on your face thinking “I have no idea where to even start with this…”? That was me about a month ago when I was asked to help theme a Drupal 8 project for the very first time. Getting started theming in Drupal 8, still being in a fairly new iteration with a programming style differing from Drupal 7, was both an exciting and daunting task. It was exciting in the sense that I heard good things from those who’ve already started theming in D8, and daunting because there’d been a lot of changes between D7 and D8.
One of the differences between Drupal 7 and 8 is template files; PHPTemplate (.tpl.php) files were replaced with Twig (.html.twig) files. Twig is a robust and elegant template engine for PHP. Once I started working with Twig, I instantly loved it. I found it to be lightweight, fairly quick to pick up, and very readable. Xquartz mac os. Not only that, but I had what felt like ultimate control to the markup, including wrapping elements and rendering exactly the ouput I needed. Often with Drupal 7, wrapping elements in a
<div> requires assistance from a back-end developer.
- This video walks through the basic use of Drupal 7's Render API for outputting content, and gives some hands-on experience in navigating and working with renderable arrays. We expand the Menu Magic module by creating several different kinds of page elements to show how renderable arrays work.
- Most of the familiar functions from Drupal 7, such as t, and drupalrender, are available, and work very similarly to the way that they always have. For example, to build an HTML unordered list with two elements, you could use an itemlist with drupalrender, as shown below.
With this newfound enthusiasm, I set out to write the best twig code ever! In order to find the output I needed, I used the Twig function dump(). This function “dumps” a variable’s information right on the screen. This proved highly useful until I realized I needed to dig deeper into the arrays and objects contained within the variable. There was only so much guess work I could do here before getting epically frustrated, seemingly wasting valuable time looking for an image file’s path.
Drupalrender flags each element with a '#printed' status to indicate that the element has been rendered, which allows individual elements of a given array to be rendered independently and prevents them from being rendered more than once on subsequent calls to drupalrender.
Though there are a handful of debugging methods to choose from, I had the best luck getting what I needed by using PHPStorm to debug Twig files. That’s right, front-end friends, PHPStorm isn’t just for back-end PHP-coding devs. It can be a great tool for front-end programmers as well!
After following the steps listed in Lubomir Culen’s post about debugging Twig templates, I began to look for templates in the following path
sites/default/files/php. From my understanding, opening a template folder gains access to the current template version the project is using, hence the long hash.
If a change is made to the template, an additional hash file is created and a new breakpoint will need to be set. If at any point the hash template files get overwhelming, clearing the cache (running
drush cr all) will reset the PHP folder and the template files, reducing the hash files to one per template folder.
First off, I needed to acclimate myself to translating PHPStorm syntax into Twig. For example, copying a variable name in PHPStorm produces a syntax like this:
$context[‘page’][‘#title’]->arguments[‘@name’]. That gets translated into the twig file like so:
page[‘#title’].arguments[‘@name’]. Here’s what my PHPStorm screen looked like while working on this solution:
Some patterns and tricks I found helpful:
$contextand starting with the main content variable.
- Strip array syntax, i.e.
- If arrays exist next to each other, separate them with periods. Ex.
- If an array has a #, @, or other symbol associated, keep its integrity. No period is needed here. Ex.
arguments[‘@name’]stays the same.
- If an arrow exists, treat the method (what comes after the ->) in the same manner as arrays. Ex.
- If you’re having trouble rendering the desired output, try adding
.valueto the end of the render code and see if that does the trick.
dump()simultaneously with PHPStorm’s suggested variable path.
- Refer to the Twig documentation for other handy built-in features.
Up until the moment I got PHPStorm doing the heavy lifting, my team and I were relying soley on the
dump() Twig function. We were halfway through the project when I discovered a value was no longer present. The disappearance was due to a template’s reliance on a value being rendered via an array placement, i.e.
content.tile.3['#markup'], the ‘3’ referring to the 4th placement in the ‘tile’ array. To alleviate potential confusion, ‘tile’ happened to be the custom field group where the
field_to_render existed, and the
field_to_render was the 4th field in the list of fields. When a field was moved within the ‘tile’ field group, the code broke. Once I had access to the phpstorm debugger, I was able to see a better way to render this element, i.e.
content.field_to_render. It suddenly dawned on me that our project needed some tidying, so I rolled up my sleeves and got to work.
These are the strategies I established during my clean-up process:
- Create the shortest render code possible with the closest placement to the main content variable. This will be the most stable. My array placement example mentioned previously is a good example of this. The same value can be present and rendered in numerous ways.
- If rendering a field, use this pattern:
content.field_to_render. This will render the field object, inheriting any backend logic that’s been applied to that field existing in the view_mode you are theming.
- If you prefer having just the markup or integer value, try adding a
.valueto the end. Examples:
content[‘#node’].nid.valuewill provide just the node id, and
content.node_titlewill render the title object whereas
content[‘#node’].title.valuewill render the title as a string.
- The first element in an array might be the most stable. For example, we often use the media module which can add complexity to a media item’s data structure. In order use a node’s image as a background for a
<div>, this is the best approach we found:
Any change can be tough to navigate, but it’s often well worth the effort. My experience theming in Drupal 8 thus far has been lovely, and fairly intuitive. I find it offers front-end developers more authority over the markup than its predecessor, and makes me excited for the future of theming in Drupal 8. If you were at all daunted by the thought of theming in Drupal 8, I hope this post helps you in your future twig debugging endeavors!
Note:Devel and Kint are a couple additional tools available for debugging Twig variables, and I mention those in case others find them useful. More information on how to set those tools up for debugging Twig files (and more!) can be found in this Drupal 8 Theming Guide and on Amber Matz’s Let’s Debug in Drupal 8! post.
If you’re new to Drupal 8 theming, I would start with the resources Amber specifies in her “Editor’s notes”, and sqndr’s D8 theming docs. Debugging twig files is an intermediate topic.
If you have any personal experience with Drupal 8 theming, or insight you’d like to share, I’d love to hear about it in the comments section!
Get In Touch
Questions? Comments? We want to know! Drop us a line and let’s start talking.