New Features for Developers in WoltLab Suite 5.5

Some of the adjustments presented so far were made as a by-product of the already presented improved user interface, ignoring threads and the modernized search. However, with WoltLab Suite 5.5 we are also continuing the systematic modernization of core components that was started in WoltLab Suite 5.2 with FormBuilder, WoltLab Suite 5.3 with Guzzle as a replacement for HTTPRequest, and WoltLab Suite 5.4 with the session system and TypeScript.

During the development of WoltLab Suite 5.5 we have already continuously updated the developer documentation. In this article, we would like to once again provide an overview of the Developer Experience (DX) improvements in WoltLab Suite 5.5 and briefly outline where the journey will take us in the future.

PSR-7 Controller

When a page is accessed, for example the forum home page, this HTTP request is processed by a controller class, usually based on AbstractPage, AbstractForm or AbstractAction. The parameters for the invocation, for example an ID, are determined via the superglobals ($_GET, $_POST and others). For the response back to the browser, PHP's echo is (implicitly) used, as well as the header() function in some cases, such as for redirects.

This approach has several disadvantages: For example, when processing the request headers, it must be known how they are encoded in the $_SERVER array. When generating the response, the individual response headers are set in many different places, and the necessary exit; after a redirect ensures that logic may not be executed at the end of processing. Even if it usually works well, as a developer you occasionally bump up against the limits of this architecture and cannot realize your own goals or can only do so with a lot of extra effort.

As a solution to these problems, starting with WoltLab Suite 5.5, we introduce support for structured processing of HTTP requests and responses based on the PSR-7 standard. Requests and responses are represented, with everything included, as PHP objects. In the case of HTTP responses, this allows, for example, to reliably read, extend, modify and remove the already set response headers before the response is sent to the client at the end of processing at a central location by WoltLab Suite Core.

WoltLab Suite 5.5 ships with laminas-diactoros as a PSR-7 implementation by default. Diactoros provides many response classes for common use cases. For example, there is a JsonResponse to which a PHP array can be passed. This is automatically encoded as JSON by Diactoros and the necessary content-type header is also set automatically.

In WoltLab Suite 5.5, the PSR-7 integration allows the PSR-7 ResponseInterface to be returned in its own controller as a first step. We have explained the examples in our developer documentation:…l-psr-7-support.

In the next version, the PSR-7 integration will be extended with support for the PSR-7-ServerRequestInterface. This will then allow request parameters to be received in a structured way.

Dedicated Event Classes

The event system of WoltLab Suite is essentially untouched since the introduction of the IParameterizedEventListener interface in WoltLab Suite 2.1. This shows that it fundamentally works very well. However, there is one major core problem that unnecessarily complicates working with events: it is not always obvious which events are available and, more importantly, what data they have available at any given time. The rather unstructured $parameters array also makes working in the IDE unnecessarily complicated, especially the use of isset($parameters[...]) to handle optional values in combination with a typo causes unnecessary frustration during development.

In WoltLab Suite 5.5, we therefore introduce the concept of dedicated event classes that encapsulate all the necessary information about the event. This way, logical events such as "a user has logged in" can be fired in multiple places without the need for the EventListener to know all the login methods. Within the event, the relevant information such as "John Doe is the user who has logged in" can be retrieved via methods with full IDE support.

The exact functionality is of course described in our migration guide in the documentation: In the standard scope of WoltLab Suite 5.5, the new UserLoggedIn event is based on this concept, it illustrates the possibilities of the new event concept very clearly.

In the next versions more event classes will follow as needed.

Clean-Up PIPs

While most XML-based PIPs (Package Installation Plugins) already supported the deletion of datasets, support for language variables and for all TAR-based PIPs was missing until now. WoltLab Suite 5.5 rectifies this situation and, in addition to obsolete language variables, also allows (PHP) files and templates to be deleted.

We have explained the use of the fileDelete, templateDelete and acpTemplateDeletePIPs in our documentation:…/#file-deletion. The changes to the language PIP can be found directly below:

When upgrading packages for WoltLab Suite 5.5, we recommend deleting all files that existed at some point but no longer exist, once. This will ensure that there are no orphaned files left even in consistently updated installations. For generating the fileDelete.xml of WoltLab Suite Core, we used a PHP script in combination with "git" that is welcome to be used as a base. It can be found in the detailed comment of the commit message of this commit:…e4e014a46fadebd.


WoltLab Suite 5.5 ships with the Symfony polyfills to provide - as far as possible - helpful new features from PHP 7.3 to PHP 8.0. Of particular interest are, for example, str_starts_with, str_ends_with, str_contains, which can make code much easier to understand.

The details can be found in our developer documentation:…y-php-polyfills.

In the next releases, the polyfills will be updated according to the availability of new PHP versions (such as PHP 8.1 and 8.2).

Removal of Heavily Deprecated Code (Deprecations)

As part of the modernization efforts, many features that were aging and showing weaknesses were again replaced with an improved implementation and the old variants were marked as deprecated. Some functions, which are already deprecated for many versions and were no longer used in the plugin store, have been removed.

The complete list can be found in the documentation:…tions_removals/.

More deprecations and more removal of old code will surely follow in the next release. We recommend to consider all deprecations each time when customizing plugins to make sure they are ready for the future.