Timber for WordPress: Twig Templates Without the PHP Soup
timber/timber (~5.7k stars) lets you write WordPress themes with the Twig template engine: logic in PHP (or Timber context), markup in .twig files. Teams that hated nested PHP tags in theme files — <?php if (have_posts()) : ?> wrapped around HTML wrapped around more PHP — still reach for Timber when they want readable templates and a clear separation between data preparation and presentation.
Why Timber exists
WordPress theme development traditionally mixes database calls, business logic, and HTML in the same file. Timber borrows from MVC thinking:
- PHP prepares a context array (post data, menus, options, ACF fields)
- Twig renders templates with filters, macros, and extends/includes
- Timber bridges WordPress objects (
TimberPost,TimberTerm) into Twig-friendly structures
If your team already knows Twig from Symfony, Laravel (Blade is different but the separation idea is similar), or Craft CMS, Timber lowers the WordPress-specific template learning curve.
Who Timber is for
- Agencies with Twig experience across multiple PHP platforms
- Maintainers of large classic themes who need template readability
- Projects pairing WordPress with Bedrock and Composer-managed dependencies
- Teams not ready to adopt Sage/Blade but wanting structured templates
When NOT to use Timber
- Greenfield with no Twig history — Sage/Blade may align better with modern WP agency stacks
- Block theme / FSE-first projects — templates live in HTML block markup, not Twig
- Hosts blocking Composer — Timber is commonly installed via Composer
- Tiny brochure themes — template abstraction overhead may not pay off
Basic Timber workflow
- Install Timber via Composer (
composer require timber/timber) or as a plugin depending on your setup. - Initialize Timber in
functions.phpper current docs. - Create
views/(or similar) directory for.twigtemplates. - Build context in PHP route files (
single.phpbecomes a thin loader callingTimber::render()). - Pass ACF fields into context:
$context['hero_title'] = get_field('hero_title'); - Render with Twig:
{{ hero_title }}instead of echoing in PHP loops.
Timber vs Sage (Blade) vs plain PHP
| Approach | Template syntax | Toolchain |
|---|---|---|
| Timber | Twig | Composer + optional Bedrock |
| Sage | Blade | Composer + Vite + Tailwind |
| Underscores | Plain PHP | Bring your own |
Block themes and Sage/Blade cover overlapping needs for new projects. Timber remains strong when you want Twig specifically or already standardized on it across PHP projects.
ACF + Timber + content operations
Timber makes it elegant to pass ACF fields into Twig context — but editors still enter data one page at a time in wp-admin unless you build bulk tooling. For multi-page text field updates across location or service pages, use Quickfields Bulk Editor for ACF. Guide: Quickfields blog post. CSV workflows: Quickfields Pro.
Pairing with the modern stack
- Bedrock for Composer layout and
.envconfig - WP-CLI for deploy scripts and content migration
- Query Monitor to catch expensive Timber loops or un-cached queries
- WPGraphQL if you later decouple the front end — Timber is classic-theme oriented
Gotchas
- Timber 2.x changes — read migration notes when upgrading from 1.x.
- Context bloat — passing entire post objects everywhere makes templates magic; be explicit.
- ACF in Twig — prepare fields in PHP; avoid calling WordPress functions inside Twig unless using approved extensions.
- Caching — Twig template compilation and object caching plugins interact in ways worth testing on staging.
FAQ
Is Timber a theme? No — it is a library/plugin that themes use.
Active maintenance? Yes — relatively active compared to many classic-theme tools; check GitHub releases.
Works with Gutenberg? Yes for classic themes; block themes follow a different model.
Performance? Timber adds a thin abstraction layer — negligible when templates are sane; problems usually come from unbounded WP_Query loops, not Twig itself.
Can I mix PHP templates and Twig? Yes during migration — gradually move views to .twig while keeping legacy PHP templates until ported.
Example Twig mental model
Instead of embedding loops in PHP markup, your archive.php might build $context['posts'] = Timber::get_posts(); and call Timber::render('archive.twig', $context);. Inside archive.twig, {% for post in posts %} renders cards with {{ post.title }} and {{ post.thumbnail.src }}. ACF fields passed as hero_text become {{ hero_text }} with filters for escaping. This pattern scales to dozens of templates without copy-pasting WordPress loop boilerplate.
Migration path from Underscores to Timber
Teams on legacy _s forks sometimes adopt Timber incrementally: install the library, convert single.php and page.php first, leave archives for later. Pair with Bedrock if you are already moving to Composer.
For content teams still editing ACF per page, add Quickfields regardless of template engine — spreadsheet bulk edits are orthogonal to Twig vs Blade vs PHP. Debug template-related query spikes with Query Monitor after each major Timber migration milestone.
Timber's documentation and community examples cover custom post types, menus, widgets, and pagination patterns — invest an afternoon reading them before structuring your views/ directory naming conventions; consistent naming pays off across multi-year client engagements.
Evaluate Timber alongside Sage honestly: if your team already knows Laravel Blade, Sage may be the faster long-term bet; if your team knows Symfony Twig, Timber is the natural WordPress bridge.
Star count (~5.7k) reflects steady adoption among classic-theme shops — not hype, but durable utility for Twig-preferring teams building long-lived client sites.