---
title: "Configuration"
manual: "Academic Profiles"
version: "main"
source: "Configuration/Index.rst"
rendered: "2026-10-02T20:47:49+00:00"
---

# Configuration {#configuration}

This extension ships its frontend TypoScript and its backend page TSconfig in
two forms: as TYPO3 **site sets**, and as classic **static templates** plus
**page TSconfig files** that are selected on a page. Both forms read the very
same files, so they configure an installation identically.

Pick one of them per site and stay with it — see
[Do not combine both](#one-mechanism-per-site) for what happens otherwise.

## What the sets contain {#configuration-components}

This extension ships six content elements, so it ships six component sets and
one aggregate set that depends on all of them.

All six are driven by one Extbase plugin, so they share one TypoScript block,
`plugin.tx_academicpersons`. That block is shipped once, in
`Configuration/TypoScript/Default/`, and every component includes it.
Which component sets a site names therefore decides which content elements the
backend offers, not how much TypoScript is loaded.

| Set | Delivers |
| --- | --- |
| `fgtclb/academic-persons-list` | The **Persons List** content element. |
| `fgtclb/academic-persons-list-and-detail` | The **Persons List and Detail** content element. |
| `fgtclb/academic-persons-detail` | The **Persons Detail** content element. |
| `fgtclb/academic-persons-card` | The **Contacts** content element, and the FlexForm restriction that hides the list, sorting and pagination fields for it. |
| `fgtclb/academic-persons-selected-profiles` | The **Profiles: Selected Profiles** content element. |
| `fgtclb/academic-persons-selected-contracts` | The **Profiles: Selected Contracts** content element. |
| `fgtclb/academic-persons` | Everything above. This is the set to use unless you deliberately want a subset. |
| `fgtclb/academic-persons-default` | The name this extension published before the sets were cut per component. It delivers exactly what `fgtclb/academic-persons` delivers, and is kept so that existing site configurations keep working. |
| `fgtclb/academic-persons-standalone` | Everything the aggregate delivers, plus a `page` object that renders content on a plain Bootstrap page. Meant for an installation without a site package of its own — an alternative to `fgtclb/academic-persons`, never an addition to it. |

Every component set depends on `fgtclb/academic-base-ctype-group`, the set of
**EXT:academic_base** that labels the content element group all academic
extensions sort their elements into.

The site settings of this extension — the detail page, the default grouping,
sorting and pagination of a profile list, the selected letter of the letter
navigation, the crop variants and placeholders of the profile image, the phone
link prefix and the [content element header](#configuration-content-element-header) switch below — are declared with the
aggregate set. A site that depends on a single component set still gets the
shipped defaults, but can only override them in **Site Settings** when
it depends on `fgtclb/academic-persons`.

## The prefix of a phone link target {#configuration-phone-link-prefix}

Every phone number this extension renders is a link, and the number is written
into its `tel:` target without the spaces it is stored with. An
installation that stores phone numbers as extensions only — the part that is
the same for every number left out — has no dialable target that way, and this
setting is what completes it.

-   **plugin.tx_academicpersons.phoneNumbers.telPrefix**

    -   *Type:* string
    -   *Default:* (empty)

    Prepended to the `tel:` target of every phone number, in the list,
    card and selection elements, in the profile detail view and in the contacts
    of a page. The spaces of prefix and number alike are removed from the
    target. The visible link text is not touched: it keeps the number as it is
    stored, without the prefix.

    The prefix is applied unconditionally, so an installation that stores full
    numbers, or a mixture of full numbers and extensions, leaves it empty.

The setting is declared for the site set and as a constant of the shared static
template, with the same default in both — see
[Do not combine both](#one-mechanism-per-site).

## The selected letter of the letter navigation {#configuration-letter-navigation}

The list and list-and-detail elements can show a letter navigation above the
list (**Alphabetical Pagination** in the content element). A letter
without profiles in that list is shown disabled and is not a link, and the
navigation is left out for a list of profiles selected by hand. What the
selected letter does is a setting:

-   **plugin.tx_academicpersons.alphabet.activeLetterResets**

    -   *Type:* boolean
    -   *Default:* 0

    Off, the selected letter is marked as the current one and is not a link.
    On, it is still marked as the current one, and links back to the list
    without a letter — the target of **A-Z**. A visually hidden "show
    all profiles" tells assistive technology where the link leads.

The setting is declared for the site set and as a constant of the shared static
template, with the same default in both.

## View modes {#configuration-view-modes}

The list, list-and-detail, selected profiles and selected contracts elements
render their profiles in a view mode. Two fields of the content element choose
it:

-   ****View Mode Default****

    The mode the element renders: **Tiles**, the grid every list
    rendered so far, or **Table**. The stored value of the tiles is
    still `list`, so a content element saved before needs no migration, and
    one saved without the field renders the tiles as well.

-   ****View Mode Toggle****

    Offers the visitor a switch between the allowed modes above the list - when
    at least two are allowed. The active mode is marked as current. Off, a mode
    the request asks for is ignored and the default renders.

The card element shares the fields with the list, hides both, and renders tiles
whatever it stores.

Two settings decide which modes exist and what the table shows:

-   **plugin.tx_academicpersons.viewMode.allowed**

    -   *Type:* string
    -   *Default:* list,table

    The modes the elements may render, comma separated. Neither the default of
    a content element nor the request of a visitor renders a mode outside this
    list: such a default falls back to the tiles - or to the first allowed mode
    where the tiles are not allowed - and such a request to the default. A mode
    is a plain name, a lowercase letter followed by letters and digits; an entry
    of any other shape is ignored.

-   **plugin.tx_academicpersons.table.columns**

    -   *Type:* string
    -   *Default:* name,position,emailAddresses,phoneNumbers,room

    The columns of the table, comma separated, in this order. The shipped
    columns are `name`, `position`, `organisationalUnit`,
    `emailAddresses`, `phoneNumbers` and `room`. The name links to the
    detail view; the contract columns show the value of every contract the
    element shows for the profile, one per line.

    The fields of the content element (**Show only selected Fields**)
    apply to the table as they apply to the tiles: while the element names
    fields there, a contract column whose field it does not name -
    `contracts.room` for `room` \- is left out. The name, and a column of
    your own, stay.

Both settings are declared for the site set and as constants of the shared
static template, with the same default in both. A mode of your own is a partial
and an entry in the allowed modes, see
[adding a view mode](../Templates/Partials/Index.html#templates-view-modes-own); its URL is described in
[the route enhancers](RouteEnhancers/Index.html#configuration-route-enhancers-view-modes).

## Filters for visitors {#configuration-visitor-filters}

A visitor can narrow the list and list-and-detail elements to one function type
or one organisational unit, where the element allows it. Two fields of the
content element, on the sheet **Settings** below **Function
Types**, switch the filters on. Both are off by default, and a list that does
not switch them on shows what it showed before:

-   ****Visitors may filter by function type****

    The list takes a function type from the request and shows only the profiles
    with a contract of that type.

-   ****Visitors may filter by organisational unit****

    The same for an organisational unit. The unit has to match exactly, a
    contract in a unit below it does not count.

With both filters set, the function type and the unit have to be on the same
contract: a person who is a professor in one unit and a lecturer in another is
not listed among the professors of the second one. A profile with several
matching contracts is listed once, and the pagination and the letter
navigation count only the profiles the filter leaves.

The options of a filter are the function types or units the element is
restricted to in **Function Types** and **Organisational
Units**, or all of them while it is restricted to none, ordered by name. A
visitor can therefore never see more than the editor chose. The list ignores a
value that is not one of the options: a number of a record that does not exist
or is hidden, a record outside the restriction, anything that is not a whole
number, and any value while the field is off. It then renders as if no filter
had been given. A manual selection of profiles ignores both filters.

The request carries the uid of the record in the default language, as the
demand arguments `functionTypeFilter` and `organisationalUnitFilter` of the
plugin. The list renders a form above the profiles with one choice per
filter, and its submission leads to the URL of the filtered list, see
[Filtered lists](RouteEnhancers/Index.html#configuration-route-enhancers-filters). The list template receives the
options as `filterOptions`, see [The options of the visitor filters](../Templates/Partials/Index.html#templates-visitor-filters). The page and
letter links keep an active filter.

The filters select profiles, and do not change which contracts of a profile are
shown. **Only contracts of the selected organisational units and
function types** below applies the restriction of the element, not the choice of
the visitor. While **Only contracts valid today** is on, a filter finds a
profile only through a contract valid today, see
[Which contracts a profile shows](#configuration-contract-display).

The card element shares the fields with the list and hides both.

## Which contracts a profile shows {#configuration-contract-display}

A profile has one or more contracts, sorted by the editor. Every view shows all
of them unless it is told otherwise.

**The list and list-and-detail elements** offer three fields in their plugin
options, on the sheet **Settings** below the [filters for visitors](#configuration-visitor-filters):

-   ****Contracts per profile****

    All contracts (the default), or only the first one.

-   ****Only contracts of the selected organisational units and function types****

    Leaves out the contracts of a profile in other units or with other function
    types than the element is restricted to. Without such a restriction the
    option has no effect. Without the option, the restriction selects the
    profiles and every contract of a selected profile is shown, as before.

-   ****Only contracts valid today****

    Leaves out the contracts that have ended or not started yet. While the
    element is restricted to organisational units or function types, or a
    visitor filters it, the option also decides which contracts select a
    profile: only one valid today does. A profile whose only matching contract
    has ended is not listed, rather than listed without that contract, and the
    pagination and the letter navigation count the same profiles. A list
    without such conditions selects nobody by a contract and still lists a
    profile whose contracts have all ended, without a contract.

**The card and selected-profiles elements** offer **Contracts per
profile** and **Only contracts valid today**. They select their profiles
by hand and apply no unit or function type restriction, so there is nothing for
the contracts to match. The card hides the field in its form; a value stored
while the element was a list stays in effect after a switch to the card, as a
detail page stored while it was a list does.

**The detail view** \- of the detail and the list-and-detail elements - is
configured in `Settings.yaml`, once for the installation rather than per
content element. Its two blocks rendered from the contracts take a key each for
the same two choices; see [The contracts of the position and contact blocks](Sections/Index.html#configuration-sections-profile-contracts):

**EXT:my_sitepackage/Configuration/AcademicPersons/Settings.yaml**

```yaml
profile:
  details:
    position:
      onlyValid: true
    contact:
      contracts: first
```

**The selected-contracts element** and the contacts element of
**EXT:academic_contacts4pages** show the contract that was chosen,
whatever the options say, even one that has ended.

The options apply in a fixed order: the unit and function type filter, then
validity, then "first". "Only the first" is the first of the contracts left, in
the editor's order of the profile's contracts, so a list restricted to one unit
shows each profile's first contract in that unit.

Validity is a matter of days. A contract is valid from the first day of
**Valid from** through the last day of **Valid to**; an empty
date does not limit it on that side, and no setting changes that. "Today" is the
date the page is rendered for, in the time zone of the installation - a date
simulated in the frontend preview of a backend user counts.

### The page cache follows the validity {#configuration-contract-display-cache}

A cached page would keep showing a contract that ended yesterday until its cache
entry expires. On TYPO3 v13 a page with profiles expires after 24 hours at the
latest, whatever `config.cache_period` says, because every record
Extbase loads limits the page to that; on TYPO3 v14 a page without
`config.cache_period` is cached for a year. So while "only contracts
valid today" applies, a page is cached no longer than until the next midnight on
which a contract that passes the unit and function type filter ends - the day
after its **Valid to** \- or starts. While the option also decides
which contracts select the profiles of a list, the same holds for every
contract that meets the restriction and the visitor filters of the list, so a
profile whose contract starts tomorrow is listed tomorrow, though nothing of it
was rendered today. Those contracts are read from the storage pages of the
list. The limit is set only on the cache entry of the page that rendered those
contracts or the list, only when that date comes before the regular expiry, and
never when no validity option applies.

## Restrict the backend contract selects {#configuration-contract-select-storage-scope}

Two backend fields let an editor pick a contract: the **Contract** of a
page contact record of **EXT:academic_contacts4pages**, and
**Selected contracts** of the **Profiles: Selected Contracts**
content element. Both offer every contract of the installation — in an
installation with more than one site, that is every site's contracts, each
labelled with a person's name.

Page TSconfig restricts a field to the pages the contracts of that page tree are
stored on. Page TSconfig is inherited down the page tree, so each site
configures its own folders on its root page.

The setting is opt-in, and without it nothing changes. Respecting the Extbase
storage page instead is deliberately not done: a page tree without an explicitly
configured storage page would get an empty select and no error.

-   **itemsProcFunc.storagePids**

    -   *Type:* string, a comma-separated list of page uids
    -   *Default:* (empty)

    The pages a contract has to be stored on to be offered. Empty — the default
    — offers every contract of the installation.

-   **itemsProcFunc.recursive**

    -   *Type:* integer
    -   *Default:* 0

    How many levels below each listed page are included. The default `0` uses
    the listed pages themselves. A hidden folder is included as well, because a
    storage folder is regularly hidden.

Set them on the page record of the site root, tab **Resources**, field
**Page TSconfig**. The path of the FlexForm field is the longer one: it
carries the data structure identifier and the sheet, and the dot in the
element's name is escaped.

**Page TSconfig of a site root**

```typoscript
# The "Contract" field of a page contact record.
TCEFORM.tx_academiccontacts4pages_domain_model_contact.contract.itemsProcFunc {
    storagePids = 42,84
    recursive = 1
}

# The "Selected contracts" field of the content element.
TCEFORM.tt_content.pi_flexform.academicpersons_selectedcontracts.sDEF.settings\.selectedContracts.itemsProcFunc {
    storagePids = 42,84
    recursive = 1
}
```

A contract the record already references stays selectable even when it is stored
outside the listed pages. Without that, opening and saving the record would drop
the relation, because a select offers no other source for its value.

The restriction is applied before
`\FGTCLB\AcademicBase\Event\ModifyTcaSelectFieldItemsEvent` is
dispatched, so a listener of that event still has the last word.

## Profiles that are not public {#configuration-hidden-profiles}

A profile whose **Visible** switch is off, the `hidden` field of
the record, is left out of every public output: the lists with their counts,
letters and pages, the selected profiles, and the detail page, which answers
with the page-not-found response of the site. The field is shared by every
language of the profile. With [`fgtclb/academic-persons-edit`](https://packagist.org/packages/fgtclb/academic-persons-edit)
installed, owners switch it themselves in the profile editor, and the
documentation of that extension describes how an installation takes the switch
away from them.

An internal directory, one that only logged-in visitors reach, lists those
profiles as well. Put the list and the detail element on a page restricted to a
frontend user group and switch **Show hidden records** on in both. Two
limits apply:

-   The directory lists every hidden profile, whether its owner or an editor
    hid it. An installation that has to tell the two apart needs a field of its
    own.
-   **EXT:academic_contacts4pages** never shows a hidden profile as a
    contact of a page, whatever **Show hidden records** says.

Start time, end time and the frontend user groups of a profile keep applying in
both directories.

## Contracts that are not public {#configuration-hidden-contracts}

A contract has one visibility, its **Visible** switch, the `hidden`
field of the record. A hidden contract is left out of the lists, the detail
view and the selected contracts, together with its position, addresses, e-mail
addresses and phone numbers, while the profile itself is still shown. The field
is shared by every language of the contract. With
[`fgtclb/academic-persons-edit`](https://packagist.org/packages/fgtclb/academic-persons-edit) installed, owners show and hide their
contracts themselves with the hide action of each contract row.

**Show hidden records** of the selected contracts element shows hidden
contracts as well, for an internal directory.

Until 3.0 a contract also had a **Show this contract online?** toggle,
which no public view read. It is removed, see
[Breaking: The contract field "publish" has been removed](../Changelog/3.0/Breaking-ContractPublishFieldRemoved.html#breaking-contract-publish-field-removed).

## The crop variants of the profile image {#configuration-crop-variants}

The image cropper of a profile image offers three crop variants. A template
requests one by its name, through the `cropVariant` argument of
`<f:image>` or of the image partial of **EXT:academic_base**:

| Name | Aspect ratio |
| --- | --- |
| `default` | Free, 16:9, 3:2, 4:3 and 1:1 |
| `square` | 1:1 |
| `portrait` | 3:4 |

`default` is the variant TYPO3 offers when a file field configures none, with
the same ratios, and the templates of this extension render it unless a site
chooses another one per view, see [The crop variant of a view](../Templates/ProfileImage/Index.html#templates-profile-image-crop-variant).
A crop an editor stored before the update is stored under that name and keeps
its meaning.

An image stores a crop for the new variants once an editor opens it in the
backend form and saves the record. Until then a template that requests `square`
or `portrait` renders the image uncropped. Where the image already has a crop
for `default`, the cropper starts `square` from that crop, fitted into its
ratio, and `portrait` from the whole image, fitted and centred; an image without
a crop starts both from the whole image.

A site that does not want a variant disables it in TCA, on this field only:

**Configuration/TCA/Overrides of the site package**

```php
$GLOBALS['TCA']['tx_academicpersons_domain_model_profile']['columns']['image']['config']['overrideChildTca']['columns']['crop']['config']['cropVariants']['portrait']['disabled'] = true;
```

Page TSconfig is not the way to do that.
`TCEFORM.sys_file_reference.crop.config.cropVariants` reaches every image below
the page it is set on, and on an image field that configures no variants of its
own it leaves the cropper with no variant at all, not even `default`.

A project that defines crop variants of its own for the profile image does so at
the same path. A variant it sets by name replaces the one of the same name and
leaves the others; assigning the whole array replaces all of them.

Crop variants a project configures on `sys_file_reference` for every image are
merged with these on the profile image: the values of this extension win key by
key, and a ratio the project adds to a variant of the same name stays. A project
that restricted `default` to a fixed ratio that way therefore finds all the
ratios of the TYPO3 default offered on the profile image again, and the free
ratio preselected on an image without a crop.

## The header of the content elements {#configuration-content-element-header}

The header and the subheader an editor enters on a **Persons List**,
**Persons Detail**, **Persons List and Detail**,
**Contacts**, **Profiles: Selected Profiles** or
**Profiles: Selected Contracts** content element are rendered by the
content element layout of the site, as for any other content element. The
layouts of **EXT:fluid_styled_content** and of the bootstrap package do
that, and the plugins render no header of their own.

A site whose content element layout renders no header, because its element
templates render it instead, lets the plugins render it:

**TypoScript constants**

```typoscript
plugin.tx_academicpersons.renderContentElementHeader = 1
```

On a site that uses the site set, that is the site setting **Render the
content element header in the plugins** of `fgtclb/academic-persons`. The
templates then render the header partial of **EXT:fluid_styled_content**
above their output, for every header layout except **Hidden**. Do not
switch it on where the layout renders the header: the header then appears twice.

The extension does not require **EXT:fluid_styled_content**. It adds the
partial path of that extension below every other one, so a site package that
ships a `Header/All.html` of its own renders that one instead, and a site
without **EXT:fluid_styled_content** provides the partial that way.

For the header layout **Default**, the partial takes the heading level
from `plugin.tx_academicpersons.settings.defaultHeaderType`, which
is mapped from the constant `styles.content.defaultHeaderType` of
**EXT:fluid_styled_content**. A site that does not include the
TypoScript of **EXT:fluid_styled_content** sets the setting itself;
without it, such a header renders as an empty `<header>` element.

## The content elements are hidden by default {#configuration-hidden-by-default}

**EXT:academic_persons** hides all six of its content elements for the
whole installation and brings them back per component. Whichever of the two
mechanisms below you use, it is what makes an element selectable in the backend
again — without one of them the content element is not offered, and existing
records keep rendering.

> [!WARNING]
> This changed in version 2.4. Before it, all six elements were selectable on
> every page of every installation. Read
> [Breaking: Site sets and static templates have been restructured](../Changelog/2.4/Breaking-SiteSetsAndStaticTemplatesRestructured.html#breaking-site-sets-and-static-templates-restructured) before upgrading:
> opening an existing record on a page that does not include the page
> TSconfig of its component can rewrite the type of that record.

## Include the site set {#site-set}

Add the set to the `config.yaml` of the site that should offer the content
elements:

**config/sites/my-site/config.yaml (diff)**

```diff
 base: 'https://example.com/'
 rootPageId: 1
+dependencies:
+  - fgtclb/academic-persons
```

See also [TYPO3 Explained, Using a site set as dependency in a site](https://docs.typo3.org/m/typo3/reference-coreapi/main/en-us/ApiOverview/SiteHandling/SiteSets/Index.html#site-sets-usage).

## Include static templates {#static-templates}

For an installation that still configures its frontend through
`sys_template` records, the same files are registered as static templates
and as selectable page TSconfig files.

> [!TIP]
> On TYPO3 v13 and v14 we recommend the site set — and if you use it, do not
> press the backend button **Create a root TypoScript record** on that
> site. The `sys_template` record it creates carries the flag
> **Clear** for constants and setup, and that flag discards everything
> the site sets contributed. An installation that is already in that state
> gets its configuration back by selecting the static templates below in that
> very record.

### Include static TypoScript {#static-typoscript}

Edit the `sys_template` record of the site root and add the entry to
**Include static (from extensions)**:

| Entry | Delivers |
| --- | --- |
| **Academic Persons: All components (academic_persons)** | Every component this extension ships, in one entry. This is the entry to use. |
| **Academic Persons: Shared plugin settings (academic_persons)** | The shared `plugin.tx_academicpersons` block on its own. This is what installations selected before version 2.4, then named **Academic Persons Settings**. The stored value did not change, so such a record keeps working untouched. |
| **Academic Persons: Standalone page (academic_persons)** | Everything **All components** delivers, plus the `page` object of the standalone flavour. Do not select it on a site that has a site package of its own. |

There is one further entry per component —
**Academic Persons: Profile list**,
**Academic Persons: Profile list and detail**,
**Academic Persons: Profile detail**,
**Academic Persons: Profile card**,
**Academic Persons: Selected profiles** and
**Academic Persons: Selected contracts**. They exist so that the static
mechanism has the same shape as the sets. Because all six components share one
TypoScript block, each of them delivers the same thing, and selecting more than
one of them changes nothing.

### Include static page TSconfig {#static-pagetsconfig}

This is the half that decides which content elements the backend offers. Edit
the page record of the site root, tab **Resources**, field
**Page TSconfig**, and add the entries for the content elements the page
tree should offer:

| Entry | Delivers |
| --- | --- |
| **Academic Persons: All components (academic_persons)** | Every component this extension ships, in one entry. |
| **Academic Persons: Profile list (academic_persons)** | Makes the **Persons List** content element selectable, and configures its entry in the new content element wizard. |
| **Academic Persons: Profile list and detail (academic_persons)** | The same for **Persons List and Detail**. |
| **Academic Persons: Profile detail (academic_persons)** | The same for **Persons Detail**. |
| **Academic Persons: Profile card (academic_persons)** | The same for **Contacts**, plus the FlexForm restriction of that element. |
| **Academic Persons: Selected profiles (academic_persons)** | The same for **Profiles: Selected Profiles**. |
| **Academic Persons: Selected contracts (academic_persons)** | The same for **Profiles: Selected Contracts**. |

The setting is inherited by every page below the one it is set on.

## Do not combine both {#one-mechanism-per-site}

A site that uses the site set **and** the static template reads the shipped
files twice. The site set is applied before the `sys_template` record, so
the second read happens after the site settings and after
`config/sites/<site>/constants.typoscript` — and it resets every constant
the extension ships a default for back to that default.

Nothing else is damaged: the **Constants** and **Setup** fields
of the `sys_template` record, the page TSconfig of a page and the page
TSconfig files selected on a page are all applied afterwards and still win. Use
one mechanism per site and the question does not arise.

## Search, permissions and the wizard {#configuration-integration}

The [Integration chapter of academic_base](https://docs.typo3.org/p/fgtclb/academic-base/main/en-us/Integration/Index.html)
covers what an installation runs beside the academic extensions: an index
queue for the profiles of this extension with EXT:solr, the tables, fields
and content types an editor group needs as a preset for b13/permission-sets,
and how to move, rename or order the academic content elements in the new
content element wizard.

-   [General configuration](General/Index.html#general-configuration)
-   [Profile sections](Sections/Index.html#profile-sections)
-   [Validation settings](Validations/Index.html#validation-settings)
-   [Frontend user synchronisation](FrontendUserSync/Index.html#frontend-user-synchronisation)
-   [Profile cleanup](ProfileCleanup/Index.html#profile-cleanup)
-   [Managed fields](ManagedFields/Index.html#managed-fields)
-   [Route enhancers](RouteEnhancers/Index.html#route-enhancers)
-   [Labels](Labels/Index.html#labels)
