Auf dem CloudFest Hackathon im März, hab‘ ich mich ein wenig mit Alain Schlesser über WordPress und Plugin-Entwicklung unterhalten. Alain meinte, dass er, wenn es das Plugin hergibt und es zeitlich möglich ist, immer zuerst eine generische Library bauen und diese dann über ein WordPress-Plugin implementieren würde.

Vor ein paar Tagen hab ich mich an unser Gespräch erinnert, weil ich mich (aus Gründen) wieder intensiver mit dem ActivityPub-Plugin beschäftigt habe. Wir hatten schon vor einem Jahr den Plan, eine ActivityPub-Bibliothek zu verwenden, um uns nicht mit dem Protokoll beschäftigen zu müssen, und uns so voll und ganz auf die WordPress Integration konzentrieren könn(t)en. Wir haben die Idee aber erstmal nicht weiter verfolgt, da die Bibliothek eine Reihe von schwergewichtigen Third-Party-Libs wie Guzzle (HTTP-Client), Monolog (Logger) oder Symfony Cache (Caching) mit sich bringt. Für all diese Funktionen hat WordPress eigene Lösungen und wegen der Interoperabilität mit anderen Plugins, sollte man diese auch nutzen.

Bei der erneuten Evaluierung der ActivityPub-Bibliothek ist mir aufgefallen, dass sich Monolog, durch einen beliebigen PSR-3 kompatiblen Logger ersetzen lässt.

Kurze Erklärung zu PSR:

Eine PHP Standard Recommendation (PSR) ist eine PHP-Spezifikation, welche durch die PHP Framework Interop Group veröffentlicht wird. Ähnlich einem Java Specification Request in Java dient sie der Standardisierung von Programmierkonzepten. Ziel ist es die Interoperabilität von Komponenten zu ermöglichen und eine gemeinsame technische Basis zu schaffen oder bewährte Konzepte für einen guten Programmierstil sowie eine gute Testbarkeit von Komponenten umzusetzen. Verschiedene Frameworks wie z. B. die der TYPO3-Community, Symfony oder Zend implementieren hierbei PSR-Spezifikationen in einem selbst gewählten Umfang.

https://de.wikipedia.org/wiki/PHP_Standard_Recommendation

PSR-3 definiert ein standardisiertes Logger-Interface, welches (in unserem Beispiel) durch Monolog implementiert wird. Beim initialisieren des ActivityPub-Servers, lässt sich Monolog, durch einen alternativen Logger ersetzen, solange dieser auch PSR-3 konform ist.

use ActivityPhp\Server;

// Create a server instance with no log output
$server = new Server([
    'logger'   => [
        'driver' => '\Psr\Log\NullLogger'
    ],
]);Code-Sprache: PHP (php)

Also hab ich mir überlegt, wie so ein Logger für WordPress aussehen könnte und einen PSR-3 kompatiblen Wrapper gebaut:

namespace WPPSR\Log;

use Psr\Log\AbstractLogger;

class ErrorLogLogger extends AbstractLogger {
    public function log( $level, $message, $context = array() ) {
        if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
            if ( defined( 'WP_DEBUG_LOG' ) && WP_DEBUG_LOG ) {
                error_log(
                    sprintf(
                        '%s: %s. Details: %s',
                        $level,
                        trim( $message, '.' ),
                        json_encode( $context )
                    )
                );
            }
        }
    }
}Code-Sprache: PHP (php)

PSR definiert passenderweise auch Interfaces für HTTP-Clients, Request-/Response-Objekte und Caching. Für die Request-Library die in WordPress benutzt wird, gibt es sogar schon ein passendes Issue: https://github.com/WordPress/Requests/issues/320

Leider sind Caching und der HTTP-Client in der ActivityPub-Implementierung noch nicht austauschbar, obwohl beide benutzten Libraries PSR kompatibel sind. Das heißt ich muss zuerst evaluieren, wie viel Arbeit es ist, die ActivityPub-Lib anzupassen, um dann diverse Wrapper für das WordPress Caching und die Request-/Response-Classes zu schreiben…

Bzw. muss ich das wahrscheinlich nicht einmal selbst implementieren, da ich bei weitem nicht der Erste war, der diese Idee hatte:

WordPress tut sich immernoch schwer mit modernem PHP-Dependency-/Plugin-Management. Ersteres ist praktisch nicht vorhanden (wird aber zumindest nicht verhindert) und letzteres basiert immer noch auf einem Prozess in dem SVN eine tragende Rolle spielt. Aber mit PSR(-Wrappern) kann man das Problem schon ganz gut kompensieren 🙂