Twig is the foundation of Drupal’s frontend rendering layer. In Drupal 10 and 11, every piece of visible markup — from nodes and blocks to views and layouts — ultimately passes through Twig templates. It provides a secure, structured way to control HTML output while keeping business logic separated from presentation logic. Twig automatically protects against XSS through auto-escaping, supports template inheritance and suggestions, and enables developers to override markup at granular levels such as content type, view mode, or specific entities. Mastering Twig means understanding how Drupal builds render arrays, how template suggestions work, and how to safely print variables while preserving caching and access control. In enterprise Drupal projects, Twig is not just about writing HTML — it is about building maintainable, scalable, and secure theming architecture.
Step 1: Create a Custom Theme
Create your theme directory:
/themes/custom/weeklydrupal_theme/
weeklydrupal_theme.info.yml
name: WeeklyDrupal Theme
type: theme
description: Custom frontend theme for WeeklyDrupal
core_version_requirement: ^10 || ^11
base theme: classy
libraries:
- weeklydrupal_theme/global-styling
Why use classy as base theme?
- Provides clean core templates
- Follows Drupal core standards
- Easier to override and extend
Enable the theme:
drush theme:enable weeklydrupal_theme
drush config:set system.theme default weeklydrupal_theme -y
Step 2: Basic Page Template
Create:
templates/page.html.twig
Example:
<!DOCTYPE html>
<html>
<head>
<head-placeholder token="{{ placeholder_token }}">
<title>{{ head_title|safe_join(' | ') }}</title>
<css-placeholder token="{{ placeholder_token }}">
<js-placeholder token="{{ placeholder_token }}">
</head>
<body{{ attributes }}>
<header>
<h1>{{ site_name }}</h1>
</header>
<main>
{{ page.content }}
</main>
<footer>
<p>© {{ "now"|date("Y") }} WeeklyDrupal</p>
</footer>
<js-bottom-placeholder token="{{ placeholder_token }}">
</body>
</html>
Twig Syntax Fundamentals
Printing Variables
{{ variable }}
Conditional Logic
{% if logged_in %}
<p>Welcome back!</p>
{% endif %}
Looping
{% for item in items %}
<li>{{ item.content }}</li>
{% endfor %}
Important Twig Filters
Common filters used in Drupal:
|escape– Prevents XSS|clean_class– Converts values to valid CSS classes|date– Formats timestamps|length– Counts items|t– Translates strings
Example:
<div class="{{ node.bundle|clean_class }}">
Template Suggestions
Drupal builds template suggestions automatically.
Examples:
node.html.twig
node--article.html.twig
node--5.html.twig
This allows per-content-type and per-node overrides.
Override a Content Type Template
Create:
templates/node--article.html.twig
Example:
<article{{ attributes }}>
<h2>{{ label }}</h2>
<div class="meta">
<span>By {{ author_name }}</span>
<span>{{ date }}</span>
</div>
<div class="content">
{{ content }}
</div>
</article>
Clear cache:
drush cr
Security and Auto-Escaping
Twig auto-escapes output.
Safe:
{{ node.title }}
Avoid unless necessary:
{{ content.body|raw }}
Using |raw incorrectly can introduce XSS vulnerabilities.
Rendering Fields Correctly
Preferred way:
{{ content.field_image }}
Avoid direct access unless necessary:
{{ node.field_image.value }}
Render arrays preserve:
- Field formatters
- Access control
- Caching metadata
Enable Twig Debugging
Inside sites/development.services.yml:
parameters:
twig.config:
debug: true
auto_reload: true
cache: false
After clearing cache, view page source.
You will see template suggestions and file paths.
This is essential for frontend debugging.
Integrating AI with Twig (Modern Pattern)
Suppose you store AI-generated summary in:
field_ai_summary
Twig usage:
{% if content.field_ai_summary %}
<div class="ai-summary">
{{ content.field_ai_summary }}
</div>
{% endif %}
Best practice:
- Generate AI content during entity save
- Store it in a field
- Render safely in Twig
Keep AI logic in backend, presentation in Twig.
Enterprise Theme Structure
weeklydrupal_theme/
├── css/
├── js/
├── templates/
│ ├── page.html.twig
│ ├── node.html.twig
│ ├── node--article.html.twig
│ └── block.html.twig
├── weeklydrupal_theme.info.yml
├── weeklydrupal_theme.libraries.yml
└── weeklydrupal_theme.theme
Never place business logic inside Twig.
Twig = presentation layer only.
Common Mistakes
- Adding PHP inside Twig
- Using
|raweverywhere - Forgetting to clear cache
- Not using template suggestions
- Accessing field values directly instead of render arrays
Interview Questions (Frontend Drupal)
1. What is Twig and why does Drupal use it?
Expected Answer:
Twig is a secure templating engine that separates presentation from business logic and prevents XSS via auto-escaping.
2. What is the difference between content.field_name and node.field_name.value?
Expected Answer:content.field_name is a render array and preserves formatters and caching metadata.node.field_name.value directly accesses raw data.
3. How do template suggestions work in Drupal?
Expected Answer:
Drupal generates template suggestions based on entity type, bundle, view mode, and ID. Developers can override specific templates like node--article.html.twig.
4. How do you enable Twig debugging?
Expected Answer:
Modify development.services.yml to enable debug, auto_reload, and disable cache.
5. Why should you avoid using |raw in Twig?
Expected Answer:
Because it bypasses auto-escaping and can introduce XSS vulnerabilities.
6. Where should business logic live in Drupal?
Expected Answer:
Business logic belongs in preprocess functions, controllers, or services — not inside Twig templates.
7. How would you integrate AI-generated content into a Drupal theme?
Expected Answer:
Generate content via backend service, store in a field, render via Twig using render arrays.