---
title: "Upgrading from 2.3 to 2.4"
manual: "Academic Profiles"
version: "main"
permalink: "https://docs.typo3.org/permalink/fgtclb/academic-persons:upgrade-from-2-3-to-2-4@main"
source: "Upgrade/From23To24.rst"
rendered: "2026-10-15T10:24:29+00:00"
---

# Upgrading from 2.3 to 2.4 {#upgrade-from-2-3-to-2-4}

Version 2.4 hides the six content elements of **academic_persons** in
the backend until a site includes the page TSconfig of their components, which
is the biggest change for an existing site. Work through the sections in order.
Skip a step that does not apply to the installation.

## Before you start {#upgrade-from-2-3-to-2-4-before-you-start}

Version 2.4 runs on TYPO3 12.4 from 12.4.22 on and on TYPO3 13.4, with PHP 8.1
or later. That is the same as for 2.3, so the TYPO3 core does not have to
change for this upgrade.

**academic_persons** 2.4 needs these packages. Upgrade them first or in
the same deployment, in this order:

-   [`fgtclb/environment-state-manager`](https://packagist.org/packages/fgtclb/environment-state-manager) 1.x, new in 2.4, which this
    extension and **academic_base** 2.4 require. It is declared in
    `composer.json` as `^1.0` and in `ext_emconf.php` as
    `1.0.0-1.99.99`, see [Important: New required dependency fgtclb/environment-state-manager](https://docs.typo3.org/permalink/fgtclb/academic-persons:important-ace-254-academic-persons@main). Composer
    installs it on its own. A classic installation installs
    **environment_state_manager** before it activates
    **academic_base** 2.4 or this extension.
-   [`fgtclb/academic-base`](https://packagist.org/packages/fgtclb/academic-base) 2.4, the same release as this extension.

The extensions that require this one follow it in the same deployment, where
installed: **academic_persons_edit**,
**academic_contacts4pages** and **academic_persons_sync**.

## Update the package {#upgrade-from-2-3-to-2-4-package}

```bash
composer require -W \
    'fgtclb/academic-base':'~2.4.0' \
    'fgtclb/academic-persons':'~2.4.0'
```

A project that requires branch `2` as `2.x-dev` keeps an inline alias such
as `2.x-dev as 2.4.x-dev` working, see [Important: The development branch installs as 2.4.x-dev](https://docs.typo3.org/permalink/fgtclb/academic-persons:important-1790796666@main).

On a classic installation, install **environment_state_manager** 1.x
from the TER in **Admin Tools > Extensions** first, because neither
**academic_base** 2.4 nor this extension can be activated without it.
Then update **academic_base**, **academic_persons** and the
extensions that require it there, in this order. Run the commands of this page
with `typo3/sysext/core/bin/typo3` instead of `vendor/bin/typo3`.

```bash
vendor/bin/typo3 cache:flush
```

## Update the database {#upgrade-from-2-3-to-2-4-database}

```bash
vendor/bin/typo3 extension:setup
```

In the backend the same is **Admin Tools > Maintenance > Analyze
Database Structure**. Version 2.4 adds one column to the contract table,
`tx_academicpersons_domain_model_contract.organisational_unit_sorting`.
Nothing is changed or dropped. The upgrade wizard of the next step fills the
new column.

## Run the upgrade wizards {#upgrade-from-2-3-to-2-4-wizards}

```bash
vendor/bin/typo3 upgrade:run academicPersons_seedContractOrganisationalUnitSorting
```

The wizard **Seed the contract sort order of academic organisational
units**, `academicPersons_seedContractOrganisationalUnitSorting`, is new in
2.4. A contract is an inline child of its profile and of its organisational
unit, and both relations wrote the same `sorting` column until 2.3, so
saving an organisational unit rearranged the contracts of every profile that
owns one of them. From 2.4 on the unit relation has a column of its own, which
the previous step adds and this wizard fills with the order the unit forms show
today. See [Important: An organisational unit sorts its contracts on its own](https://docs.typo3.org/permalink/fgtclb/academic-persons:important-organisational-unit-sorts-its-contracts@main).

Run it after the database update, the wizard requires an up to date schema.
Without it every contract carries `0` in the new column, so an
organisational unit form lists its contracts in whatever order the database
returns until an editor saves that unit once. Profiles keep ordering their
contracts by `sorting`, so the frontend is not affected either way.

Running the wizard again is harmless. It appends what has no position yet and
never renumbers what has one. Once TYPO3 has recorded it as done, it is offered
again only after it is marked undone. TYPO3 13 marks a wizard undone with
`vendor/bin/typo3 upgrade:mark:undone academicPersons_seedContractOrganisationalUnitSorting`.
TYPO3 12 has no such command: open
**Admin Tools > Upgrade > Upgrade Wizard**, find the wizard under
**Wizards marked as done** and choose **Mark undone**.

**academic_partners** and **academic_contacts4pages** ship the
same repair for their own tables, as
`academicPartners_seedPartnershipRoleSorting` and
`academicContact4pages_seedContactSecondarySorting`. Run them in this step
where those extensions are installed.

The other wizards of this extension,
`academicPersons_MigrateListTypeToCTypeContentElements` and
`academicPersons_MigrateProfileAutoCreateExtensionsConfiguration`, shipped
with 2.3 already. An installation that ran them there has nothing more to do.

## Adapt the configuration {#upgrade-from-2-3-to-2-4-configuration}

### Make the content elements selectable {#upgrade-from-2-3-to-2-4-page-tsconfig}

The site sets and static templates were cut per content element, and the six
content elements are now hidden for the whole installation until the page
TSconfig of their component brings them back. See
[Breaking: Site sets and static templates have been restructured](https://docs.typo3.org/permalink/fgtclb/academic-persons:breaking-site-sets-and-static-templates-restructured@main) for the complete
change.

-   **TYPO3 12, and TYPO3 13 without a site set:** add
    **Academic Persons: All components (academic_persons)** in the page
    record of every site root, tab **Resources**, field
    **Include static Page TSconfig (from extensions)**, or the entries
    of the single content elements a site should offer, see
    [Include static page TSconfig](https://docs.typo3.org/permalink/fgtclb/academic-persons:static-pagetsconfig@main). This entry did not
    exist in 2.3. Without it the content elements are no longer offered in the
    backend.
-   **TYPO3 13 with a site set:** nothing to do. The sets
    `fgtclb/academic-persons-default` and `fgtclb/academic-persons-standalone`
    keep their names and deliver the page TSconfig of all six content elements.
    A site may name the new aggregate `fgtclb/academic-persons` or single
    component sets instead.

Use one mechanism per site, never a site set and a static template together,
see [Do not combine both](https://docs.typo3.org/permalink/fgtclb/academic-persons:one-mechanism-per-site@main).

Existing content elements keep rendering in the frontend either way. The
breaking change entry warns that saving such a content element in the backend,
on a page that does not include the page TSconfig of its component, writes
another content type. That no longer happens in 2.4.0:
**academic_base** 2.4 keeps the stored type selected and labels it
**(not enabled on this page)**, so saving the record keeps it. A content
element whose type was already replaced before the update, for example on a
page that restricted the content types with
`TCEFORM.tt_content.CType.keepItems`, is not repaired. Its record
history shows the former type.

The **Profile Card** now offers the field **Detail Page**,
which the page TSconfig of 2.3 disabled. To keep it hidden, see
[Important: The profile card offers the detail page](https://docs.typo3.org/permalink/fgtclb/academic-persons:important-ace-833-academic-persons@main).

### Static templates and imports {#upgrade-from-2-3-to-2-4-static-templates}

A `sys_template` record keeps working without a change. Both values its
field **Include TypoScript sets** on the tab **Advanced
Options** can store, `EXT:academic_persons/Configuration/TypoScript/Default` and
`EXT:academic_persons/Configuration/TypoScript/Standalone`, still resolve.
Only their labels changed, to **Academic Persons: Shared plugin
settings** and **Academic Persons: Standalone page**.

An `@import` of a shipped file in a site package has to be checked.
These files were removed:

-   [`Configuration/TypoScript/constants.typoscript`](https://docs.typo3.org/m/typo3/reference-coreapi/main/en-us/ExtensionArchitecture/FileStructure/Configuration/TypoScript/Index.html#file-extension-configuration-typoscriptconstants-typoscript) and
    [`Configuration/TypoScript/setup.typoscript`](https://docs.typo3.org/m/typo3/reference-coreapi/main/en-us/ExtensionArchitecture/FileStructure/Configuration/TypoScript/Index.html#file-extension-configuration-typoscriptsetup-typoscript), the deprecated forwards
    to `Configuration/TypoScript/Default/`,
-   [`Configuration/TypoScript/Standalone/constants.typoscript`](https://docs.typo3.org/m/typo3/reference-coreapi/main/en-us/ExtensionArchitecture/FileStructure/Configuration/TypoScript/Index.html#file-extension-configuration-typoscriptconstants-typoscript) and
    [`Configuration/TypoScript/Standalone/setup.typoscript`](https://docs.typo3.org/m/typo3/reference-coreapi/main/en-us/ExtensionArchitecture/FileStructure/Configuration/TypoScript/Index.html#file-extension-configuration-typoscriptsetup-typoscript),
-   `Configuration/TSconfig/page.tsconfig`, now
    `Configuration/TSconfig/Full/page.tsconfig`,
-   the files below `Configuration/Sets/AcademicPersonsDefault/` and
    `Configuration/Sets/AcademicPersonsStandalone/`.

An `@import` of a missing file fails silently and shows up as
missing configuration. The breaking change entry linked above has the table of
old and new paths.

### Grouping and sorting of the profile list {#upgrade-from-2-3-to-2-4-grouping-and-sorting}

The defaults of `plugin.tx_academicpersons.demand.groupBy` and
`plugin.tx_academicpersons.demand.sortBy` are now the same with and
without a site set, `lastNameAlpha` and `lastName`.

-   A site without a site set, which on TYPO3 12 is every site, now groups a
    profile list by the first letter of the last name unless it sets
    `demand.groupBy` itself. Set the constant to an empty value to
    keep an ungrouped list.
-   A site on a site set now sorts a profile list by last name unless it sets
    `demand.sortBy` itself. The value `title` the sets shipped up
    to 2.3 was rejected by the extension, so these lists had no ordering at
    all.

### The settings file {#upgrade-from-2-3-to-2-4-settings-file}

A site package that ships its own
`Configuration/AcademicPersons/Settings.yaml` with a `validations`
map replaces the shipped map as a whole. Remove the `number` flag from
`zip` and `streetNumber` of `physicalAddress` there, as the
shipped file does now, so that postcodes and street numbers are stored as
entered. Flush all caches afterwards. See
[Important: Address postcode and street number accept text](https://docs.typo3.org/permalink/fgtclb/academic-persons:important-ace-841-academic-persons@main).

### Extension configuration {#upgrade-from-2-3-to-2-4-extension-configuration}

Two options are new, `profile.feuser.telephoneNumberType` and
`profile.feuser.faxNumberType`. They decide which phone number type
the telephone and fax numbers of a frontend user are imported as, and default
to `business`. The next synchronization run writes `business` where an
imported record still carries the type `phone` or `fax` and the installation
does not offer it. Set the options in **Admin Tools > Settings >
Extension Configuration** to type the imported numbers differently. See
[Feature: Configurable frontend user phone number types](https://docs.typo3.org/permalink/fgtclb/academic-persons:feature-configurable-frontend-user-phone-number-types@main).

Check the lists `demand.allowedSortByValues`,
`demand.allowedGroupByValues`, `types.emailAddressTypes`,
`types.phoneNumberTypes` and `types.physicalAddressTypes` for an entry
without a value, such as `=Private`. Such an entry is
ignored now, and a record stored with it shows its type as an invalid value in
the backend until it is saved with another one. See
[Important: Empty configured values are ignored](https://docs.typo3.org/permalink/fgtclb/academic-persons:important-ace-438-academic-persons@main).

### Routing {#upgrade-from-2-3-to-2-4-routing}

A site configuration that imports more than one of the route enhancer files
`List.yaml`, `ListAndDetail.yaml` and `Detail.yaml` has to
limit each enhancer to the pages that carry its plugin with
`limitToPages`. Otherwise the enhancer imported first takes the URLs of
the others, and the detail page answers `404`. See
[Important: Route enhancers have to be limited to their pages](https://docs.typo3.org/permalink/fgtclb/academic-persons:important-route-enhancers-limit-to-pages@main) and
[Route enhancers](https://docs.typo3.org/permalink/fgtclb/academic-persons:configuration-route-enhancers@main).

### Labels {#upgrade-from-2-3-to-2-4-labels}

-   A frontend label override under
    `plugin.tx_academic_persons._LOCAL_LANG` no longer has an
    effect. Move it to `plugin.tx_academicpersons._LOCAL_LANG`, or
    to the path of the one plugin it is meant for. See
    [Important: Label overrides are read from the documented path](https://docs.typo3.org/permalink/fgtclb/academic-persons:important-label-overrides-use-the-documented-path@main) and
    [Labels](https://docs.typo3.org/permalink/fgtclb/academic-persons:configuration-labels@main).
-   The backend labels of the relation between frontend users and profiles
    moved from **academic_persons_edit** into this extension, to
    `EXT:academic_persons/Resources/Private/Language/locallang_tca.xlf`.
    An override through
    `$GLOBALS['TYPO3_CONF_VARS']['SYS']['locallangXMLOverride']` has to
    target the new file. The tab of the profile form is keyed
    `tx_academicpersons_domain_model_profile.div.frontend_users.label`
    there, no longer
    `tx_academicpersons_domain_model_profile.tabs.frontend_users.label`.
    See [Important: Frontend user labels moved into this extension](https://docs.typo3.org/permalink/fgtclb/academic-persons:important-frontend-user-labels-moved@main).
-   A further translation of `locallang.xlf` that copied the unit
    `contracts.emailAdresses` renames it to
    `contracts.emailAddresses`. See
    [Important: The contract e-mail label shows in English](https://docs.typo3.org/permalink/fgtclb/academic-persons:important-contract-email-label-unit-id@main).

### Profile synchronization {#upgrade-from-2-3-to-2-4-profile-synchronization}

`academic:createprofiles` and `academic:updateprofiles` now process
hidden profiles and disabled frontend users as well, and ignore the start and
end time of profiles and frontend users and the frontend user groups of
profiles. They update the data of such a profile and leave its visibility
alone. A profile that was
kept out of the synchronization by hiding it, or by disabling its frontend
user, is overwritten by the next run.

Before the first run, set **Disable profile sync** (`skip_sync`)
on every profile that must not be synchronized. See
[Breaking: Profile synchronization now includes hidden profiles and users](https://docs.typo3.org/permalink/fgtclb/academic-persons:breaking-1782285582@main) and [Important: Profile synchronization ignores the visibility window](https://docs.typo3.org/permalink/fgtclb/academic-persons:important-ace-667-academic-persons@main).

`academic:createprofiles` now also creates a profile for a disabled
frontend user, and for one outside its start and end time, that has none yet.
**Disable profile sync** cannot prevent that, because it is a field of
the profile that does not exist yet. Exclude the page of such frontend users
with `--exclude-pids`, or delete the profiles created for them.

Both commands now refuse a value of `--include-pids` or
`--exclude-pids` with a part that is not a page uid, and exit with code
`2` instead of running with another list. Check the arguments of scheduler
tasks and scripts. See [Important: Profile create and update commands refuse wrong page lists](https://docs.typo3.org/permalink/fgtclb/academic-persons:important-ace-845-academic-persons@main).

`academic:updateprofiles` now stores new records next to their profile or
contract instead of on the page of the frontend user. Records an earlier run
stored there stay where they are. Moving them is optional,
[Important: Updated profiles keep new records on their page](https://docs.typo3.org/permalink/fgtclb/academic-persons:important-ace-843-academic-persons@main) has the queries that find them.

## Adapt templates and assets {#upgrade-from-2-3-to-2-4-templates}

An override keeps its own copy and does not receive a change of the shipped
file. Seven files changed. None was renamed, moved or removed, and no asset
changed. All of them except `Partials/Profile/Item.html` translate their
labels with the extension name `AcademicPersons` now instead of
`academic_persons`, which moves the path of a label override, see
[Labels](https://docs.typo3.org/permalink/fgtclb/academic-persons:upgrade-from-2-3-to-2-4-labels@main). The other changes follow. The paths
below are relative to `Resources/Private/`:

| File | What changed | Entry |
| --- | --- | --- |
| `Partials/Profile/Contract/Field.html` | Renders the organisational unit and the title of the location, and a `tel:` target without spaces. | [Important: Contract rows render the location, the unit and dialable phones](https://docs.typo3.org/permalink/fgtclb/academic-persons:important-contract-fields-render-the-unit-and-tel-targets@main) |
| `Templates/Profile/Detail.html` | The same `tel:` target, and a name without empty parts. | [Important: Profile names leave out empty parts](https://docs.typo3.org/permalink/fgtclb/academic-persons:important-ace-853-academic-persons@main) |
| `Partials/Profile/Item.html` | The name without empty parts. | [Important: Profile names leave out empty parts](https://docs.typo3.org/permalink/fgtclb/academic-persons:important-ace-853-academic-persons@main) |
| `Partials/Profile/List/ItemList.html`, `Templates/Profile/Card.html`, `Templates/Profile/SelectedContracts.html`, `Templates/Profile/SelectedProfiles.html` | Nothing else. | [Important: Label overrides are read from the documented path](https://docs.typo3.org/permalink/fgtclb/academic-persons:important-label-overrides-use-the-documented-path@main) |

Compare every override with the shipped file of 2.4 and take the changes over.
[Overriding templates](https://docs.typo3.org/permalink/fgtclb/academic-persons:templates-override@main) describes how the overrides are set up.

## Adapt your code {#upgrade-from-2-3-to-2-4-code}

-   The two `itemsProcFunc` classes moved to the namespace
    `\FGTCLB\AcademicPersons\Backend\FormEngine`, as `ContractItems`
    and `ProfileShowFieldsItems`, and the method of the latter is
    `itemsProcFunc()` now. Own TCA or FlexForm configuration, and a class
    that extends one of them, uses the new names. See
    [Breaking: Renamed itemsProcFunc handler classes to FormEngine namespace](https://docs.typo3.org/permalink/fgtclb/academic-persons:breaking-1783613367@main). A project that only changed the items can
    listen to `\FGTCLB\AcademicBase\Event\ModifyTcaSelectFieldItemsEvent`
    instead, see [Feature: Dispatch ModifyTcaSelectFieldItemsEvent in itemsProcFunc handlers](https://docs.typo3.org/permalink/fgtclb/academic-persons:feature-1783613368@main).
-   A project that extends or replaces `ProfileDemand`,
    `ProfileRepository`, `ContractRepository` or
    `ProfileController` takes the new optional parameters and the new
    demand flag into account. See [Important: Extended ProfileDemand, findByUids() and demand handling](https://docs.typo3.org/permalink/fgtclb/academic-persons:important-ace-250-academic-persons@main).
    Narrowing what a plugin shows no longer needs such a subclass, see
    [Feature: Narrow the profiles and contracts a plugin shows](https://docs.typo3.org/permalink/fgtclb/academic-persons:feature-profile-and-contract-query-events@main).
-   A project that extends or replaces the models `Address`, `Email`
    or `PhoneNumber` adds the `hidden` property with its getter and
    setter. See [Feature: Visibility (hidden) support for contact record models](https://docs.typo3.org/permalink/fgtclb/academic-persons:feature-1782285578@main).
-   Code outside this extension that looks up imported telephone records by
    the import identifier `phone:fe_users:<uid>` uses
    `telephone:fe_users:<uid>` now. See
    [Important: Imported telephone records use a stable identifier](https://docs.typo3.org/permalink/fgtclb/academic-persons:important-imported-telephone-records-use-a-stable-identifier@main).

## Check the result {#upgrade-from-2-3-to-2-4-check}

1.  The new content element wizard offers the content elements on the pages of
    every site that should have them, and an existing persons content element
    opens in the backend with its own type.
1.  A profile list groups and sorts its profiles as intended.
1.  An organisational unit form lists its contracts in the order it showed
    before the update.
1.  The detail page is hidden in menus. A request of it without a profile now
    ends with the "page not found" handling of the site, see
    [Important: The profile detail answers "not found" without a profile](https://docs.typo3.org/permalink/fgtclb/academic-persons:important-profile-detail-answers-not-found-without-a-profile@main).
1.  Where organisational units are translated, no contract shows twice on a
    profile. Contracts that an earlier localization of a unit created stay.
    Delete them in the backend,
    [Important: Localizing an organisational unit leaves contracts alone](https://docs.typo3.org/permalink/fgtclb/academic-persons:important-localizing-an-organisational-unit-keeps-its-contracts@main)
    has the query that lists them.
1.  Where **academic_persons_edit** synchronizes profiles into
    translations, check the profiles `academic:createprofiles` created
    before the update, and translate the ones without a translation in the
    backend. See [Important: A created profile is translated again](https://docs.typo3.org/permalink/fgtclb/academic-persons:important-ace-610-academic-persons@main).
1.  A run of `academic:updateprofiles` exits with code `0` and reports
    the number of updated frontend users, and a profile with
    **Disable profile sync** set stays unchanged.
