Twig Blocks
Timber provides powerful functionality for rendering specific blocks from Twig templates, both from PHP and within Twig templates themselves. This allows you to create reusable template components and render only specific portions of a template when needed.
What are Twig Blocks? #
Twig blocks are sections of a template that can be defined with {% block %} tags. They're commonly used for template inheritance, but with Timber's block rendering functions, you can also use them as standalone, reusable components.
{# components/alerts.twig #}
{% block error %}
<div class="alert alert-error" role="alert">
{{ message }}
</div>
{% endblock %}
{% block success %}
<div class="alert alert-success" role="alert">
{{ message }}
</div>
{% endblock %}
{% block warning %}
<div class="alert alert-warning" role="alert">
{{ message }}
</div>
{% endblock %}PHP Functions #
Timber provides two PHP functions for working with Twig blocks:
Timber::compile_twig_block() #
Returns the rendered block as a string.
/**
* @param string $block_name The name of the block to render
* @param array|string $filenames Template file(s) to load
* @param string|array|null $caller Optional. Value from a `LocationManager` method to control lookup.
* Use `LocationManager::get_calling_script_dir()` (string) or
* `LocationManager::get_locations()` (array). When `null`, Timber uses
* `LocationManager::get_calling_script_dir(1)`.
* @param array $data Data to pass to the template
* @param bool|int|array $expires Cache expiration (optional)
* @param string $cache_mode Cache mode (optional)
* @return string|false The rendered block content
*/
Timber::compile_twig_block(
$block_name,
$filenames,
$caller = null,
$data = [],
$expires = false,
$cache_mode = Loader::CACHE_USE_DEFAULT
)Timber::render_twig_block() #
Directly echoes the rendered block content.
/**
* @param string $block_name The name of the block to render
* @param array|string $filenames Template file(s) to load
* @param string|array|null $caller Optional. Value from a `LocationManager` method to control lookup.
* Use `LocationManager::get_calling_script_dir()` (string) or
* `LocationManager::get_locations()` (array). When `null`, Timber uses
* `LocationManager::get_calling_script_dir(1)`.
* @param array $data Data to pass to the template
* @param bool|int|array $expires Cache expiration (optional)
* @param string $cache_mode Cache mode (optional)
*/
Timber::render_twig_block(
$block_name,
$filenames,
$caller = null,
$data = [],
$expires = false,
$cache_mode = Loader::CACHE_USE_DEFAULT
)Twig Function #
Within Twig templates, you can use the render_twig_block() function:
{{ render_twig_block(block_name, filenames, data, expires, cache_mode) }}Basic Usage Examples #
Simple Alert Component #
Create a reusable alert component template:
views/components/alerts.twig
{% block error %}
<div class="bg-red-500 text-white p-4 rounded" role="alert">
<strong>Error:</strong> {{ message }}
</div>
{% endblock %}
{% block success %}
<div class="bg-green-500 text-white p-4 rounded" role="alert">
<strong>Success:</strong> {{ message }}
</div>
{% endblock %}
{% block warning %}
<div class="bg-yellow-500 text-black p-4 rounded" role="alert">
<strong>Warning:</strong> {{ message }}
</div>
{% endblock %}PHP Usage:
// Display a success message
$success_alert = Timber::compile_twig_block('success', 'components/alerts.twig', [
'message' => 'Your form was submitted successfully!'
]);
echo $success_alert;
// Or render directly
Timber::render_twig_block('error', 'components/alerts.twig', [
'message' => 'Please fix the errors below.'
]);Twig Usage:
{# In your main template #}
<main>
<h1>Contact Form</h1>
{% if form_errors %}
{{ render_twig_block('error', 'components/alerts.twig', {
message: 'Please correct the errors below.'
}) }}
{% endif %}
{% if form_success %}
{{ render_twig_block('success', 'components/alerts.twig', {
message: 'Thank you! Your message has been sent.'
}) }}
{% endif %}
{# Rest of your form here #}
</main>Card Components #
Create a flexible card component with multiple variations:
views/components/cards.twig
{% block basic_card %}
<div class="card">
<h3>{{ title }}</h3>
<p>{{ content }}</p>
</div>
{% endblock %}
{% block image_card %}
<div class="card card--with-image">
<img src="{{ image.src }}" alt="{{ image.alt }}" class="card__image">
<div class="card__content">
<h3>{{ title }}</h3>
<p>{{ content }}</p>
{% if link %}
<a href="{{ link.url }}" class="card__link">{{ link.text }}</a>
{% endif %}
</div>
</div>
{% endblock %}
{% block featured_card %}
<div class="card card--featured">
<div class="card__badge">Featured</div>
<h3>{{ title }}</h3>
<p>{{ content }}</p>
<div class="card__meta">
<span>{{ date }}</span>
<span>{{ author }}</span>
</div>
</div>
{% endblock %}PHP Usage:
// Get some posts and render different card types
$featured_post = Timber::get_post(['meta_key' => 'featured', 'meta_value' => true]);
$recent_posts = Timber::get_posts(['posts_per_page' => 3]);
// Render featured card
if ($featured_post) {
echo Timber::compile_twig_block('featured_card', 'components/cards.twig', [
'title' => $featured_post->title,
'content' => $featured_post->excerpt,
'date' => $featured_post->date,
'author' => $featured_post->author->name,
]);
}
// Render regular cards for recent posts
foreach ($recent_posts as $post) {
echo Timber::compile_twig_block('image_card', 'components/cards.twig', [
'title' => $post->title,
'content' => $post->excerpt,
'image' => $post->thumbnail,
'link' => [
'url' => $post->link,
'text' => 'Read More'
]
]);
}Advanced Usage Examples #
Dynamic Component Selection #
Use variables to determine which block to render:
{# views/page.twig #}
{% for component in page.components %}
{{ render_twig_block(component.type, 'components/all.twig', component.data) }}
{% endfor %}// In your PHP file
$context['page'] = [
'components' => [
[
'type' => 'hero',
'data' => [
'title' => 'Welcome to Our Site',
'subtitle' => 'Building amazing experiences',
'background_image' => $hero_image
]
],
[
'type' => 'text_block',
'data' => [
'content' => 'Lorem ipsum dolor sit amet...',
'alignment' => 'center'
]
],
[
'type' => 'call_to_action',
'data' => [
'title' => 'Ready to Get Started?',
'button_text' => 'Contact Us',
'button_url' => '/contact'
]
]
]
];Layout Section Rendering #
Render specific sections of a larger layout:
views/layouts/page-sections.twig
{% block header %}
<header class="page-header">
<h1>{{ title }}</h1>
{% if subtitle %}
<p class="page-subtitle">{{ subtitle }}</p>
{% endif %}
</header>
{% endblock %}
{% block sidebar %}
<aside class="sidebar">
<h3>Related Links</h3>
<ul>
{% for link in sidebar_links %}
<li><a href="{{ link.url }}">{{ link.title }}</a></li>
{% endfor %}
</ul>
</aside>
{% endblock %}
{% block footer %}
<footer class="page-footer">
<p>© {{ "now"|date('Y') }} {{ site.title }}</p>
</footer>
{% endblock %}Email Template Components #
Create reusable email template blocks:
views/email/components.twig
{% block email_header %}
<div style="background: #f8f9fa; padding: 20px; text-align: center;">
<img src="{{ logo_url }}" alt="{{ site_name }}" style="max-width: 200px;">
<h1 style="color: #333; margin: 10px 0;">{{ subject }}</h1>
</div>
{% endblock %}
{% block email_button %}
<div style="text-align: center; margin: 20px 0;">
<a href="{{ url }}" style="background: #007cba; color: white; padding: 12px 24px; text-decoration: none; border-radius: 4px; display: inline-block;">
{{ text }}
</a>
</div>
{% endblock %}
{% block email_footer %}
<div style="background: #f8f9fa; padding: 20px; text-align: center; border-top: 1px solid #ddd;">
<p style="color: #666; margin: 0;">{{ footer_text }}</p>
<p style="color: #666; margin: 5px 0 0;">
<a href="{{ unsubscribe_url }}" style="color: #666;">Unsubscribe</a>
</p>
</div>
{% endblock %}PHP Usage for Email Generation:
function send_welcome_email($user_email, $user_name) {
$header = Timber::compile_twig_block('email_header', 'email/components.twig', [
'logo_url' => get_template_directory_uri() . '/assets/logo.png',
'site_name' => get_bloginfo('name'),
'subject' => 'Welcome to Our Platform!'
]);
$button = Timber::compile_twig_block('email_button', 'email/components.twig', [
'url' => home_url('/dashboard'),
'text' => 'Get Started'
]);
$footer = Timber::compile_twig_block('email_footer', 'email/components.twig', [
'footer_text' => 'Thanks for joining us!',
'unsubscribe_url' => home_url('/unsubscribe')
]);
$email_body = $header . '<div style="padding: 20px;"><p>Hello ' . $user_name . ',</p><p>Welcome to our platform!</p></div>' . $button . $footer;
wp_mail($user_email, 'Welcome!', $email_body, ['Content-Type: text/html; charset=UTF-8']);
}Fallback Behavior #
When a specified block doesn't exist, Timber will render the entire template instead:
// If 'nonexistent_block' doesn't exist, this will render the whole template
$output = Timber::compile_twig_block('nonexistent_block', 'components/alerts.twig', $data);This provides a graceful fallback, ensuring your site doesn't break if a block name is misspelled or removed.
Performance and Caching #
Block rendering supports the same caching options as regular template rendering:
// Cache for 1 hour
$cached_block = Timber::compile_twig_block('expensive_block', 'components/complex.twig', $data, expires: 3600);
// Different cache times for logged-in vs anonymous users
$user_specific_cache = Timber::compile_twig_block('user_block', 'components/user.twig', $data, expires: [3600, 300]);Real-World Examples #
AJAX Component Loading #
Use block rendering to dynamically load components via AJAX:
function ajax_render_component() {
check_ajax_referer('render_component', 'nonce');
$component_type = sanitize_text_field($_POST['component_type']);
$component_data = json_decode(stripslashes($_POST['component_data']), true);
$output = Timber::compile_twig_block(
$component_type,
'components/ajax.twig',
$component_data
);
wp_send_json_success(['html' => $output]);
}
add_action('wp_ajax_render_component', 'ajax_render_component');Modular Layout Building #
Build complex layouts from smaller block components:
views/components/layout-builder.twig
{% block hero_section %}
<section class="hero" style="background-image: url({{ background_image.src }});">
<div class="hero__content">
<h1>{{ title }}</h1>
<p>{{ subtitle }}</p>
{{ render_twig_block('primary_button', 'examples/buttons.twig', {
text: cta_text,
url: cta_url
}) }}
</div>
</section>
{% endblock %}
{% block text_section %}
<section class="text-section">
<div class="container">
<h2>{{ title }}</h2>
<div class="content">{{ content|raw }}</div>
</div>
</section>
{% endblock %}
{% block gallery_section %}
<section class="gallery">
<div class="container">
<h2>{{ title }}</h2>
<div class="gallery__grid">
{% for image in images %}
<div class="gallery__item">
<img src="{{ image.src('medium') }}" alt="{{ image.alt }}">
</div>
{% endfor %}
</div>
</div>
</section>
{% endblock %}PHP Usage:
$page_sections = get_field('page_sections');
foreach ($page_sections as $section) {
echo Timber::compile_twig_block(
$section['section_type'] . '_section',
'components/layout-builder.twig',
$section
);
}Best Practices #
1. Organize Your Block Templates #
Create a clear structure for your block templates:
views/
├── components/
│ ├── alerts.twig
│ ├── cards.twig
│ ├── forms.twig
│ ├── buttons.twig
│ └── navigation.twig
├── email/
│ ├── components.twig
│ └── notifications.twig
└── layouts/
├── sections.twig
└── layout-builder.twig
2. Use Meaningful Block Names #
Choose descriptive names that clearly indicate the block's purpose:
{# Good #}
{% block primary_navigation %}
{% block error_message %}
{% block featured_product_card %}
{# Avoid #}
{% block nav %}
{% block msg %}
{% block card %}Block rendering with Timber provides a powerful way to create modular, reusable template components that can be used both in PHP and Twig contexts, making your theme development more efficient and maintainable.