Migration 

This page lists required migration steps when upgrading to a new version of the extension.

Version 1.1.0 

Non-array data in process-variables 

If the payload resolved by process-variables (e.g. via dataSource ) is not an array, the current record's own field values are no longer used as a fallback. Instead, variables are processed against an empty record, and the payload is provided as the content object's current value (see Choosing which record to process).

Variables using field in such a configuration now resolve to an empty value. Either convert the payload to an array beforehand (e.g. using a preProcessing processor), or reference the payload with current = 1 instead.

Wrapped current values 

process-each, iterable-to-array and process-variables now wrap arrays and objects which cannot be converted to strings in a CurrentValue object before providing them as current value (see Wrapped current values). TypoScript is not affected, apart from such values no longer causing errors in stdWrap . Within stdWrap , arrays now resolve to a comma-separated list of their scalar values and stringable objects, all other wrapped values resolve to an empty string.

Custom PHP code reading ContentObjectRenderer::getCurrentVal() within these processors (e.g. user functions or data source aware processors) must unwrap the value, see Accessing the current value.

Version 1.0.0 

Version 1.0.0 replaces the previous PHP-class rendering model (DataProcessor / DataProvider / Presenter) with the HANDLEBARSTEMPLATE content object. All rendering configuration moves to TypoScript; custom PHP classes are no longer the entry point.

Removed classes and interfaces 

The following classes and interfaces have been removed and have no replacement:

  • \CPSIT\Typo3Handlebars\DataProcessing\DataProcessor (interface)
  • \CPSIT\Typo3Handlebars\DataProcessing\AbstractDataProcessor
  • \CPSIT\Typo3Handlebars\Data\DataProvider (interface)
  • \CPSIT\Typo3Handlebars\Data\Response\ProviderResponse (interface)
  • \CPSIT\Typo3Handlebars\Presenter\Presenter (interface)
  • \CPSIT\Typo3Handlebars\Presenter\AbstractPresenter
  • \CPSIT\Typo3Handlebars\DataProcessing\SimpleProcessor

The handlebars.processor service tag has also been removed.

TypoScript entry point 

Before: Each content element was routed to a DataProcessor class via a USER content object:

tt_content.header = USER
tt_content.header.userFunc = Vendor\Extension\DataProcessing\HeaderProcessor->process
Copied!

After: Use HANDLEBARSTEMPLATE directly:

tt_content.header = HANDLEBARSTEMPLATE
tt_content.header {
    templateName = Header

    variables {
        header = TEXT
        header.field = header

        subheader = TEXT
        subheader.field = subheader
    }
}
Copied!

Data preparation (DataProvider → variables / dataProcessing) 

Before: Data was prepared in a DataProvider class and returned as a ProviderResponse object, which the Presenter then passed to the renderer.

After: Data is prepared entirely in TypoScript:

  • Simple field values: use variables with content objects such as TEXT , FILES , etc.
  • Database relations and menus: use standard TYPO3 dataProcessing processors (e.g., database-query , menu ).
  • Per-record variable processing inside a loop: use process-variables.

Template selection (Presenter → templateName) 

Before: The Presenter called $this->renderer->render('path/to/template', $data) .

After: The template is declared in TypoScript:

tt_content.my_element {
    templateName = MyElement
}
Copied!

For conditional template selection, use stdWrap on templateName :

tt_content.my_element {
    templateName = MyElement
    templateName.override.if {
        isTrue.field = tx_myext_variant
        value = special
    }
    templateName.override = MyElementSpecial
}
Copied!

Helper registration 

Before: Helpers were registered via Services.yaml tags:

Configuration/Services.yaml
services:
  Vendor\Extension\Renderer\Helper\GreetHelper:
    tags:
      - name: handlebars.helper
        identifier: 'greet'
        method: 'greetById'
Copied!

After: Use the #[AsHelper] attribute directly on the class or method:

EXT:my_extension/Classes/Renderer/Helper/GreetHelper.php
use CPSIT\Typo3Handlebars\Attribute\AsHelper;
use CPSIT\Typo3Handlebars\Renderer\Helper\Helper;
use DevTheorem\Handlebars\HelperOptions;

#[AsHelper('greet')]
final readonly class GreetHelper implements Helper
{
    public function render(HelperOptions $options): string { /* ... */ }
}
Copied!

The Services.yaml tag approach still works and can be used if you cannot modify the helper class (e.g., a third-party class).

Debug mode 

The debug mode built into HandlebarsRenderer has been removed. Previously, when TYPO3's config.debug flag or $GLOBALS['TYPO3_CONF_VARS']['FE']['debug'] was enabled, the renderer automatically bypassed the template cache and switched the Handlebars compiler to strict mode (throwing on missing variables instead of silently returning empty strings).

There is no automatic replacement tied to a debug flag. Use the following alternatives instead:

  • Cache bypass: Disable caching explicitly via TYPO3's caching framework configuration or by setting config.no_cache = 1 during development.
  • Strict compilation: Enable rendering.strictMode in the extension configuration. Unlike the previous behavior, this is a persistent setting rather than one tied to TYPO3's debug flags.
  • Strict template validation: Use the shipped {{debug}} helper inside templates to inspect variable values at render time. For programmatic checks, call Handlebars::precompile() directly to inspect the generated PHP code.

Template path configuration 

No migration needed. Template path configuration via Services.yaml and TypoScript remains unchanged; paths can now additionally be set per content object (see Template paths).