Context
The template context is the set of variables available in every Twig template. Sloth builds it lazily — values are only resolved when the template actually accesses them.
Built-in context keys
| Key | Content | Condition |
|---|---|---|
site | Site information — name, url, description, language, … | Always |
globals | Global URLs — home_url, theme_url, images_url | Always |
sloth | Sloth internals — current_layout | Always |
wp_title | Current page title | Always |
options | Options accessor — {{ options.my_field }} | Always |
post | Current post model | Single posts and pages only |
{post_type} | Alias for post — e.g. {{ project.title }} | Single posts and pages only |
taxonomy | Current taxonomy term | Taxonomy archives only |
{taxonomy_slug} | Alias for taxonomy | Taxonomy archives only |
author | Current author | Author archives only |
user | Alias for author | Author archives only |
Usage in Twig
{{ site.name }}
{{ site.description }}
{{ globals.theme_url }}
{{ wp_title }}
{# On single posts #}
{{ post.title }}
{{ post.content }}
{{ post.my_acf_field }}
{# On single posts — post type alias #}
{{ project.title }}
{# On taxonomy archives #}
{{ taxonomy.name }}
{{ projectcategory.name }}
{# Options #}
{{ options.primary_color }}
{{ options.blogname }}
Adding custom context
Auto-discovery
Drop a class extending Sloth\Context\ContextProvider into app/Context/ or theme/Context/ and Sloth discovers it automatically:
<?php
namespace App\Context;
use Sloth\Context\ContextProvider;
class NavigationContextProvider extends ContextProvider
{
public function key(): string
{
return 'navigation';
}
public function resolve(): array
{
return [
'primary' => wp_get_nav_menu_items('primary'),
'footer' => wp_get_nav_menu_items('footer'),
];
}
}
Available in Twig immediately:
{% for item in navigation.primary %}
<a href="{{ item.url }}">{{ item.title }}</a>
{% endfor %}
Manual registration
Register a provider in any service provider's boot() method:
public function boot(): void
{
app('context')->register(new MyContextProvider());
}
Conditional providers
Override shouldResolve() to only include the key on certain pages:
class SalesBannerContextProvider extends ContextProvider
{
public function key(): string
{
return 'sales_banner';
}
public function shouldResolve(): bool
{
return is_front_page() || is_shop();
}
public function resolve(): array
{
return [
'text' => options('sales_banner_text'),
'color' => options('sales_banner_color', '#ff0000'),
];
}
}
Static values
For one-off values that don't need a full provider:
app('context')->set('current_step', 3);
app('context')->set('show_sidebar', false);
Provider API
abstract class ContextProvider
{
// The key under which this value is available in Twig
abstract public function key(): string;
// Resolve and return the value — called lazily on first access
abstract public function resolve(): mixed;
// Whether to include this key — defaults to true
public function shouldResolve(): bool
{
return true;
}
}
Context in PHP
// Access a single key (lazy)
app('context')['post'];
app('context')['site'];
// Set a value
app('context')['my_key'] = 'value';
app('context')->set('my_key', 'value');
// Register a provider
app('context')->register(new MyContextProvider());
// Get full context as array (resolves all providers)
app('context')->toArray();
:::tip Production deployment
After adding new context providers, run wp sloth manifest:clear to regenerate the manifest cache. See Auto-Discovery.
:::
Testing context providers
If your provider calls WordPress functions directly, they may be loaded before Patchwork and cannot be mocked in tests. Wrap them in an injectable class instead:
// app/Context/MyWordPressWrapper.php
class MyWordPressWrapper
{
public function getSomeValue(): string
{
return (string) some_wp_function();
}
}
// app/Context/MyProvider.php
class MyProvider extends ContextProvider
{
public function __construct(
private readonly MyWordPressWrapper $wrapper
) {}
public function key(): string { return 'my_key'; }
public function resolve(): mixed
{
return $this->wrapper->getSomeValue();
}
}
Register via a service provider:
public function boot(): void
{
app('context')->register(
new MyProvider(app(MyWordPressWrapper::class))
);
}
Sloth uses BlogInfo internally for exactly this reason — it wraps get_bloginfo() and home_url() so SiteContextProvider is fully testable. Inject it via app(BlogInfo::class) if you need the same values in your own provider.