Academic Projects 

Extension key

academic_projects

Package name

fgtclb/academic-projects

Version

main

Language

en

Author

FGTCLB

License

This document is published under the Creative Commons BY 4.0 license.

Rendered

Mon, 31 Aug 2026 20:35:30 +0000


TYPO3 extension for the presentation of projects and research projects of universities with specifically structured data and typified system categories. List view in the form of a tile display with filtering, which only provides positive filter results based on system categories, prevents impossible filter combinations and thus always ensures a positive user experience.

Examples of structured data: start and end year, areas of expertise, type of cooperation, funding bodies, duration. In conjunction with the Contact for Pages extension, the extension enables an active user journey and thus shows, for example, project managers, research participants or cooperation partners.


Introduction 

What the extension does and the main concepts behind it.

Installation 

Install academic_projects via Composer, the Extension Manager or a TER upload.

Configuration 

Configure the extension and its plugins for your installation.

Templates 

Override and customise the frontend templates.

Known problems 

Known issues and information about them.

Changelog 

Learn about what has changed and which actions are required to upgrade.

What does it do? 

This extension provides a new page type for projects.

Installation 

The extension has to be installed like any other TYPO3 CMS extension. You can download and install it using one of the following methods.

Install the stable release
composer require 'fgtclb/academic-projects':'^2'
Copied!
  1. Switch to the module Admin Tools > Extensions.
  2. Switch to Get Extensions.
  3. Search for the extension key academic_projects.
  4. Import the extension from the repository.
  1. Get the current version from TER by downloading the ZIP version. Alternatively, get the ZIP from the GitHub Releases page.
  2. Switch to the module Admin Tools > Extensions.
  3. Enable Upload Extension.
  4. Select or drag the extension ZIP archive and upload the file.

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 for what happens otherwise.

What the sets contain 

This extension ships two content elements, so it ships two component sets, one set for the styles.content override described below, and one aggregate set that depends on all of them.

Both content elements are driven by one Extbase plugin, so they share one TypoScript block, plugin.tx_academicprojects . That block is shipped once, in Configuration/TypoScript/, 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-projects-project-list The Projects content element.
fgtclb/academic-projects-project-list-single The Projects (selected) content element.
fgtclb/academic-projects-content-load The styles.content.getContent override only. No content element, and nothing this extension is otherwise made of — see The content load override.
fgtclb/academic-projects Everything above. This is the set to use unless you deliberately want a subset, and it is the name this extension published before the sets were cut per component — a site configuration that depends on it needs no change.

Every content element 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 content elements are hidden by default 

EXT:academic_projects hides both 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.

What the sets do not control 

The page type Academic project (doktype 30) and its backend layout AcademicProject are not part of any set, and enabling or not enabling a set never changes them.

That is deliberate, not an oversight. Both are values stored on pages records: a page carries doktype = 30 and backend_layout = pagets__AcademicProject long before any site configuration is read. Were they delivered by an opt-in set, every page tree on a site that does not use that set would show [ MISSING LABEL ] for the layout, the layout could not be picked for a new page, and the page type would disappear from the page tree wizard.

They are therefore registered installation-wide — the page type in TCA (Configuration/TCA/Overrides/pages.php), the backend layout in the always-included Configuration/page.tsconfig — and stay available on every site of the installation.

What a set does deliver for that page type is its frontend rendering: the page object that picks the Fluid template of the page type is part of the shared TypoScript block, so a site that includes no set of this extension renders such a page with whatever its own site package defines.

The content load override 

Configuration/TypoScript/ContentLoad/setup.typoscript redefines styles.content.getContent for the whole site so that it selects colPos = 0 only. This is an installation-wide rendering change, it applies to every page of the site and not only to the pages of this extension, and three academic extensions ship the same override.

It is therefore a set of its own, fgtclb/academic-projects-content-load. The aggregate set depends on it, so a site on fgtclb/academic-projects keeps what it had; a site that wants the content elements without the override names the component sets it needs instead of the aggregate.

Include the 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)
 base: 'https://example.com/'
 rootPageId: 1
+dependencies:
+  - fgtclb/academic-projects
Copied!

See also TYPO3 Explained, Using a site set as dependency in a site.

Include 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.

Include static TypoScript 

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

Entry Delivers
Academic Projects: Projects (academic_projects) The TypoScript of the Projects content element.
Academic Projects: Projects (selected) (academic_projects) The same for Projects (selected).
Academic Projects: Content load override (academic_projects) The styles.content.getContent override on its own.
Academic Projects: All components (academic_projects) Every component this extension ships, in one entry.
Academic Projects: Shared plugin settings and page rendering (academic_projects) The shared plugin.tx_academicprojects block and the page object of the page type, on their own. This is the entry an installation stored before the configuration was cut per component, and it keeps working — but it does not make any content element selectable, which the page TSconfig below does, and it no longer carries the content load override.

Include static page TSconfig 

Edit the page record of the site root, tab Resources, field Page TSconfig, and add the entry:

Entry Delivers
Academic Projects: Projects (academic_projects) Makes the Projects content element selectable, and configures its entry in the new content element wizard.
Academic Projects: Projects (selected) (academic_projects) The same for Projects (selected).
Academic Projects: All components (academic_projects) Every component this extension ships, in one entry.

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

Do not combine both 

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. For this extension that is the plugin.tx_academicprojects constants block, the three Fluid root paths.

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.

General configuration 

...

Overriding templates 

EXT:academic_projects is using Fluid as template engine.

This documentation won't bring you all information about Fluid but only the most important things you need for using it. You can get more information in the section Fluid templates of the Sitepackage tutorial. A complete reference of Fluid ViewHelpers provided by TYPO3 can be found in the ViewHelper Reference

Change the templates using TypoScript constants 

As any Extbase based extension, you can find the templates in the directory Resources/Private/.

If you want to change a template, copy the desired files to the directory where you store the templates.

We suggest that you use a sitepackage extension. Learn how to Create a sitepackage extension.

# TypoScript constants
plugin.tx_academicprojects {
    view {
        templateRootPath = EXT:mysitepackage/Resources/Private/Extensions/myextension/Templates/
        partialRootPath = EXT:mysitepackage/Resources/Private/Extensions/myextension/Partials/
        layoutRootPath = EXT:mysitepackage/Resources/Private/Extensions/myextension/Layouts/
    }
}
Copied!

Known problems 

Please note that this extension is still in development. Changes to existing code may appear in upcoming versions.

If you run into a bug or a feature that would be helpful, please use the issue tracker.

ChangeLog v3 

Every change to the Academic Projects extension is documented here.

Also available 

3.0 Changes 

Table of contents

Breaking Changes 

Features 

Deprecation 

Important 

Breaking: Extbase plugins require CType on TYPO3 v14 

Description 

TYPO3 v14 removed the tt_content sub-type feature (the list_type column) and changed ExtensionManagementUtility::addPlugin() accordingly. The academic plugins have been registered as first-class content elements (CType) since the 2.0 version line (see the 2.0 breaking note about migrating from list_type to CType); for TYPO3 v14 support the internal registration was adapted to the new addPlugin() signature and the vestigial list_type handling was dropped.

In addition the "New Content Element" wizard TSconfig still created the plugins as CType=list with a list_type, contradicting the CType registration; it now creates them with the dedicated CType directly.

Impact 

On TYPO3 v14 the tt_content.list_type column no longer exists. Any content records still stored as CType=list with a list_type of one of the plugins below will no longer resolve, and custom TypoScript, TSconfig, page TSconfig or SQL that references list_type for these plugins stops working.

The change relates to the following plugins:

  • academicprojects_projectlist
  • academicprojects_projectlistsingle

Affected Installations 

Installations that upgrade to TYPO3 v14 and still hold content elements stored as CType=list + list_type=<plugin> (including elements created through the previous "New Content Element" wizard), or that reference list_type for these plugins in their own configuration.

Migration 

Run the provided upgrade wizard academicProjects_pluginUpgradeWizard before upgrading to TYPO3 v14 (it requires the list_type column, which v14 removes) to migrate the tt_content records to the dedicated CType values. Update any custom configuration referencing list_type to match on CType instead.

Breaking: Removed TYPO3 v12 support 

Description 

Support for TYPO3 v12 has been removed for the 3.x version line, based on the dual TYPO3 core version support per major version of the academic extensions support matrix.

This includes removing build, test and configuration parts only required for TYPO3 v12. Version specific code paths are dropped in a dedicated step.

Impact 

TYPO3 v12 or older instances can no longer install or update to the 3.x version of the academic extensions and are required to upgrade TYPO3 first.

The extension cannot be installed on TYPO3 v12 anymore but does not break otherwise.

Affected installations 

All installations using an academic extension on TYPO3 v12 that want to upgrade to the 3.x version line.

Migration 

Upgrade the TYPO3 installation to a supported version (TYPO3 v13) beforehand or within the same upgrade step.

Important: The backend layout is registered for every installation 

Description 

The backend layout of the page type this extension registers, and the descriptions of its content elements, were imported only by Configuration/Sets/AcademicProjects/page.tsconfig.

Configuration/page.tsconfig of an extension is auto-included for the whole installation since TYPO3 v12.0 (Feature: #96614); a site set is opt-in per site. So on a site that does not enable the set fgtclb/academic-projects the layout pagets__AcademicProject resolved nowhere: the page properties showed [ MISSING LABEL ] for it and it could not be selected for a new page at all.

Both imports moved to Configuration/page.tsconfig, where fgtclb/academic-programs already had them, and the copy in the site set was removed rather than left to be applied twice. The Configuration/TsConfig/page.tsconfig that carried nothing but a @todo asking for exactly this move was removed with it.

Impact 

The backend layout and the content element descriptions are available on every installation, whether or not it uses site sets.

Affected Installations 

All installations of this extension. Nothing has to be done: pages already carrying pagets__AcademicProject resolve the layout from now on.

Important: The category filter accepts a list of uids 

Description 

Factory\DemandFactory::createDemandObject() read the submitted category filter itself:

foreach ($demandFromForm['filterCollection'] as $uids) {
    $categoryUids = array_merge($categoryUids, GeneralUtility::intExplode(',', $uids));
}
Copied!

GeneralUtility::intExplode() takes a string, so a filter value that is a list ended in a TypeError:

TypeError: GeneralUtility::intExplode(): Argument #2 ($string) must be of
type string, array given
Copied!

That is exactly what a filter select with multiple submits — the argument the category filter select gained in the same release. A filterCollection that is not an array at all did not raise, but emitted a PHP warning foreach() argument must be of type array|object and silently dropped the filter.

Both shapes are reachable from a crafted request without any template being involved, because the controller action takes the demand as a plain ?array $demand = null and validates nothing.

The filter is read through FGTCLB\CategoryTypes\Filter\CategoryFilterNormalizer now, which accepts a single value, a list and a comma separated string, and treats anything it cannot read as no filter.

Impact 

  • A category filter select with multiple works.
  • A request with an unreadable filter renders the list unfiltered instead of failing.
  • An unselected filter no longer contributes uid 0 to the query. The prepended "all options" entry carries an empty value, and every unselected category type added one 0 to the uid list. The rendered result is unchanged — no category has uid 0 — but the list handed to CategoryRepository::findByGroupAndUidList() is empty now, which it accepts since the same release.
  • A uid submitted twice is used once.

Affected Installations 

None have to act. Own code calling createDemandObject() with a hand built demand array keeps working, and gains the list shape.

References 

  • CategoryFilterNormalizer in EXT:category_types — the class the filter is read with, and where its behaviour is documented.

Important: The FlexForm upgrade wizard migrates records 

Description 

The upgrade wizard academicProjects_flexFormUpgradeWizard (FGTCLB\AcademicProjects\Upgrades\FlexFormUpgradeWizard) never migrated a single content element. It built the WHERE constraint of its UPDATE statement on the query builder of the enclosing SELECT:

$updateQueryBuilder->update('tt_content')
    ->set('pi_flexform', $this->array2xml($flexFormData))
    ->where(
        $queryBuilder->expr()->in(                                   // select builder
            'uid',
            $queryBuilder->createNamedParameter($record['uid'], …)   // select builder
        )
    )
    ->executeStatement();
Copied!

A named parameter is bound to the query builder that created it, so the statement carried a placeholder whose value was never bound to it — while set() had created a placeholder of its own on the update builder, holding the new FlexForm XML. The first record therefore ran

UPDATE tt_content SET pi_flexform = :dcValue1 WHERE uid IN (:dcValue1)
Copied!

comparing the XML against uid, and every following record referred to a placeholder that did not exist on the update builder at all.

The constraint is now built on the builder that executes it, with eq() since the value is always a single uid:

->where(
    $updateQueryBuilder->expr()->eq(
        'uid',
        $updateQueryBuilder->createNamedParameter($record['uid'], Connection::PARAM_INT)
    )
)
Copied!

Impact 

The wizard now performs the FlexForm migration it announces: settings.hideCompletedProjects becomes settings.activeState (value 1 maps to active, anything else to all), settings.filter.options becomes settings.hideFilter and settings.sorting.options becomes settings.hideSorting, each keeping its value.

Previously the outcome depended on the database:

  • MySQL, MariaDB and SQLite reported success and changed nothing.
  • PostgreSQL aborted with a Doctrine\DBAL\Exception\DriverException, invalid input syntax for integer.

Affected Installations 

Installations that ran the upgrade wizard of a previous version. The plugin FlexForm of academicprojects_projectlist and academicprojects_projectlistsingle content elements still carries the old setting names, and the plugins fall back to their default behaviour for those settings.

Migration 

Run the upgrade wizard again. An installation that already executed it has it recorded as done, so it has to be marked undone first — in the Install Tool under Upgrade > Upgrade Wizard, or on the command line:

vendor/bin/typo3 upgrade:mark:undone academicProjects_flexFormUpgradeWizard
vendor/bin/typo3 upgrade:run academicProjects_flexFormUpgradeWizard
Copied!

Running it again is safe: the wizard only rewrites a FlexForm that still contains one of the old setting names and leaves every other record untouched.

Important: List ordering ties are broken by uid 

Description 

ProjectRepository::findByDemand() orders by the sorting option the plugin demands — and by nothing else, so records equal in that ordering (two projects with the same title, for example) were returned in whatever relative order the database yielded. On PostgreSQL that is not the same list twice. The query now appends uid ascending as a tiebreaker.

Impact 

No visible change is expected: within records equal in the demanded ordering, uid ascending is the order every supported database returned in practice, it is simply guaranteed now rather than coincidental.

Affected Installations 

Every installation of this extension.

Important: The page template name of the academic project page type is set explicitly 

Description 

This extension registers a page type with a backend layout and ships the page template for it in Resources/Private/Pages/. Its TypoScript adds that directory to page.10.templateRootPaths , but it did not set page.10.templateName — the property that actually selects the file.

A site package deriving the name from the backend layout therefore did not find it. bk2k/bootstrap-package does exactly that:

templateName.cObject = TEXT
templateName.cObject {
  data = pagelayout
  case = uppercamelcase
  split {
    token = pagets__
    cObjNum = 1
    1.current = 1
  }
}
Copied!

case = uppercamelcase is GeneralUtility::underscoredToUpperCamelCase() , which lowercases the whole string before it camel cases it on underscores. The registered backend layout pagets__AcademicProject therefore resolved to Academicproject.html, and the frontend ended in an InvalidTemplateResourceException — in a production context a page whose body reads Oops, an error occurred!.

The extension now sets the name itself, inside the page type condition it already uses:

[page && traverse(page, "doktype") == 30]
  page.10 {
    templateName >
    templateName = AcademicProject
  }
[END]
Copied!

The clear is not decoration. Bootstrap package assigns templateName.cObject , and a cObject overwrites the plain value in ContentObjectRenderer::stdWrapValue() , so assigning without clearing would change nothing.

Impact 

A page of this type renders its template on a site package that derives the name from the backend layout, where it previously did not render at all.

Nothing changes for a site package that sets the name itself, as long as it does so after this extension's TypoScript, and nothing changes for a PAGEVIEW page object — that content object ignores templateName and resolves the file from paths , which is why that integration worked before and is unaffected now.

Affected Installations 

All installations of this extension that use a FLUIDTEMPLATE page object. An installation that shipped Academicproject.html in its own site package to work around this loses that override: the template of this extension is used instead. Clearing page.10.templateName after this extension's TypoScript restores it.

Important: The page TSconfig directory is now spelled TSconfig 

Description 

The extensions of this set spelled their page TSconfig directory in three different ways — TsConfig, TSconfig and TSConfig. They now all use TSconfig, which is how TYPO3 spells the term and what the core documentation uses.

In this extension the directory was Configuration/TsConfig.

Nothing was broken before, because every import matched the directory it pointed at. The reason to change it is that a filesystem is case sensitive on Linux and case insensitive on macOS and Windows, so a path copied between two of these extensions resolved on one machine and silently not on another — and a page TSconfig @import that does not resolve raises no error, the configuration is simply absent.

Impact 

Every file this extension ships moved with the directory. The imports inside the extension were updated in the same change, so an installation that only installs the extension has nothing to do.

An integrator who references these paths from their own configuration has to update them, because the old path no longer exists:

Page TSconfig of your own site package
# before
@import 'EXT:academic_projects/Configuration/TsConfig/BackendLayouts/*.tsconfig'
# after
@import 'EXT:academic_projects/Configuration/TSconfig/BackendLayouts/*.tsconfig'

# before
@import 'EXT:academic_projects/Configuration/TsConfig/Wizards/*.tsconfig'
# after
@import 'EXT:academic_projects/Configuration/TSconfig/Wizards/*.tsconfig'
Copied!

Affected Installations 

Every installation that imports a page TSconfig file of this extension by path, or that copied such a path into its own site package. An installation that relies only on the auto-included Configuration/page.tsconfig of the extension, or on its site set, is unaffected.

Important: The replace view helper accepts its arrays again on v14 

Description 

FGTCLB\AcademicProjects\ViewHelpers\Format\ReplaceViewHelper documents and implements array support for three of its arguments, but registered all three as string:

$this->registerArgument('content', 'string', 'Content in which to perform replacement. Array supported.');
$this->registerArgument('substring', 'string', 'Substring to replace. Array supported.', true);
$this->registerArgument('replacement', 'string', 'Replacement to insert. Array supported.', false, '');
Copied!

TYPO3 v14 rejects that. Fluid 5 validates a registered argument type with StrictArgumentProcessor, where Fluid 4 used LenientArgumentProcessor and let anything through:

InvalidArgumentValueException (1256475113): The argument "substring" was
registered with type "string", but is of type "array" in view helper
"FGTCLB\AcademicProjects\ViewHelpers\Format\ReplaceViewHelper".
Copied!

The three arguments are registered as mixed now, which is the type the view helper always behaved as: it branches on is_scalar() and casts to (array) otherwise, before handing the values to str_replace() or str_ireplace().

Impact 

A template passing a list to content, substring or replacement works on TYPO3 v14 again. Nothing changes for a template passing strings.

caseSensitive and returnCount keep their boolean type - they rely on the coercion StrictArgumentProcessor performs for it.

A string|array union was tried first and is not equivalent. Fluid 5 matches its scalar coercion on the whole registered type string, so a union falls through uncoerced and is then validated against each member. An integer is neither a string nor an array, and the previous string type used to cast it - so the union would have exchanged one rejected value type for another. With mixed the view helper performs that cast itself, as it always did.

Affected Installations 

Installations on TYPO3 v14 whose templates pass an array or a non-string scalar to this view helper. It is used by no template shipped here.

References 

Important: The sorting select shares the option rendering 

Description 

ViewHelpers\Form\SortingSelectViewHelper::renderOptionTags() was removed. It was identical to the method it inherits from FGTCLB\CategoryTypes\ViewHelpers\Form\AbstractSelectViewHelper, down to the last character - the class only ever needed its own getOptions().

That base class writes every option through a single method now, which escapes the option value. It used to concatenate the value unchanged while escaping the label.

Impact 

The rendered markup is unchanged. The options of this select carry the values of Enumeration\SortingOptions - title, asc, desc and their siblings - and none of them needs escaping.

An own subclass overriding renderOptionTags() keeps working, and one calling parent::renderOptionTags() reaches the inherited implementation.

References 

  • AbstractSelectViewHelper in EXT:category_types - the class writing the option markup, and where the change is documented.

3.x Changes by type 

This lists all changes to the Academic Projects extension of minor versions grouped by their type.

Table of contents

Breaking Changes 

Features 

Deprecations 

Important notes 

ChangeLog v2 

Every change to the Academic Projects extension is documented here.

Also available 

Breaking: Site sets and static templates have been restructured 

Description 

The TypoScript and the page TSconfig of this extension were shipped twice: the static template read Configuration/TypoScript/, and the site set fgtclb/academic-projects shipped its own constants.typoscript and setup.typoscript, each of them a single @import of that folder. The page TSconfig existed only as the wizard file Configuration/TSconfig/Wizards/NewContentElement.tsconfig and was not selectable on a page at all.

Both mechanisms now read one physical copy of every file, and both of them deliver the extension per component instead of as one block:

  • Configuration/TypoScript/ keeps the shared plugin.tx_academicprojects block and the page object of the page type. Both content elements are driven by the one plugin, so that block is shipped once and every component folder names it in a one-line include_static_file.txt.
  • Configuration/TypoScript/ProjectList/ and Configuration/TypoScript/ProjectListSingle/ are the two component folders — what the static template registers and what the matching set points its typoscript key at.
  • Configuration/TSconfig/<Component>/page.tsconfig holds the page TSconfig of a component and is what the page field Page TSconfig offers and what the set points its pagets key at.
  • Configuration/TypoScript/Full/ and Configuration/TSconfig/Full/page.tsconfig are the aggregates for installations that do not use site sets.

The content elements are now hidden by default. The always-included Configuration/page.tsconfig removes both content element types from the selectable ones, and the page TSconfig of a component adds its own back — so an element is offered where it is wanted instead of on every page of every installation. The TCA registration itself did not move, so the frontend renders existing records exactly as before. Editing such a record in the backend is a different matter — read the warning below before upgrading.

The styles.content.getContent override that Configuration/TypoScript/setup.typoscript used to import unconditionally is a component of its own now, Configuration/TypoScript/ContentLoad/setup.typoscript. It redefines a global TypoScript object path for every page of a site, so it must be possible to take the content elements without it.

The page type Academic project (doktype 30) and its backend layout AcademicProject are unchanged and stay installation-wide. They are values stored on pages records and are not, and must not be, part of any opt-in set.

Impact 

A sys_template record that selected the static template of this extension keeps its stored value and keeps working: the registered folder is unchanged, only its label is. What it no longer delivers is the styles.content.getContent override, which moved into a component of its own.

A site package that imported one of the moved files by path fails to resolve it. @import of a missing file is silent, so this shows up as missing configuration rather than as an error message.

Both content elements are no longer offered in the backend until the page TSconfig of their component is included, through the site set or through the page field Page TSconfig.

The set fgtclb/academic-projects keeps its name and keeps delivering everything, so a site configuration that depends on it needs no change.

Affected Installations 

Installations that import one of the shipped files from an own site package, that use one of the content elements of this extension without including its page TSconfig, or that relied on the styles.content.getContent override arriving with the plugin configuration.

Migration 

Adjust every @import in an own site package:

Old path New path
EXT:academic_projects/Configuration/TypoScript/constants.typoscript Unchanged.
EXT:academic_projects/Configuration/TypoScript/setup.typoscript Unchanged, but it no longer imports the styles.content override below.
EXT:academic_projects/Configuration/TypoScript/Content/ContentLoad.typoscript EXT:academic_projects/Configuration/TypoScript/ContentLoad/setup.typoscript
EXT:academic_projects/Configuration/TypoScript/Content/ EXT:academic_projects/Configuration/TypoScript/ContentLoad/
EXT:academic_projects/Configuration/TSconfig/Wizards/NewContentElement.tsconfig EXT:academic_projects/Configuration/TSconfig/Full/page.tsconfig
EXT:academic_projects/Configuration/TSconfig/Wizards/*.tsconfig EXT:academic_projects/Configuration/TSconfig/Full/page.tsconfig
EXT:academic_projects/Configuration/Sets/AcademicProjects/constants.typoscript Removed. It was a one-line @import of the file above it in this table.
EXT:academic_projects/Configuration/Sets/AcademicProjects/setup.typoscript Removed, for the same reason.

The entry in the sys_template record keeps its value and changes its label:

Old entry New entry
Academic Projects (academic_projects), stored as EXT:academic_projects/Configuration/TypoScript/ Academic Projects: Shared plugin settings and page rendering (academic_projects), same stored value — or Academic Projects: All components (academic_projects), stored as EXT:academic_projects/Configuration/TypoScript/Full, which also carries the content load override.

Add the page TSconfig entry, which did not exist before, in the page record of the site root, tab Resources, field Page TSconfig: Academic Projects: All components (academic_projects), stored as EXT:academic_projects/Configuration/TSconfig/Full/page.tsconfig. Without it the content elements are not selectable any more, and existing records of them lose their CType when they are saved from the backend form.

Sites that use the site set instead need no migration — but they must not use both mechanisms at once, see the Configuration chapter.

A site configuration may name the new component sets instead of the aggregate:

Set Delivers
fgtclb/academic-projects Unchanged in name, now delivers through the component sets below.
fgtclb/academic-projects-project-list The Projects content element only.
fgtclb/academic-projects-project-list-single The Projects (selected) content element only.
fgtclb/academic-projects-content-load The styles.content.getContent override only. The aggregate depends on it; name the component sets above without it to opt out.

Feature: The replace view helper can return the number of edits 

Description 

FGTCLB\AcademicProjects\ViewHelpers\Format\ReplaceViewHelper counted its replacements and returned the count instead of the replaced content when a returnCount argument was set:

if ($this->arguments['returnCount'] ?? false) {
    return $count;
}
Copied!

That argument was never registered, and Fluid rejects an argument a view helper does not declare while it parses the template - so no template could reach the branch:

Undeclared arguments passed to ViewHelper
FGTCLB\AcademicProjects\ViewHelpers\Format\ReplaceViewHelper: returnCount.
Valid arguments are: content, substring, replacement, caseSensitive
Copied!

returnCount is a registered boolean argument now, defaulting to false:

<ap:format.replace
    content="A research project of the research group"
    substring="research"
    replacement="teaching"
    returnCount="true"
/>
Copied!

renders 2.

Impact 

Nothing changes for a template that does not pass the argument - the default returns the replaced content, as before. A template that passed returnCount used to raise the parse error above and renders the count now.

The count is the one str_replace() and str_ireplace() report, so it counts occurrences rather than distinct substrings, and it is 0 for a substring that does not occur.

References 

Feature: "Show hidden records" plugin option for the project lists 

Description 

A new boolean plugin option Show hidden records ( settings.showHiddenRecords , checkbox/toggle, default off) was added to the following plugins:

  • Projects ( academicprojects_projectlist )
  • Projects (selected) ( academicprojects_projectlistsingle )

Both plugins share the single Configuration/FlexForms/ProjectSettings.xml data structure.

When the option is enabled, the frontend project listing includes hidden (disabled) records, independent of the Context API visibility settings. Only the hidden enable column (disabled) is ignored; the deleted, starttime/endtime and fe_group restrictions stay in effect.

Impact 

Editors can now opt in per plugin instance to display hidden projects in the frontend, for example to preview intentionally hidden records without changing the global preview settings. The option is off by default, so existing plugin instances keep their current behaviour.

Affected Installations 

All installations using the EXT:academic_projects extension starting with version 2.4. No action is required for existing installations.

Important: Extended ProjectDemand and demand handling 

Description 

To support the new "Show hidden records" plugin option, the project demand pipeline gained a new transport flag:

  • \FGTCLB\AcademicProjects\Domain\Model\Dto\ProjectDemand has a new bool $showHiddenRecords property with setShowHiddenRecords(bool): void and getShowHiddenRecords(): bool accessors (default false ).
  • \FGTCLB\AcademicProjects\Factory\DemandFactory::createDemandObject() now reads $settings['showHiddenRecords'] and sets the flag on the demand object.
  • \FGTCLB\AcademicProjects\Domain\Repository\ProjectRepository::findByDemand() honours the flag: when it is true , the query ignores only the disabled (hidden) enable field via the Extbase query settings.

The public method signatures of DemandFactory::createDemandObject() and ProjectRepository::findByDemand() are unchanged.

Impact 

The change is non-breaking: the new flag defaults to false and no existing method signature changed. Projects that build a ProjectDemand themselves can opt in by calling setShowHiddenRecords(true) .

Affected Installations 

Only installations that extend or replace the ProjectDemand DTO, the DemandFactory or the ProjectRepository need to take the added flag into account. All other installations are unaffected.

Important: The page type is registered from a boot listener 

Description 

TYPO3 v13 has no allowedRecordTypes TCA option and resolves the tables allowed on a page type through PageDoktypeRegistry . This extension registered its page type 30 there, from Configuration/TCA/Overrides/pages.php.

That is too early. The first call to PageDoktypeRegistry->add() collects every table declaring security.ignorePageTypeRestriction - tt_content, sys_template and backend_layout - from the TcaSchemaFactory and latches the result for the rest of the request. A TCA override file runs while the TCA is still being assembled, before TcaSchemaFactory::load() , so that factory is still empty and none of the three ever reaches the allow list of the default page type.

TYPO3 then refuses content elements on ordinary pages:

Attempt to insert record on pages:1 where table "tt_content" is not allowed
Copied!

This happens while the TCA cache is cold, which is every import run after a cache flush and the first backend request after one. Once the TCA cache is warm the override files are not executed at all - and then the page type of this extension is not registered either, and silently falls back to the allow list of the default page type instead of allowing every record type.

The registration moved to an event listener on \TYPO3\CMS\Core\Core\Event\BootCompletedEvent , \FGTCLB\AcademicProjects\EventListener\RegisterAcademicPageDoktype . That event is dispatched one line after TcaSchemaFactory::load() and on every request, warm cache included, which is what both halves of the defect need. The listener does nothing on TYPO3 v14, where the TCA option carries the configuration and PageDoktypeRegistry->add() is deprecated.

Impact 

Content elements can be created on standard pages again while the TCA cache is cold, and the page type 30 of this extension allows every record type while it is warm.

Affected Installations 

All installations of this extension on TYPO3 v13. TYPO3 v14 is not affected, it resolves the allowed tables from TCA. Nothing has to be done beyond the usual cache flush after an update.

Breaking: Removed partials 

Description 

Some partials got removed as the templating structure has changed.

Impact 

Those partials include:

  • Resources/Private/Layouts/Default.html
  • Resources/Private/Partials/Categories.html
  • Resources/Private/Partials/Project/Items.html
  • Resources/Private/Partials/Project/SingleItem.html

Affected Installations 

EXT:academic_partners installations overriding those partials.

Migration 

Adapt overrides accordingly to the new templating structure.

Breaking: #108800 - Remove translation files 

Description 

To unify the academic extensions the usage of locallang_db files was removed and the labels were moved to the locallang_be files.

Impact 

TYPO3 instances with extensions providing translation overrides or using the locallang_db keys with the full syntax directly no longer replaces or provide them or leading to untranslated key display.

Affected installations 

TYPO3 instances with extensions providing translation overrides or using the locallang_db keys with the full syntax directly.

Migration 

Use the keys from locallang_be files.

Important: Basic bootstrap styling 

Description 

The default templating now supports basic bootstrap styling and is semantically optimized to also not lack any major accessibility.

Breaking: Changed plugin FlexForm option and values 

Description 

FlexForm options of following plugins has changed:

  • academicprojects_projectlist
  • academicprojects_projectlistsingle

Changed options:

  • settings.hideCompletedProjects => settings.activeState
  • settings.filter.options => settings.hideFilter
  • settings.sorting.options => settings.hideSorting

In case of settings.activeState that also includes supported values for the field, which also matches possible values of newly added PHP Enum \FGTCLB\AcademicProjects\Domain\Model\Dto\ActiveState :

FlexForm Enum Old Value
all ActiveState::ALL any value except 1
active ActiveState::ACTIVE 1
completed ActiveState::COMPLETED no old value

Impact 

Plugin usage with custom set old options uses fallback values of new options and will behave not in the expected way until options are migrated using the provided wizard.

Further, plugin output may lead to unexpected output not adoption for changed option names in case fluid templates are overridden, either in a project site package extension or another extension.

Affected installations 

All TYPO3 instances upgrade from 1.x to 2.x of this extension and having at least one of the mentioned plugins used as content object, either as content element or direct rendering in TypoScript.

Also extensions overriding fluid templates of EXT:academics_projects.

Migration 

An TYPO3 UpgradeWizard academicProjects_flexFormUpgradeWizard is provided to migrate old plugin FlexForm options and values to the new settings and values, in case of activeState also transforming the value based on mapping mentioned in the table above.

Furthermore, overridden fluid template in projects needs to adopt for changed options listed above in the description.

Breaking: Migrated extbase plugins from list_type to CType 

Description 

TYPO3 v13 deprecated the tt_content sub-type feature, only used for CType=list sub-typing also known as list_type and mostly used based on old times for extbase based plugins. It has been possible since the very beginning to register Extbase Plugins directly as CType instead of CType=list sub-type, which has now done.

Technically this is a breaking change, and instances upgrading from 1.x version of the plugin needs to update corresponding tt_content records in the database and eventually adopt addition, adjustments or overrides requiring to use the correct CType.

Impact 

The change relates to following plugins:

  • academicprojects_projectlist
  • academicprojects_projectlistsingle

Affected Installations 

All installations using the above listed plugins prior V2.0.

Migration 

A TYPO3 UpgradeWizard academicProjects_pluginUpgradeWizard is provided to migrate plugins from CType=list to dedicated CTypes matching the new registration.

Breaking: Removed methods from FGTCLBAcademicProjectsDomainModelDtoProjectDemand 

Description 

Following class methods has been removed:

  • ProfileDemand::getHideCompletedProjects()
  • ProfileDemand::setHideCompletedProjects()

Impact 

Using above mentioned removed ProfileDemand methods to call related methods in the ProfileRepository directly leads to FATAL PHP ERROR.

Affected installations 

TYPO3 instances using removed ProfileDemand methods.

Migration 

The removed method should be replaced using the new methods:

  • ProfileDemand::setActiveState(string $activeState): void
  • ProfileDemand::getActiveState(): string

instead, working slightly different now.

\FGTCLB\AcademicProjects\Domain\Model\Dto\ActiveState ENUM provided possible values for the active state but cannot be passed directly.

before
$demand = new ProfileDemand();
$demand->setHideCompletedProjects(true);
$demand->setHideCompletedProjects(false);
Copied!
$demand = new ProfileDemand();
// setHideCompletedProjects(true)
$demand->setActiveState(ActiveState::ACTIVE);
// setHideCompletedProjects(false)
$demand->setActiveState(ActiveState::ALL);
Copied!

Important: Switch to EXT:category_types v2 

Description 

Category type based handling has been streamlined and centralized within the EXT:category_types extension and the known implementation based on deprecated TYPO3 Enumeration has been replaced with a modern PHP API provided by the EXT:category_type extension.

Extension specific category types are now grouped and are now defined by newly introduced yaml file format, following a concrete convention to look and auto-register these files.

EXT:academic_projects now ships a default set of partner related category types, which can be found in ./Configuration/CategoryTypes.yaml

EXT:academic_projects related category types can be extended by any other TYPO3 extension providing a Configuration/CategoryTypes.yaml file containing category-types using the group-identifier projects.

Configuration/CategoryTypes.yaml format uses following syntax:

Configuration/CategoryTypes.yaml
types:
    - identifier: <unique_identifier>
      title: '<type-translation-lable-using-full-LLL-syntax'
      group: projects
      icon: '<icon-file-using-EXT-syntax-needs-to-be-an-as-svg>'
Copied!

Sitemap