---
title: "Add custom fields"
manual: "News system"
version: "main"
permalink: "https://docs.typo3.org/permalink/georgringer/news:proxyclassgenerator@main"
source: "Tutorials/ExtendNews/ProxyClassGenerator/Index.rst"
rendered: "2026-09-23T19:24:09+00:00"
---

# Add custom fields {#proxyclassgenerator}

Follow this chapter to learn how to add new fields or actions.

It is important to know how this concept is implemented. If a class should be extended, EXT:news will generate
a new file containing the original class of the extension itself and all other classes which should extended it.

Take a look at the following 2 working examples:

-   Add relation to a FE user: [https://github.com/cyberhouse/t3ext-newsauthor](https://github.com/cyberhouse/t3ext-newsauthor)
-   Add an image gallery to a news record: [https://github.com/cyberhouse/t3ext-news_gallery](https://github.com/cyberhouse/t3ext-news_gallery)

> [!WARNING]
> **Attention**
>
> This generator works only with the news version 3.2.0 or higher.

> [!WARNING]
> The drawbacks are easy to identify:
>
> -   Don't use any use statements as those are currently ignored!
> -   It is not possible to override an actual method or property!

The files are saved by using the Caching Framework in the directory `typo3temp/Cache/Code/news`.

-   [1) Add a new field in the backend](https://docs.typo3.org/permalink/georgringer/news:1-add-a-new-field-in-the-backend@main)
-   [2) Register the class](https://docs.typo3.org/permalink/georgringer/news:2-register-the-class@main)
-   [3) Exclude the class from dependency injection](https://docs.typo3.org/permalink/georgringer/news:3-exclude-the-class-from-dependency-injection@main)

## 1\) Add a new field in the backend {#1-add-a-new-field-in-the-backend}

To add new fields, use either the extension [extension_builder](http://typo3.org/extensions/repository/view/extension_builder) or create the extension from scratch.

The extension key used in this examples is `eventnews`.

### Create the fields {#create-the-fields}

3 files are basically all what you need:

#### ext_emconf.php {#ext-emconf-php}

The file  `ext_emconf.php` holds all basic information about the extension like the title, description and version number.

```php
<?php

$EM_CONF[$_EXTKEY] = [
   'title' => 'news events',
   'description' => 'Events for news',
   'category' => 'plugin',
   'author' => 'Georg Ringer',
   'author_email' => '',
   'state' => 'alpha',
   'uploadfolder' => false,
   'createDirs' => '',
   'clearCacheOnLoad' => true,
   'version' => '1.0.0',
   'constraints' => [
      'depends' => [
         'typo3' => '7.6.13-8.7.99',
         'news' => '6.2.0-6.9.99',
      ],
      'conflicts' => [],
      'suggests' => [],
   ],
];
```

#### SQL definition {#sql-definition}

Create the file `ext_tables.sql` in the root of the extension directory with the following content:

```sql
# Table structure for table 'tx_news_domain_model_news'
#
CREATE TABLE tx_news_domain_model_news (
   location_simple varchar(255) DEFAULT '' NOT NULL,
   other_categories int(11) DEFAULT '0' NOT NULL
);
```

#### TCA definition {#tca-definition}

The TCA defines which tables and fields are available in the backend and how those are rendered (e.g. as input field, textarea, select field, ...).

In this example, the table `tx_news_domain_model_news` will be extended by a simple input field and a
2nd category relation. Create the file `Configuration/TCA/Overrides/tx_news_domain_model_news.php`.

```php
<?php
defined('TYPO3') or die();

$fields = [
   'location_simple' => [
      'label' => 'My location',
      'config' => [
         'type' => 'input',
         'size' => 15
      ],
   ],
   'other_categories' => [
      'label' => 'Other categories',
      'config' => [
         'type' => 'category',
      ],
   ],
];

\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addTCAcolumns('tx_news_domain_model_news', $fields);
\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addToAllTCAtypes('tx_news_domain_model_news', 'location_simple,other_categories');
```

### Install the extension {#install-the-extension}

Now you should be able to install the extension and if you open a news record, you should see the new field in the last tab.

## 2\) Register the class {#2-register-the-class}

Until now, EXT:news won't use the new field because it doesn't know about it. To change that, you need to register your new model.

### Registration {#registration}

Create the file `ext_localconf.php` in the root of the extension:

```php
<?php
defined('TYPO3') or die();

$GLOBALS['TYPO3_CONF_VARS']['EXT']['news']['classes']['Domain/Model/News']['eventnews'] = 'eventnews';
```

`Domain/Model/News` is the namespace to the class which should be extended and `eventnews` is the extension key.

### Custom class {#custom-class}

As the class `Domain/Model/News` should be extended, create a file at the same path in the own extension which is
`path/to/eventnews/Classes/Domain/Model/News.php`:

```php
<?php

namespace GeorgRinger\Eventnews\Domain\Model;

use GeorgRinger\News\Domain\Model\Category;
use TYPO3\CMS\Extbase\Annotation\ORM\Lazy;
use TYPO3\CMS\Extbase\Persistence\ObjectStorage;

class News extends \GeorgRinger\News\Domain\Model\News
{
   protected string $locationSimple = '';

   /**
    * @var ?ObjectStorage<Category>
    */
   #[Lazy]
   protected ?ObjectStorage $otherCategories;

   public function __construct()
   {
      $this->otherCategories = new ObjectStorage();
   }

   public function initializeObject(): void
   {
      $this->otherCategories = $this->otherCategories ?? new ObjectStorage();
   }

   public function getLocationSimple(): string
   {
      return $this->locationSimple;
   }

   public function setLocationSimple(string $locationSimple): void
   {
      $this->locationSimple = $locationSimple;
   }

   /**
    * @return ?ObjectStorage<Category>
    */
   public function getOtherCategories(): ?ObjectStorage
   {
      return $this->otherCategories;
   }

   /**
    * @param ObjectStorage<Category> $otherCategories
    */
   public function setOtherCategories(ObjectStorage $otherCategories): void
   {
      $this->otherCategories = $otherCategories;
   }
}
```

> [!IMPORTANT]
> The proxy class generator merges all `__construct()` and `initializeObject()` methods from
> extending classes into single combined methods, so your constructor code **will** run when creating
> new objects and your object initialization code when loading entities from the database.

## 3\) Exclude the class from dependency injection {#3-exclude-the-class-from-dependency-injection}

As the class you define will be added to a new generated class, the class needs to be excluded from dependency injection in Configuration/Services.yaml:

```yaml
services:
  _defaults:
    autowire: true
    autoconfigure: true
    public: false

  GeorgRinger\Eventnews\:
    resource: '../Classes/*'
    exclude: '../Classes/Domain/Model/*'
```

> [!TIP]
> **Hint**
>
> If you are using the extension `extension_builder`, this class might have been created for you already.

> [!IMPORTANT]
> If you reference other objects, you must define the full namespace at the location and don't use namespace imports (with "use")!

### Rebuild proxy classes {#rebuild-proxy-classes}

After changes to the extending class or its registration, rebuild the proxy classes:

```bash
bin/typo3 news:rebuildProxyClasses
```

This regenerates the merged class files in `var/cache/code/news/`. You should run this command
after every change to the news model or any extension that extends it.

Alternatively, clearing the **system cache** via the backend or the **Admin Tools** module
will also trigger a rebuild on the next request.
