Academic Partners 

Extension key

academic_partners

Package name

fgtclb/academic-partners

Version

main

Language

en

Author

FGTCLB

License

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

Rendered

Thu, 17 Sep 2026 07:34:13 +0000


TYPO3 extension for presenting partner institutions and cooperations of universities with structured data and typified system categories, including filterable list and map views in the frontend.


Introduction 

What the extension does and the main concepts behind it.

Installation 

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

Configuration 

Configure the extension and its plugins for your installation.

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? 

...

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-partners':'^2'
Copied!
  1. Switch to the module Admin Tools > Extensions.
  2. Switch to Get Extensions.
  3. Search for the extension key academic_partners.
  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 four content elements, so it ships four component sets, one set for the styles.content override described below, and one aggregate set that depends on all of them.

All four content elements are driven by one Extbase plugin, so they share one TypoScript block, plugin.tx_academicpartners . 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-partners-list The Partners List content element.
fgtclb/academic-partners-map The Partners Map content element.
fgtclb/academic-partners-partnerships-list The Partnerships List content element.
fgtclb/academic-partners-partnerships-teaser The Partnerships Teaser content element.
fgtclb/academic-partners-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-partners 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_partners hides all four 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 partner (doktype 40) and its backend layout AcademicPartner 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 = 40 and backend_layout = pagets__AcademicPartner 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-partners-content-load. The aggregate set depends on it, so a site on fgtclb/academic-partners 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-partners
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 Partners: Partners List (academic_partners) The TypoScript of the Partners List content element.
Academic Partners: Partners Map (academic_partners) The same for Partners Map.
Academic Partners: Partnerships List (academic_partners) The same for Partnerships List.
Academic Partners: Partnerships Teaser (academic_partners) The same for Partnerships Teaser.
Academic Partners: Content load override (academic_partners) The styles.content.getContent override on its own.
Academic Partners: All components (academic_partners) Every component this extension ships, in one entry.
Academic Partners: Shared plugin settings and page rendering (academic_partners) The shared plugin.tx_academicpartners 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 Partners: Partners List (academic_partners) Makes the Partners List content element selectable, and configures its entry in the new content element wizard.
Academic Partners: Partners Map (academic_partners) The same for Partners Map.
Academic Partners: Partnerships List (academic_partners) The same for Partnerships List.
Academic Partners: Partnerships Teaser (academic_partners) The same for Partnerships Teaser.
Academic Partners: All components (academic_partners) 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_academicpartners 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.

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 Partners extension is documented here.

Also available 

3.0 Changes 

Table of contents

Breaking Changes 

Features 

Deprecation 

Important 

Breaking: The map assets are built and loaded as a module 

Description 

The stylesheet and the script of the partner map are now compiled from sources in the repository. Both moved into a frontend/ subdirectory, and the script became an ES module:

EXT:academic_partners/Resources/Public/Css/map.css
->  EXT:academic_partners/Resources/Public/Css/frontend/map.css

EXT:academic_partners/Resources/Public/JavaScript/map.js
->  EXT:academic_partners/Resources/Public/JavaScript/frontend/map.js
Copied!

The vendored Leaflet library, its marker cluster plugin and their stylesheets are unchanged. They are third party files without sources here, they keep their paths, and they are still loaded as classic scripts — the map module reads the LeafletObject global they define.

Impact 

An installation that uses the shipped Map.html template needs to do nothing.

An installation that references either path keeps pointing at a file that no longer exists.

Affected installations 

Installations that override Templates/Partner/Map.html or reference map.css or map.js from their own site package.

Migration 

In an overridden template, replace the two references:

<f:asset.css identifier="partnerC2" href="EXT:academic_partners/Resources/Public/Css/frontend/map.css" />
<f:asset.module identifier="@fgtclb/academic-partners/frontend/map.js" />
Copied!

The three Leaflet lines around them stay exactly as they are.

Breaking: Record and category icons follow the colour scheme 

Description 

The record icons of this extension were registered with the core provider \TYPO3\CMS\Core\Imaging\IconProvider\SvgIconProvider , which renders the default markup - the markup a typeicon_classes entry reaches - as an <img> tag. An image is opaque to CSS, so the icon kept the ink of its file whatever the backend colour scheme said, and a dark drawing stayed dark on the dark cards of the record list.

They are now registered with \FGTCLB\AcademicBase\Imaging\IconProvider\CurrentColorSvgIconProvider , which inlines the file in both markups, and the files themselves are drawn in currentColor with no colour of their own.

That covers the three identifiers of this extension - academic-partners , tx_academicpartners_domain_model_partnership and tx_academicpartners_domain_model_role - and its four category type icons, which EXT:category_types registers as category_types.partners.* . The four category types ask for it with inlineIcon: true in Configuration/CategoryTypes.yaml; without that flag a category type icon keeps the core provider.

Impact 

The four category type icons reach the frontend, through <core:icon identifier="category_types.partners.{type}" /> in Pages/AcademicPartner.html, Partials/Partnerships/List/Item.html and Partials/Partnerships/Teaser/Item.html, and through category_types.partners.{category} in Partials/Partner/Item.html. None of those calls asks for the inline markup, so their rendered markup changes: an <img> of a fixed pixel size becomes an inlined <svg> with width="1em" height="1em" , which follows the font size and the colour of the text around it. Every site using the partner or partnership plugins sees those icons resize and recolour.

Site CSS or JavaScript that sized, coloured or addressed the <img> has to address the <svg> instead.

In the backend, the academic partner page type icon, the two record icons and the four category type icons take the text colour around them, so they stay legible in a dark backend colour scheme. academic-partners is also the icon of the four content elements of this extension, so those follow with it - the identifier is one icon, not two.

Affected Installations 

Every installation of this extension. Installations that render the partner or partnership plugins in the frontend are affected visibly.

Migration 

Replace an image selector with an element selector in the site CSS, for example

/* before */
.partner-attributes .icon img { width: 32px; }

/* after */
.partner-attributes .icon svg { width: 1.25em; }
Copied!

The icon element keeps the surrounding <span class="t3js-icon icon" data-identifier="…"> wrapper, so a selector written against the wrapper needs no change.

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 or v14 - beforehand or within the same upgrade step.

Breaking: Removed the unused autocomplete library 

Description 

The file Resources/Public/JavaScript/autocomplete.min.js has been removed. It was a minified third party library that arrived with the initial import of the extension and was never referenced — no template, no TypoScript, no PHP and no other asset loaded it.

It was shipped in every release regardless, and a vendored, minified file without a source is a maintenance and security liability for as long as it exists.

Impact 

Nothing in the extension changes. No plugin, template or partial loaded the file, so no rendering, styling or behaviour is affected.

The file is no longer part of the package and a request for it returns 404.

Affected installations 

Only installations that referenced the file from their own site package or template overrides. That is possible, because the file was located below Resources/Public/, but it was never part of the extension's public API and no documentation ever mentioned it.

Migration 

If a project loads the file from its own template, ship the library in the project's own site package and reference it from there instead:

<f:asset.script identifier="autocomplete" src="EXT:my_sitepackage/Resources/Public/JavaScript/autocomplete.min.js" />
Copied!

No migration is required otherwise.

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 page template name of the academic partner 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__AcademicPartner therefore resolved to Academicpartner.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") == 40]
  page.10 {
    templateName >
    templateName = AcademicPartner
  }
[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 Academicpartner.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_partners/Configuration/TsConfig/BackendLayouts/*.tsconfig'
# after
@import 'EXT:academic_partners/Configuration/TSconfig/BackendLayouts/*.tsconfig'

# before
@import 'EXT:academic_partners/Configuration/TsConfig/Wizards/*.tsconfig'
# after
@import 'EXT:academic_partners/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: Partner map draws on a late module load 

Description 

The partner map did not draw on most page loads. The container stayed empty, no tiles, no markers, and nothing was reported anywhere - not in the browser console, not in the TYPO3 log.

Resources/Private/TypeScript/frontend/map.ts bound its whole body to document.addEventListener('DOMContentLoaded', ...) without asking whether that event was still ahead of it.

f:asset.module renders every module with async : the ViewHelper accepts an identifier and nothing else, and \TYPO3\CMS\Core\Page\JavaScriptRenderer writes the attribute unconditionally. An async module is not ordered against document parsing, so it regularly runs after DOMContentLoaded has already fired. The listener was then registered on an event that never comes again.

The module now runs its initialisation immediately when the document has finished parsing, and waits only while it has not:

if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', initializeMap, { once: true });
} else {
    initializeMap();
}
Copied!

That is the shape the other frontend modules of this repository already use. This was the only one missing it.

Impact 

The map draws on every load. Nothing about its markup, its configuration or its data changed, and an installation that saw the map draw before - the load where the module happened to win the race - sees no difference.

Affected Installations 

Every installation rendering the Partners Map plugin, or a template that includes the map module.

Important: The map leaves out partners without coordinates 

Description 

Controller\PartnerController::mapAction() fed the map from Domain\Repository\PartnerRepository::findByDemand() , which carries no geocode constraint. A partner page that was never geocoded - or whose geocoding failed - therefore reached the map template, and \Domain\Model\Partner types both coordinates as non-nullable float defaulting to 0:

protected float $geocodeLongitude = 0;
protected float $geocodeLatitude = 0;
Copied!

So a missing coordinate arrived in the template as a perfectly valid one:

<li class="map-partner" data-lat="0" data-lng="0" …>
Copied!

Resources/Private/TypeScript/frontend/map.ts guarded the values with Number.isNaN() , which 0 passes, and the marker was drawn at 0/0 - open ocean south of Ghana. The guard could not catch an empty attribute either, because Number('') is 0 and not NaN.

The map query now requires both coordinates, and the frontend module refuses to draw a record whose coordinates it cannot use. A partner without coordinates stays in the list, which is unchanged: it is still a perfectly good list entry.

Absence is the criterion, not the value. NULL and the empty string mean "no coordinate"; a stored 0 is a real one, and only the pair 0/0 is refused. Longitude 0 runs through the United Kingdom, France, Spain and Ghana and latitude 0 is the equator, so treating a single zero as missing would hide partners that are genuinely there.

The two coordinate columns became allowLanguageSynchronization . A place does not move when the page is translated, so a translation follows its default record instead of carrying a coordinate of its own. A partner translated before geocoding ran kept an empty coordinate and was therefore drawn at 0/0 in that language - and, under the rule above, would have been left off that language's map entirely.

Domain\Repository\PartnerRepository::findGeoLocated() gained the same requirement, so a record that claims a successful or manually status without ever having received coordinates is no longer reported as located.

Impact 

A partner that was previously drawn at 0/0 disappears from the map. That marker never pointed at the partner's location, so nothing that pointed anywhere is lost.

When no partner has coordinates at all, the plugin no longer renders an empty map centred on Germany. It renders a message instead:

No partner with a location to show on the map.
Copied!

The label is map.noLocatedPartnersFound in Resources/Private/Language/locallang.xlf and can be overridden like any other label. Integrators who replaced Resources/Private/Templates/Partner/Map.html keep their own copy and get neither the condition nor the message.

A template that draws the map for one partner is not covered by any of this. The typical case is a partner detail page that renders the partner's own location: it has no query to constrain, and the list it hands to the map holds that single partner whether it has coordinates or not. Such a template draws the partner at 0/0, or - with the module above - an empty map centred on Germany.

Domain\Model\Partner::isDrawable() is the same rule for a single object. Guard the map with it:

EXT:my_sitepackage/Resources/Private/Templates/Pages/AcademicPartner.html
<f:if condition="{partner.drawable}">
    <f:render partial="Partner/Map" arguments="{partners: '{0: partner}'}" />
</f:if>
Copied!

Partner/Map stands for the site package's own map partial: this extension ships the map only as the plugin template, not as a partial.

It is deliberately not called "geo located": Domain\Repository\PartnerRepository::findGeoLocated() also requires a geocode status, and a record can claim to be located without carrying a coordinate. Like the frontend module it also refuses a coordinate that is not a finite number.

The model does not see exactly what the query sees, in either direction. An absent coordinate has already become 0 by the time a template asks, so a pair with only one coordinate missing reads as drawable at 0 on that axis while the query excludes it; a hand-entered 0.0 is refused by the model while the query lets it through. ACE-566 changes the column type and is where the two are reconciled.

A custom controller that calls Domain\Repository\PartnerRepository::findByDemand() itself gets the old behaviour unless it opts in, because the demand defaults to false:

$demand->setDrawableOnly(true);
Copied!

The server-side rule matches the pair 0/0 as a string, in the spelling \Command\GeocodeCommand writes. A hand-entered 0.0 therefore passes the query and is dropped by the frontend module instead. A numeric comparison cannot be expressed portably while the column is VARCHAR; ACE-566 changes the column type and removes that asymmetry.

\Command\GeocodeCommand writes its result through the DataHandler now instead of the repository. Only a DataHandler write runs \DataHandling\Localization\DataMapProcessor , and geocoding is the one path that actually writes coordinates - persisting through Extbase would reach the default record and leave every translation behind, which is the defect one level down.

Language synchronization takes effect when a record is saved, so it cannot repair what is already stored. The upgrade wizard academicPartners_synchronizePartnerCoordinates copies each partner's coordinates onto its translations once. Run it after updating; a site with translated partner pages needs it, and a site without translations does not. Deleted translations and workspace versions are left alone, and so is a coordinate an editor detached from its default record on purpose.

A workspace draft created before the update keeps its own stale coordinate: the wizard does not touch drafts, so publishing such a draft after the update re-introduces the empty value for that record. Re-saving it in the workspace is enough to bring it back in line.

Affected Installations 

Every installation rendering the Partners Map plugin whose partner records are not all geocoded, and every installation with translated partner pages. Installations where every partner has coordinates see no change.

Installations whose own templates draw a map for a single partner - most often a partner detail page - need to add the isDrawable() guard shown above; this extension's own page template renders no map.

Important: The partner page type renders its categories 

Description 

A page of the partner page type can carry categories of the category types this extension registers, and its page template has always contained a block that lists them, grouped by category type. That block never appeared.

It read the categories as {partner.categories.allCategoriesByType} , and the model behind {partner} has no such property — it exposes the collection as getAttributes() . Fluid resolves an unknown path to null without raising anything, so the surrounding <f:if> was false on every partner page and the whole list was skipped. The list and teaser partials of this extension already read the working path.

The page template now reads it as well:

<f:for each="{partner.attributes.allCategoriesByType}" as="categories" key="type">
Copied!

Impact 

A partner page with at least one category assigned now shows its category types and the categories of each, in the markup the template already contained — for example Region followed by Rhine-Main Area.

A category type without an assigned category produces no entry, and a partner page without categories renders exactly as before.

Affected Installations 

All installations that render partner pages with the page template shipped by this extension and assign categories to them.

An installation that overrides Resources/Private/Pages/AcademicPartner.html is not affected. A copy that was taken only to repair this defect can be dropped, as long as it carries no other change.

Important: Partner queries are ordered deterministically 

Description 

Every query of this extension executed without an ordering, so the order of its result was whatever the database happened to yield. On PostgreSQL that is not the same list twice: the partnership teaser rendered a different partner on two renders of the same data. The queries now order explicitly:

  • PartnershipRepository::findByPid() — the source of every partnership list and teaser — orders by the manual backend sorting (TCA ctrl sortby ), with uid settling ties.
  • PartnerRepository::findAll() and findGeoLocated() order by the backend sorting of the page records, with uid settling ties — partner records are pages, so among siblings this is the order the editor arranged in the page tree; partners spread over several parent pages interleave deterministically by that same value.
  • PartnerRepository::findNextForGeolocation() processes the geocoding queue oldest record first ( uid ascending) instead of letting the database pick.
  • PartnerRepository::findByDemand() appends uid as a tiebreaker to the ordering the plugin demands, so records equal in that ordering — two partners with the same title, for example — keep a stable relative order.

Impact 

Partnership lists and teasers now render in the order the records have in the backend. An installation whose editors reordered partnership records will see the frontend follow that order — which is the order the editor expressed, but was never delivered before. Everything else keeps its practical order: the backend page sorting and uid ascending are what every supported database returned in practice, they are simply guaranteed now rather than coincidental.

Affected Installations 

Every installation of this extension.

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.

Important: The static template and the backend layout are registered correctly 

Description 

Two registrations of this extension did not reach an installation.

The static template was registered under the wrong extension key. Configuration/TCA/Overrides/sys_template.php passed 'academic_programs' to ExtensionManagementUtility::addStaticFile() , so the entry offered in a template record as Academic Partners Page Setup pointed at EXT:academic_programs/Configuration/TypoScript/ — the TypoScript of a different extension. The TypoScript of this extension was registered nowhere and could only be reached through the site set fgtclb/academic-partners .

What that costs an installation without site sets: the page template directory of this extension never enters page.10.templateRootPaths , and the PartnershipProcessor data processor is never registered, so partnerships are not resolved on any page. An installation that has this extension without fgtclb/academic-programs included nothing at all, silently — SysTemplateTreeBuilder skips an include whose extension is not loaded.

The backend layout was imported by the site set only. Configuration/page.tsconfig is auto-included for the whole installation since TYPO3 v12.0 (Feature: #96614); a site set is opt-in per site. The backend layout of the page type this extension registers, and the descriptions of its content elements, were imported only by Configuration/Sets/AcademicPartners/page.tsconfig. On a site that does not enable that set the layout pagets__AcademicPartner 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 empty Configuration/TsConfig/page.tsconfig, which nothing imports any more, was removed with it.

The missing label of the layout's content column was added to Resources/Private/Language/locallang_be.xlf in the same change.

Impact 

The static template Academic Partners Page Setup now includes the TypoScript of this extension. 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.

The static template fix is not self-healing. A template record that selected the entry before stores EXT:academic_programs/Configuration/TypoScript/ , which is still a valid registration of the other extension, so the record keeps working and keeps including the wrong tree. The now correct entry has to be added to the record by hand. No upgrade wizard ships for it: the stored value is genuinely ambiguous — it cannot be told apart from an intentional selection of Academic Programs Page Setup — and rewriting it would break an installation that meant the latter.

Nothing has to be done for the backend layout. Pages already carrying pagets__AcademicPartner resolve it from now on.

3.x Changes by type 

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

Table of contents

Breaking Changes 

Features 

Deprecations 

Important notes 

ChangeLog v2 

Every change to the Academic Partners 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-partners 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_academicpartners block and the page object of the page type. All four 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/List/, Configuration/TypoScript/Map/, Configuration/TypoScript/PartnershipsList/ and Configuration/TypoScript/PartnershipsTeaser/ are the four 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 all four 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 partner (doktype 40) and its backend layout AcademicPartner 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.

The four 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-partners 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_partners/Configuration/TypoScript/constants.typoscript Unchanged.
EXT:academic_partners/Configuration/TypoScript/setup.typoscript Unchanged, but it no longer imports the styles.content override below.
EXT:academic_partners/Configuration/TypoScript/Content/ContentLoad.typoscript EXT:academic_partners/Configuration/TypoScript/ContentLoad/setup.typoscript
EXT:academic_partners/Configuration/TypoScript/Content/ EXT:academic_partners/Configuration/TypoScript/ContentLoad/
EXT:academic_partners/Configuration/TSconfig/Wizards/NewContentElement.tsconfig EXT:academic_partners/Configuration/TSconfig/Full/page.tsconfig
EXT:academic_partners/Configuration/TSconfig/Wizards/*.tsconfig EXT:academic_partners/Configuration/TSconfig/Full/page.tsconfig
EXT:academic_partners/Configuration/Sets/AcademicPartners/constants.typoscript Removed. It was a one-line @import of the file above it in this table.
EXT:academic_partners/Configuration/Sets/AcademicPartners/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 Partners Page Setup (academic_partners), stored as EXT:academic_partners/Configuration/TypoScript/ Academic Partners: Shared plugin settings and page rendering (academic_partners), same stored value — or Academic Partners: All components (academic_partners), stored as EXT:academic_partners/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 Partners: All components (academic_partners), stored as EXT:academic_partners/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-partners Unchanged in name, now delivers through the component sets below.
fgtclb/academic-partners-list The Partners List content element only.
fgtclb/academic-partners-map The Partners Map content element only.
fgtclb/academic-partners-partnerships-list The Partnerships List content element only.
fgtclb/academic-partners-partnerships-teaser The Partnerships Teaser content element only.
fgtclb/academic-partners-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 partner select is sorted by label 

Description 

The partner select of a partnership record now offers the partners ordered by their title, ascending, using the collation of the language the backend is displayed in.

Until now the select declared no order and offered the partners in the order the query behind it returned, which on this version line is the page tree order of the partner pages. In an installation with more than a handful of partners the entry to pick was found by scanning rather than by reading.

The order is declared on the field itself, so TYPO3 applies it with the collator of the backend language: a title starting with a diacritic is ordered by its base letter, and Öresund Academy is offered between Oberlin Institute and Potsdam College rather than after Zeta University.

The empty placeholder entry stays at the top of the list.

Impact 

Editors of partnership records see the same partners in a different, and findable, order. Nothing changes about which partners are offered, about what a save stores, or about how any list renders in the frontend. No migration and no manual step is required.

An editor who relied on the page tree order of the partner pages inside this select no longer gets it. That order was never an intended order of the select, it was the order of the query behind it.

Affected Installations 

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

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

Description 

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

  • List ( academicpartners_list )
  • Map ( academicpartners_map )

Both plugins share the single ListSettings.xml flexform data structure, which gains the new toggle.

When the option is enabled, the frontend partner 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.

The option is core-version-aware and available in both the TYPO3 v12 and v13 flexform data structures of the plugins.

Impact 

Editors can now opt in per plugin instance to display hidden partners 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_partners extension starting with version 2.4. No action is required for existing installations.

Important: Extended PartnerDemand and demand handling 

Description 

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

  • \FGTCLB\AcademicPartners\Domain\Model\Dto\PartnerDemand has a new bool $showHiddenRecords property with setShowHiddenRecords(bool): void and getShowHiddenRecords(): bool accessors (default false ).
  • \FGTCLB\AcademicPartners\Factory\DemandFactory::createDemandObject() now reads $settings['showHiddenRecords'] and sets the flag on the demand object.
  • \FGTCLB\AcademicPartners\Domain\Repository\PartnerRepository::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 PartnerRepository::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 PartnerDemand themselves can opt in by calling setShowHiddenRecords(true) .

Affected Installations 

Only installations that extend or replace the PartnerDemand DTO, the DemandFactory or the PartnerRepository 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 40 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\AcademicPartners\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 40 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: Changed identifier of backend layout 

Description 

The identifier of the backend layout was changed to unify the naming within all of the academic extensions.

Impact 

The backend layout identifier was changed from AcademicPartners to AcademicPartner.

Affected Installations 

Installations using the backend layout with the old identifier.

Migration 

Adapt to new naming of the backend layouts.

Breaking: Move translations to their belonging locallang files 

Description 

As some labels used for the backend were maintained in the locallang files for frontend usage, these labels were organized accordingly.

Impact 

Some labels in the backend might not be translated anymore, if a custom translation was only added to the frontend locallang file.

Affected Installations 

Installations with custom translations only added to the frontend locallang files.

Migration 

Add the custom translations to the correct locallang files.

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/Pages/AcademicPartners.html
  • Resources/Private/Partials/Categories.html
  • Resources/Private/Partials/Partner/Items.html
  • Resources/Private/Partials/Partner/SingleItem.html
  • Resources/Private/Partials/Partnerships/ListItem.html
  • Resources/Private/Partials/Partnerships/TeaserItem.html

Affected Installations 

TYPO3 instances with extensions overriding those partials of EXT:academic_partners.

Migration 

Adapt overrides accordingly to the new templating structure.

Important: Basic bootstrap styling 

Description 

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

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_partners now ships a default set of partner related category types, which can be found in ./Configuration/CategoryTypes.yaml

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

Configuration/CategoryTypes.yaml format uses following syntax:

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

Sitemap