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 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
        dataProcessing.10 = T3docs\Examples\DataProcessing\CustomCategoryProcessor
        dataProcessing.10 {
            as = categories
            categoryList.field = tx_examples_main_category

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

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

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:

namespace T3docs\Examples\DataProcessing;

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

class CustomCategoryProcessor implements DataProcessorInterface
    public function process(
        ContentObjectRenderer $cObj,
        array $contentObjectConfiguration,
        array $processorConfiguration,
        array $processedData
    ) : array {
        if (isset($processorConfiguration['if.']) && !$cObj->checkIf($processorConfiguration['if.'])) {
            // leave $processedData unchanged in case there were previous other processors
            return $processedData;
        // categories by comma-separated list
        $categoryIdList = $cObj->stdWrapValue('categoryList', $processorConfiguration ?? []);
        if ($categoryIdList) {
            $categoryIdList = GeneralUtility::intExplode(',', (string)$categoryIdList, true);

        /** @var CategoryRepository $categoryRepository */
        $categoryRepository = GeneralUtility::makeInstance(CategoryRepository::class);
        $categories = [];
        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 typo3conf/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 = tx_examples_main_category

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.