---
title: "Profile sections"
manual: "Academic Profiles"
version: "main"
source: "Configuration/Sections/Index.rst"
rendered: "2026-10-02T15:38:26+00:00"
---

# Profile sections {#configuration-sections}

`Configuration/AcademicPersons/Settings.yaml` describes a profile in six
top-level maps. It ships with **academic_persons**, which owns the
records and their TCA, and it is the one file the backend record editor, the
public detail view and the editing frontend of [EXT:academic_persons_edit](https://extensions.typo3.org/extension/academic_persons_edit) read.

| Map | Describes |
| --- | --- |
| `profile` | The public detail layout (`structure` and `details`), and every directly editable profile property with its section, control and validators. |
| `special` | The components of the editing frontend that are not one property: the composed display name, the image and the synchronisation switch. |
| `contracts` | The contract fields, and the address, email and phone sections a contract owns. |
| `documentSections` | The sortable lists attached to a profile: the seven timeline entry types and the contracts. |
| `frontendUserSync` | Which `fe_users` column feeds which property when profiles are synchronised from frontend users, see [Frontend user synchronisation](../FrontendUserSync/Index.html#configuration-frontend-user-sync). |
| `managedFields` | Which fields are read-only in the backend on the records a synchronisation wrote, see [Managed fields](../ManagedFields/Index.html#configuration-managed-fields). |

The order of every map and list is preserved and is what the editing frontend
renders. The [validator flags](../Validations/Index.html#configuration-validations) are documented
on their own page.

> [!WARNING]
> **Attention**
>
> The syntax of this file is still considered experimental and may change in
> a future release.

## The profile map {#configuration-sections-profile}

Two keys describe the public layout, everything else is a field:

```yaml
profile:
  structure:
    left:
      - menuSections
    right:
      - headline
      - position
      - profileImage
      - contact
      - subline
      - profileEntries
      - menuSectionsDatas
  details:
    headline:
      - title
      - firstName
      - middleName
      - lastName
    subline: 'LLL:EXT:academic_persons/Resources/Private/Language/locallang.xlf:detail.subline'
  gender:
    section: information
    fieldType: select
    renderType: select
    validators:
      - required
  firstName:
    section: information
    fieldType: input
    renderType: text
    validators:
      - readonly
      - disabled
    helptext: 'LLL:EXT:academic_persons/Resources/Private/Language/locallang.xlf:helptext.firstName'
  miscellaneous:
    section: aboutme
    fieldType: textarea
    renderType: ckeditor
    characterLimit: 1000
    validators:
      - html
```

-   **`structure`**

    The layout columns and the ordered elements in each column. The shipped
    detail template renders `left` as the desktop navigation and `right` as
    the main content; on mobile, the `left` elements are inserted again
    directly before `subline`.

-   **`details`**

    Per element, the ordered profile properties, the relation map, the label
    reference or the special renderer it renders. Supported elements are
    `menuSections`, `headline`, `position`,
    `profileImage`, `contact`, `subline`,
    `profileEntries` and `menuSectionsDatas`; an unknown element
    renders nothing. `position` and `contact` take the special
    renderer `special: datasFromContracts`, and choose their contracts
    with `contracts` and `onlyValid` \- see
    [The contracts of the position and contact blocks](#configuration-sections-profile-contracts). `position` also
    lists what its line shows, see
    [What the position line shows](#configuration-sections-profile-position-fields). `menuSections` lists
    stable navigation identifiers and `menuSectionsDatas` maps each of
    them to the profile relation it shows.

### The contracts of the position and contact blocks {#configuration-sections-profile-contracts}

A block rendered with `special: datasFromContracts` chooses which of the
profile's contracts it renders. The shipped file states the defaults:

```yaml
profile:
  details:
    position:
      special: datasFromContracts
      contracts: all
      onlyValid: false
      fields:
        - position
    contact:
      special: datasFromContracts
      contracts: all
      onlyValid: false
```

-   **`contracts`**

    `all` renders every contract, `first` only the first in the editor's
    order that `onlyValid` leaves. Anything else is `all`.

-   **`onlyValid`**

    `true` leaves out the contracts that have ended or not started yet, and
    limits the page cache lifetime as described in
    [The page cache follows the validity](../Index.html#configuration-contract-display-cache). A boolean, or a value PHP
    reads as one (`1`, `'true'`, `'yes'`, `'on'`); anything else is
    `false`.

The two blocks are configured one by one, so a profile page may list every
position and the contact data of the first contract only. The unit and function
type filter of the list elements has no counterpart here: the detail view shows
one profile, not a restricted list. See [Which contracts a profile shows](../Index.html#configuration-contract-display)
for how the options of the content elements relate.

### What the position line shows {#configuration-sections-profile-position-fields}

`profile.details.position.fields` lists what the position line shows of
each contract, in this order. Three values are accepted:

-   **`position`**

    The position text of the contract.

-   **`functionType`**

    The name of the contract's function type. A profile with the gender
    `ms` gets the female name and one with `mr` the male name, where the
    function type has one. Every other profile, and a function type without
    the gendered name, gets the general name.

-   **`organisationalUnit`**

    The display text of the contract's organisational unit, or its unit name
    where the display text is empty.

The shipped value is `[position]`, the line as it was before the key
existed. Other values are dropped, and a list that keeps none of the three is
the shipped value. A contract that has none of the listed values gets no line.

Settings files merge key by key, so a site package that wants the function
type next to the position states only the list:

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

```yaml
profile:
  details:
    position:
      fields:
        - position
        - functionType
```

Each value is rendered in an element of its own, with the classes
`academic-persons-detail__position-part` and
`academic-persons-detail__position-part--<value>`. The shipped stylesheet
separates them with a comma, and a site package changes that in CSS.

### How the layout is rendered {#configuration-sections-profile-rendering}

The shipped `Resources/Private/Templates/Profile/Detail.html` receives
the two keys as `publicProfile` and dispatches every identifier of
`structure` to a partial of the same name below
`Resources/Private/Partials/Profile/PublicProfile/`:

| Element | `details` entry | Renders |
| --- | --- | --- |
| `menuSections` | Ordered navigation identifiers | One link per identifier whose relation has records |
| `headline` | Ordered profile properties | The non-empty ones as the parts of the heading |
| `position` | `special: datasFromContracts` | The values `fields` lists of every contract `contracts` and `onlyValid` select |
| `profileImage` | Ordered image properties | Every non-empty one, as a figure |
| `contact` | `special: datasFromContracts` | Email addresses, phone numbers, postal addresses, location with room, and office hours of every contract `contracts` and `onlyValid` select, see [Office hours in the contact block](#configuration-sections-profile-office-hours) |
| `subline` | An `LLL:EXT:` reference | The translated heading, and the point before which the `left` elements are repeated below the large breakpoint |
| `profileEntries` | Ordered rich text properties | The non-empty ones as fold-out entries |
| `links` | Ordered link properties | The non-empty ones, each with its companion title property (`website` with `websiteTitle`) as the link text |
| `menuSectionsDatas` | Navigation identifier to relation map | One timeline section per identifier whose relation has records |

Overriding a partial changes how an element renders, overriding
`profile` changes what renders and where. The years of a timeline entry
are printed as they are stored - a single year, a range, or an open range
prefixed with a "since" or "till" label - and nothing about them is locale
dependent.

Below the large breakpoint the elements of the `left` column are
rendered a second time, directly before the `subline` element of the
`right` column. A layout without `subline` in `right`
therefore has no mobile navigation.

The view is a content element and renders no `<main>`, no `<aside>` and no
`<h1>` \- a page may carry two profile plugins, and those belong to the page
template. Its headings start at `<h2>` for the headline, with the block
headings one level below it.

The template loads the stylesheet
`Resources/Public/Css/frontend/profile-detail.css` and the module
`@fgtclb/academic-persons/frontend/profile.js` through the asset collector.
The module toggles the fold-out entries, keeps the sticky navigation below a
page header with the id `page-header` and, when the site loads Bootstrap,
marks the section in view through its ScrollSpy. The icons of the contact rows
and the fold-out entries are the identifiers `academic-persons-envelope`,
`academic-persons-phone`, `academic-persons-address`,
`academic-persons-room`, `academic-persons-clock`,
`academic-persons-detail-plus` and
`academic-persons-detail-minus` of `Configuration/Icons.php`; a site
package re-registers an identifier to replace the glyph. They are [Bootstrap
Icons](https://icons.getbootstrap.com/), and their MIT licence ships beside
them in `Resources/Public/Icons/LICENSE-bootstrap-icons.txt`.

The colours of the view are custom properties declared on the
`.academic-persons-detail` root element - `--academic-persons-detail-text`,
`--academic-persons-detail-border` and the two accents. Redeclaring them on
that class in the site's own stylesheet is how the view is themed; the shipped
stylesheet touches nothing outside that element.

> [!NOTE]
> The navigation of the `left` column is sticky. A theme that wraps its
> content sections in `overflow: hidden` clips it, and the extension
> deliberately does not override that from its own stylesheet. Lift it in the
> site's stylesheet on the wrapper that has it, for example:
>
> ```css
> body:has(.academic-persons-detail) .my-theme-section {
>     overflow: unset;
> }
> ```

#### Office hours in the contact block {#configuration-sections-profile-office-hours}

A contract with office hours gets a row of its own in the contact block, after
the location and room, with the label "Office hours" (`detail.officeHours`).
A contract without them gets no row. The row carries the class
`academic-persons-detail__contact-row--office-hours`, so a site that does not
want it hides it in its stylesheet.

The editor of `EXT:academic_persons_edit` stores office hours as HTML, the
backend form and an import as plain text. The row turns line breaks into
`<br>` and then passes the value through the core HTML sanitizer, the
default build of `<f:sanitize.html>`. Paragraphs, lists, emphasis and
links are kept. Event handler attributes are removed, and an element the
sanitizer does not allow, a script among them, is printed as escaped text and
never runs. A plain text value keeps its lines. HTML from the editor carries no
line breaks between its blocks, so it renders as it was written.

Plain text is read as HTML as well. A `<` in it starts a tag for the
sanitizer, so `10:00 < 12:00` loses the `<` and `Room <A 1.23>` renders
as an empty link. Write such values without angle brackets.

The contract fields of the list, list and detail, card, selected profiles and
selected contracts elements, and of the contacts element of
`EXT:academic_contacts4pages`, render office hours the same way, when office
hours are among their fields to show.

### What an override of the detail template loses {#configuration-sections-detail-override}

Until 2.4 `Templates/Profile/Detail.html` was the view: it rendered the
image, the contact data and every timeline section itself. Since 3.0.0 it is a
dispatcher over the `structure` map, and the eleven partials below
`Partials/Profile/PublicProfile/` are what renders.

**A project that overrides the template keeps rendering its own copy.** Nothing
looks broken, and two things are silently gone:

-   **The configurable layout.** `profile.structure` and
    `profile.details` are handed to the template as `publicProfile` and
    are read by the new partials only, so changing them has no effect at all
    while the old template renders.
-   **Three partials the detail view no longer renders.**
    `Partials/Profile/Header.html` and
    `Partials/Profile/SectionHeader.html` are still shipped and still
    rendered - by the list and card views, and by the profile editing view of
    **academic_persons_edit** \- so an override of one of them made for
    the *detail* view no longer reaches it.
    `Partials/Profile/DataHeader.html` had the detail view as its only
    caller and is **deleted**: a project template that still renders
    `Profile/DataHeader` fails at render time rather than rendering nothing.
    [Breaking: The partials of the detail view change](../../Changelog/3.0/Breaking-PublicProfileDetailPartials.html#breaking-public-profile-detail-partials) has the migration.

Adopt the new template instead, and move the project's changes into the partial
of the element they belong to: they are one file per element, and overriding one
of them is what [How the layout is rendered](#configuration-sections-profile-rendering) describes.

### The fields {#configuration-sections-fields}

Every other key is a field, and fields share one shape across
`profile`, `contracts.fields` and
`contracts.contactSections.<section>.fields`:

| Key | Meaning |
| --- | --- |
| `section` | Profile fields only. Fields with the same section are grouped and rendered together, in file order; the first field of a section decides where the section appears. |
| `propertyName` | The domain and form data property, when it differs from the key. Optional. |
| `fieldName` | The database column, when it differs from the underscored property name. Optional. |
| `fieldType` | `input`, `select`, `textarea` or `check`. Describes the frontend control; **the TCA column keeps the type its TCA file declares**. |
| `renderType` | The renderer of the editing frontend: `text`, `select`, `checkbox`, `email`, `phone`, `date`, `combinedLink` or `ckeditor`. |
| `validators` | The [flag list](../Validations/Index.html#configuration-validations-flags). |
| `characterLimit` | Rich text fields (`renderType: ckeditor`) only: the maximum number of readable characters. Checked on the server, never copied into the TCA. |
| `helptext` | An `LLL:EXT:` reference rendered next to the control; for contract and contact fields also literal text. A translation domain reference of TYPO3 v14 does not resolve here, see [Labels](../Labels/Index.html#configuration-labels). |
| `autocomplete` | Contract and contact fields only: an HTML `autocomplete` token. |
| `options` | Contract selects only: `organisationalUnits`, `functionTypes` or `locations`. |
| `custom` | Profile fields only: `true` declares a project field, a column a site package adds to the profile table and makes editable in the profile editor. Its `fieldName` is required, and its key is its property name. See [project fields](https://docs.typo3.org/p/fgtclb/academic-persons-edit/main/en-us/Configuration/Settings/Index.html#configuration-editor-project-fields) of academic_persons_edit. |

A field is dropped silently when it has no section (profile fields), no
`fieldType` or no `renderType`. Removing a field from the file
removes it from the editing frontend and from the validation; it never removes
a column or stored data. Apart from a project field, the settings describe
columns and properties the extensions ship and create none.

## The special map {#configuration-sections-special}

```yaml
special:
  title:
    type: special
    renderType: title
    fields:
      - title
      - firstName
      - middleName
      - lastName
  image:
    type: special
    renderType: cropper
  skipSync:
    type: special
    fieldType: check
    renderType: checkbox
  hidden:
    type: special
    fieldType: check
    renderType: checkbox
```

`title` composes the display name from the listed profile properties,
`image` is the profile image, `skipSync` the switch that keeps
a profile out of the synchronisation from its frontend user, and
`hidden` the owner's switch **Show my profile publicly**, see
[Profiles that are not public](../Index.html#configuration-hidden-profiles). A special entry
with a `fieldType` and without composed `fields` addresses one
profile column directly and takes part in the profile validation; the other
two do not.

## The contracts map {#configuration-sections-contracts}

```yaml
contracts:
  label: 'LLL:EXT:academic_persons/Resources/Private/Language/locallang_tca.xlf:tx_academicpersons_domain_model_profile.columns.contracts.label'
  type: contracts
  fieldName: contracts
  rowFields:
    - position
  actions:
    - view
    - down
    - up
    - delete
    - edit
  fields:
    position:
      fieldType: input
      renderType: text
      validators:
        - required
    organisationalUnit:
      fieldType: select
      renderType: select
      options: organisationalUnits
    validFrom:
      fieldType: input
      renderType: date
      validators:
        - required
        - date
  contactSections:
    emailAddresses:
      fields:
        emailAddress:
          propertyName: email
          fieldName: email
          fieldType: input
          renderType: email
          autocomplete: email
          validators:
            - required
            - email
        emailAddressType:
          propertyName: type
          fieldName: type
          fieldType: select
          renderType: select
```

`fields` are the contract fields in editor order. The three contact
sections - `physicalAddresses`, `emailAddresses` and
`phoneNumbers` \- each carry their own `fields` map. Their keys
are unique across the file, which is why `emailAddress` names the
`email` property and column and each `<section>Type` key names the
`type` property of its own record.

`label`, `type`, `fieldName`, `rowFields` and
`actions` complete the `contracts` entry of the document sections
below.

## The document sections {#configuration-sections-documents}

```yaml
documentSections:
  contracts:
    type: contracts
  publications:
    label: 'LLL:EXT:academic_persons/Resources/Private/Language/locallang_tca.xlf:tx_academicpersons_domain_model_profile.columns.publications.label'
    type: publication
    fieldName: publications
    rowFields:
      - year
      - title
    actions:
      - view
      - down
      - up
      - delete
      - edit
    validators:
      title:
        - required
      link:
        - url
      from:
        - number
      to:
        - number
      year:
        - required
        - number
      description:
        editor:
          limit: 500
          type: ckeditor
```

Each key is a stable section identifier; the map order is the display order.

| Key | Meaning |
| --- | --- |
| `label` | An `LLL:EXT:` reference for the section heading. |
| `type` | The record type of the rows, i.e. the `type` of the profile information records. `contracts` is the reserved value for the contract section, which takes everything it does not declare from the top-level `contracts` map. |
| `fieldName` | The profile relation the rows hang off. |
| `readonly` | `true` disables creation and every mutating action; the section still offers `view`. |
| `rowFields` | The values shown in a compact row, in order. Timeline entries support `from`, `to`, `year`, `title` and `description`; contracts support `from`, `to` and `position`. |
| `actions` | The actions offered per row, in order: `view`, `down`, `up`, `delete` and `edit`. An action not listed is not available. Listing both `up` and `down` also enables drag sorting. |
| `validators` | A map from field to flag list, or to a map with `validators`, individual `<flag>: true` entries and an `editor` block. `editor.type: ckeditor` implies the `html` flag and takes a readable-text `limit`; `editor.type: textarea` implies `textarea`. The contract section validates against `contracts.fields` instead. |
| `helptext` | A map from field to an `LLL:EXT:` reference or literal text. |

> [!WARNING]
> `type` and `fieldName` describe the editing frontend. The seven
> profile relations, and the record type each of them selects, are declared
> by the TCA of the profile table since 3.0.0 and are **not** generated from
> this file any more. Renaming either of them for one of the seven shipped
> sections therefore leaves a backend inline column that stores one record
> type and a frontend editor that writes another - the records created in one
> context are invisible in the other. A section of an own record type needs
> its own column in a TCA override of the profile table; the loop over the
> seven relations in
> `Configuration/TCA/tx_academicpersons_domain_model_profile.php` is the
> template for it.

The validators of a timeline section address the record type of that section
only: a required title of publications does not make the title of a lecture
required, neither in the editing frontend nor in the backend, where the flags
land in the `columnsOverrides` of that record type. The field keys `from`,
`to` and `description` are aliases of the `yearStart`, `yearEnd` and
`bodytext` properties (columns `year_start`, `year_end` and
`bodytext`); `year` addresses the `year` property and column.

Unknown row fields and actions are discarded, as are duplicates; both lists
are matched without regard to case.

## Overriding the file {#configuration-sections-override}

The file is collected from **all installed extensions**: every package that
contains `Configuration/AcademicPersons/Settings.yaml` contributes, and
the package loaded later wins per key. The files are merged **recursively**: a
map is merged key by key at any depth, so a site package states only what it
changes and keeps every entry it does not name - including the entries a later
**academic_persons** release adds.

Four rules decide what happens to a value, and they hold at every depth:

| The later file has | Result |
| --- | --- |
| a map | merged key by key with the earlier map |
| a list | replaces the earlier list as a whole, an empty list included |
| a value of another type | replaces the earlier value |
| `null` (`~`) | removes the key, as if no package had configured it |

A list is replaced rather than combined because the entries of a flag list have
no identity to merge by: an override that could only add entries could never
drop `required`. A YAML map whose keys happen to be `0` to `n-1` is a
list as well, and an empty map, `{}`, is the same empty array as an empty
sequence - it clears a map the way `[]` clears a list.

The key order of a merged map is the order of the later file when that file
names **every** key of the earlier map; otherwise the earlier order stays and
the keys only the later file names are appended. A file that names a map
completely therefore decides the display order - and stops deciding it as soon
as a later **academic_persons** release adds an entry the file does not
name, which is the moment to add that entry to the file.

To change the shipped configuration:

1.  Add `Configuration/AcademicPersons/Settings.yaml` to your site
    package.
1.  Make the site package **depend on** **academic_persons** in its
    `composer.json` or `ext_emconf.php`, so that it is loaded after
    it.
1.  Name the keys that differ from
    `EXT:academic_persons/Configuration/AcademicPersons/Settings.yaml`,
    and nothing else:

    ```yaml
    profile:
      # one flag list; the layout, the other fields and every other key of
      # this field stay as shipped
      title:
        validators:
          - required
      # a field the installation does not want at all
      middleName: ~
    documentSections:
      # one label; the record type, relation, rows and actions stay
      lectures:
        label: 'LLL:EXT:my_site/Resources/Private/Language/db.xlf:lectures'
    ```
1.  Flush the TYPO3 caches. The normalised graph is cached in the core cache.

> [!NOTE]
> An entry is **not** removed by leaving it out - leaving it out means "do
> not change it", at every level. Set the key to `~` to remove it, and
> a flag list that is to be empty to `[]`. An override written before
> 3.0, which removed entries by restating a map without them, has to be
> migrated - see [Breaking: Settings files merge recursively](../../Changelog/3.0/Breaking-SettingsFilesMergeRecursively.html#breaking-settings-files-merge-recursively).

To see what an override changes, run
`vendor/bin/typo3 academic:persons:settings:migrate --delta`. It prints,
for every package after **academic_persons**, the smallest file with
the same effect - replacing the package's file with it changes nothing - and
names, as comments, the entries a map the package copied leaves out and
therefore inherits. The **Status** report of EXT:reports lists the same
entries, and the ones a package removes with `~`, under
**Academic Persons**. See [Feature: Settings overrides are reported and shrunk](../../Changelog/3.0/Feature-SettingsOverrideReportAndDelta.html#feature-settings-override-report-and-delta).

There is no TypoScript and no site set equivalent for these settings.

> [!NOTE]
> The backend record editor reads the same maps. Unlocking a field for the
> editing frontend, or requiring one, changes the backend form of that record
> the same way.
