---
title: "PathProvider & VariableProvider"
manual: "Handlebars"
version: "main"
permalink: "https://docs.typo3.org/permalink/cpsit/typo3-handlebars:developer-corner-paths-and-variables@main"
source: "DeveloperCorner/PathsAndVariables.rst"
rendered: "2026-09-29T09:05:57+00:00"
---

# PathProvider & VariableProvider {#developer-corner-paths-and-variables}

Two further interfaces allow contributing template paths and global variables
from PHP rather than from TypoScript or `Services.yaml` configuration.
Both are auto-registered via `#[AutoconfigureTag]` and both use a
priority integer to control merge order, set via Symfony's
`#[AsTaggedItem(priority: ...)]` attribute on the implementing class.

-   [PathProvider](https://docs.typo3.org/permalink/cpsit/typo3-handlebars:pathprovider@main)
-   [VariableProvider](https://docs.typo3.org/permalink/cpsit/typo3-handlebars:variableprovider@main)

## PathProvider {#developer-corner-path-provider}

Implement the
[\\CPSIT\\Typo3Handlebars\\Renderer\\Template\\Path\\PathProvider](https://docs.typo3.org/permalink/cpsit/typo3-handlebars:cpsit-typo3handlebars-renderer-template-path-pathprovider@main)
interface to contribute template and partial root paths programmatically — for
example when paths depend on the current site configuration or a value not
available at container compile time.

Higher priority values are merged last and therefore take precedence over lower
ones. The three built-in providers use 0 (`GlobalPathProvider`), 50
(`TypoScriptPathProvider`), and 100 (`ContentObjectPathProvider`).

-   **interface PathProvider**

    -   *Fully qualified name:* `\CPSIT\Typo3Handlebars\Renderer\Template\Path\PathProvider`

    -   **getTemplateRootPaths()**

        Return an array of template root paths, keyed by integer priority.

        -   *returntype:* array

    -   **getPartialRootPaths()**

        Return an array of partial root paths, keyed by integer priority.

        -   *returntype:* array

    -   **isCacheable()**

        Return `true` if the paths provided by this provider may be
        cached. Return `false` for request-dependent paths.

        -   *returntype:* bool

**EXT:my_extension/Classes/Renderer/Template/Path/SitePathProvider.php**

```php
namespace Vendor\Extension\Renderer\Template\Path;

use CPSIT\Typo3Handlebars\Renderer\Template\Path\PathProvider;
use Symfony\Component\DependencyInjection\Attribute\AsTaggedItem;
use TYPO3\CMS\Core\Site\SiteFinder;

#[AsTaggedItem(priority: 25)]
final readonly class SitePathProvider implements PathProvider
{
    public function __construct(
        private SiteFinder $siteFinder,
    ) {}

    public function getTemplateRootPaths(): array
    {
        return [];
    }

    public function getPartialRootPaths(): array
    {
        return [];
    }

    public function isCacheable(): bool
    {
        return false;
    }
}
```

The class is picked up automatically because `PathProvider` carries
`#[AutoconfigureTag('handlebars.template_path_provider')]`. No extra
`Services.yaml` entry is needed beyond standard autowiring. The
`#[AsTaggedItem(priority: ...)]` attribute on the class determines merge
order; without it, the provider defaults to priority 0.

## VariableProvider {#developer-corner-variable-provider}

Implement the
[\\CPSIT\\Typo3Handlebars\\Renderer\\Variables\\VariableProvider](https://docs.typo3.org/permalink/cpsit/typo3-handlebars:cpsit-typo3handlebars-renderer-variables-variableprovider@main)
interface to inject variables into every template rendering without repeating
them in TypoScript. Common uses include a site-wide locale string, feature
flags, or shared navigation data.

Providers are merged in ascending priority order; a higher-priority provider
can overwrite keys from a lower-priority one. The built-in
`GlobalVariableProvider` uses priority 0.

-   **interface VariableProvider**

    -   *Fully qualified name:* `\CPSIT\Typo3Handlebars\Renderer\Variables\VariableProvider`

    -   **get()**

        Return the variables contributed by this provider.

        -   *returntype:* array

    -   **isCacheable()**

        Return `true` if the variables provided by this provider may be
        cached. Return `false` for request-dependent variables. If any
        registered provider returns `false`, the merged
        `VariableBag` result is not cached and is recomputed on every
        access.

        -   *returntype:* bool

**EXT:my_extension/Classes/Renderer/Variables/SiteVariableProvider.php**

```php
namespace Vendor\Extension\Renderer\Variables;

use CPSIT\Typo3Handlebars\Renderer\Variables\VariableProvider;
use Symfony\Component\DependencyInjection\Attribute\AsTaggedItem;
use TYPO3\CMS\Core\Site\SiteFinder;

#[AsTaggedItem(priority: 10)]
final readonly class SiteVariableProvider implements VariableProvider
{
    public function __construct(
        private SiteFinder $siteFinder,
    ) {}

    public function get(): array
    {
        return [
            'siteName' => $this->siteFinder->getSiteByPageId(0)->getIdentifier(),
        ];
    }

    public function isCacheable(): bool
    {
        return true;
    }

    public function offsetExists(mixed $offset): bool
    {
        return array_key_exists($offset, $this->get());
    }

    public function offsetGet(mixed $offset): mixed
    {
        return $this->get()[$offset] ?? null;
    }

    public function offsetSet(mixed $offset, mixed $value): never
    {
        throw new \LogicException('Variables are read-only.', 1781693633);
    }

    public function offsetUnset(mixed $offset): never
    {
        throw new \LogicException('Variables are read-only.', 1781693639);
    }
}
```

Like `PathProvider`, the class is picked up automatically via
`#[AutoconfigureTag('handlebars.variable_provider')]` on the interface.
The `#[AsTaggedItem(priority: ...)]` attribute on the class determines
merge order; without it, the provider defaults to priority 0.
