---
title: "For developers"
manual: "Academic Projects"
version: "3.0"
permalink: "https://docs.typo3.org/permalink/fgtclb/academic-projects:developers@3.0"
source: "Developers/Index.rst"
rendered: "2026-10-26T17:55:40+00:00"
---

# For developers {#developers}

Both project list content elements, **Projects** and
**Selected Projects**, dispatch two PSR-14 events of this extension
and the plugin view event of **academic_base**. They are the supported
way to change what a plugin queries and what it renders, and they replace the
only alternative there used to be: subclassing `ProjectController` and
re-registering the plugin.

Which classes of this extension are public API, and what that promises, is
stated for all academic extensions on the [extension points page of
academic_base](https://docs.typo3.org/p/fgtclb/academic-base/main/en-us/Developers/ExtensionPoints/Index.html#developers-extension-points).

Nothing changes in an installation that has no listener: both plugins query and
render exactly what they did before.

## Events {#developers-project-events}

| Event | Dispatched | What a listener can change | Owner |
| --- | --- | --- | --- |
| [ModifyProjectDemandEvent](https://docs.typo3.org/permalink/fgtclb/academic-projects:developers-event-modify-project-demand-event@3.0) | by both content elements, after the demand is built from the content element settings and the request and before the projects are queried | replace the demand | this extension |
| [ModifyProjectListEvent](https://docs.typo3.org/permalink/fgtclb/academic-projects:developers-event-modify-project-list-event@3.0) | by both, after the query and before the view variables are assigned | replace the projects, replace the applicable categories, assign further view variables | this extension |
| [ModifyPluginViewEvent](https://docs.typo3.org/permalink/fgtclb/academic-projects:developers-event-modify-plugin-view-event@3.0) | by both, once each time they render, after the action assigned its own variables | assign further view variables | **academic_base** |

One action, `ProjectController::listAction()`, serves both content
elements, so all three events fire for both, in this order. Which one is
rendering is on the context every event carries, as the plugin name
`ProjectList` or `ProjectListSingle`.
