---
title: "Custom data processors"
manual: "TYPO3 Explained"
version: "13.4"
permalink: "https://docs.typo3.org/permalink/t3coreapi:content-elements-custom-data-processor@13.4"
source: "ApiOverview/ContentElements/CustomDataProcessing.rst"
rendered: "2026-09-23T13:16:30+00:00"
---

# Custom data processors {#content-elements-custom-data-processor}

When there is no suitable [data processor](https://docs.typo3.org/m/typo3/reference-typoscript/13.4/en-us/DataProcessing/Index.html#dataProcessing) 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
[`t3docs/examples`](https://packagist.org/packages/t3docs/examples).

## Using a custom data processor in TypoScript {#content-elements-custom-data-processor-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:

**EXT:examples/Configuration/TypoScript/DataProcessors/Processors/CustomCategoryProcessor.typoscript**

```typoscript
tt_content {
  examples_dataproccustom =< lib.contentElement
  examples_dataproccustom {
    templateName = DataProcCustom
    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.

> [!NOTE]
> 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) {#content-elements-custom-data-processor-alias}

<!-- TODO: no Markdown rendering for "versionadded" -->

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`](../../ExtensionArchitecture/FileStructure/Configuration/ServicesYaml.md#file-extension-configuration-services-yaml):

**EXT:examples/Configuration/Services.yaml**

```yaml
T3docs\Examples\DataProcessing\CustomCategoryProcessor:
    tags:
        - name: 'data.processor'
          identifier: 'custom-category'
```

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

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

> [!TIP]
> It is recommended to tag custom data processors as this will
> automatically add them to the internal `DataProcessorRegistry`,
> enabling [dependency injection](https://docs.typo3.org/permalink/t3coreapi:dependencyinjection@13.4) by default.
> Otherwise, the service would need to be set [public](https://docs.typo3.org/permalink/t3coreapi:what-to-make-public@13.4).

> [!NOTE]
> If your data processor should not be shared then
> you need to set the `shared: false` tag attribute for the service.

## Implementing the custom data processor {#content-elements-custom-data-processor-implementation}

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 it is
    the configuration `tt_content.examples_dataproccustom`

-   **`array $processorConfiguration`**

    Contains the configuration of the currently called data processor. In this
    example it is 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 same content element. Your custom data processor also stores
    the variables to be sent to the Fluid template here.

This is an example implementation of a custom data processor:

**EXT:examples/Classes/DataProcessing/CustomCategoryProcessor.php**

```php
<?php

declare(strict_types=1);

/*
 * 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<string, mixed> $contentObjectConfiguration The configuration of Content Object
   * @param array<string, mixed> $processorConfiguration The configuration of this processor
   * @param array<string, mixed> $processedData Key/value store of processed data (e.g. to be passed to a Fluid View)
   * @return array<mixed> 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.

The field `categoryList` gets configured in TypoScript as follows:

```typoscript
categoryList.field = categories
```

[stdWrap](https://docs.typo3.org/m/typo3/reference-typoscript/13.4/en-us/Functions/Stdwrap.html#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 get stored in the desired key in the
`$processedData` array.

To make the data processor more configurable, we test for a TypoScript
[if](https://docs.typo3.org/m/typo3/reference-typoscript/13.4/en-us/Functions/If.html#if) condition at the beginning, and name the key
we use to store the data configurable by the configuration `as`.
