Custom data processors

When there is no suitable data processor that prepares the variables needed for your content element or template, you can define a custom data processor by implementing \TYPO3\CMS\Frontend\ContentObject\DataProcessorInterface.

You can find the example below in the TYPO3 Documentation Team extension EXT:examples.

Using a custom data processor in TypoScript

The data processor can be configured through a TypoScript setup configuration. A custom data processor can be used in the definition of a "new custom content element" as follows:

tt_content {
    examples_dataproccustom =< lib.contentElement
    examples_dataproccustom {
        templateName = DataProcCustom
        # Before TYPO3 v12.1 you have to give the fully-qualified class name of the processor
        # dataProcessing.10 = T3docs\Examples\DataProcessing\CustomCategoryProcessor
        # Since TYPO3 v12.1 one can also use a (in Services.yaml) configured alias
        dataProcessing.10 = custom-category
        dataProcessing.10 {
            as = categories
            categoryList.field = categories

In the extension examples you can find the code in EXT:examples/Configuration/TypoScript/DataProcessors/Processors/CustomCategoryProcessor.typoscript.

In the field categories the comma-separated categories are stored.


The custom data processor described here should serve as a simple example. It can therefore only work with comma-separated values, not with an m:n relationship as used in the field categories of tables like tt_content. For that, further logic would need to be implemented.

Register an alias for the data processor (optional)

New in version 12.1.

Instead of using the fully-qualified class name as data processor identifier (in the example above T3docs\Examples\DataProcessing\CustomCategoryProcessor) you can also define a short alias in Configuration/Services.yaml:

        - name: 'data.processor'
          identifier: 'custom-category'

The alias custom-category can now be used as data processor identifier like in the TypoScript example above.


When registering a data processor alias please be sure you don't override an existing alias (form TYPO3 Core or a third-party extension) as this may cause errors.


It is recommended to tag a custom data processors as this will automatically add them to the internal DataProcessorRegistry, enabling dependency injection by default. Otherwise, the service would need to be set public.

Implementing the custom data processor

The custom data processor must implement \TYPO3\CMS\Frontend\ContentObject\DataProcessorInterface. The main method process() gets called with the following parameters:

ContentObjectRenderer $cObj

Receives the data of the current TypoScript context, in this case the data of the calling content element.

array $contentObjectConfiguration

Contains the configuration of the calling content element. In this example all configuration of tt_content.examples_dataproccustom

array $processorConfiguration

Contains the configuration of the currently called data processor. In this case the value of as and the stdWrap configuration of the categoryList

array $processedData

On calling, contains the processed data of all previously called data processors on this content element. Your custom data processor also stores the variables to be send to Fluid here.

This is an example implementation of a custom data processor:



 * This file is part of the TYPO3 CMS project. [...]

namespace T3docs\Examples\DataProcessing;

use T3docs\Examples\Domain\Repository\CategoryRepository;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer;
use TYPO3\CMS\Frontend\ContentObject\DataProcessorInterface;

 * Class for data processing comma separated categories
class CustomCategoryProcessor implements DataProcessorInterface
     * Process data for the content element "My new content element"
     * @param ContentObjectRenderer $cObj The data of the content element or page
     * @param array $contentObjectConfiguration The configuration of Content Object
     * @param array $processorConfiguration The configuration of this processor
     * @param array $processedData Key/value store of processed data (e.g. to be passed to a Fluid View)
     * @return array the processed data as key/value store
    public function process(
        ContentObjectRenderer $cObj,
        array $contentObjectConfiguration,
        array $processorConfiguration,
        array $processedData
    ) {
        if (isset($processorConfiguration['if.']) && !$cObj->checkIf($processorConfiguration['if.'])) {
            return $processedData;
        // categories by comma separated list
        $categoryIdList = $cObj->stdWrapValue('categoryList', $processorConfiguration ?? []);
        $categories = [];
        if ($categoryIdList) {
            $categoryIdList = GeneralUtility::intExplode(',', (string)$categoryIdList, true);
            /** @var CategoryRepository $categoryRepository */
            $categoryRepository = GeneralUtility::makeInstance(CategoryRepository::class);
            foreach ($categoryIdList as $categoryId) {
                $categories[] = $categoryRepository->findByUid($categoryId);
            // set the categories into a variable, default "categories"
            $targetVariableName = $cObj->stdWrapValue('as', $processorConfiguration, 'categories');
            $processedData[$targetVariableName] = $categories;
        return $processedData;

In the extension examples you can find the code in EXT:/examples/Classes/DataProcessing/CustomCategoryProcessor.php.

On being called, the CustomCategoryProcessor runs stdWrap on the calling ContentObjectRenderer, which has the data of the table tt_content in the calling content element.

Since the field categoryList got configured in TypoScript as follows:

categoryList.field = categories

stdWrap fetches the value of categoryList from tt_content.tx_examples_main_category of the currently calling content element.

Now the custom data processor processes the comma-separated values into an array of integers that represent uids of the table sys_category. It then fetches the category data from the CategoryRepository by calling findByUid.

The data of the category records then gets stored in the desired key in the $processedData array.

To make the data processor more configurable, we test for a TypoScript if condition at the beginning, and make the name of the key we use to store the data configurable by the configuration as.