Warum Plugin-Wildwuchs ein Betriebsrisiko ist
WordPress kennt keine Rechtetrennung zwischen Plugins. Jede aktivierte Erweiterung läuft im selben PHP-Prozess wie der Core, mit denselben Datenbankrechten, denselben Dateisystemrechten und Zugriff auf jeden Hook, den WordPress anbietet. Es gibt keine Sandbox, keine Capability-Grenze zwischen zwei Plugins und keine Deklaration, welche Daten eine Erweiterung anfassen darf. Ein Plugin, das nur Kontaktformulare rendern soll, kann Bestellungen lesen, Benutzerkonten anlegen und Dateien schreiben. Das ist keine Nachlässigkeit im Kern, das ist das Erweiterungsmodell von WordPress, und es ist einer der Gründe für seine Verbreitung. Die betriebliche Folge ist unbequem: Das Sicherheitsniveau einer Installation ist nicht der Durchschnitt aller Plugins, sondern das Niveau des schwächsten. Dreißig Plugins sind deshalb dreißig Vertrauensentscheidungen.
Zwei Zahlen aus dem Patchstack-Bericht für 2025 gehören in jede Entscheidungsvorlage. Erstens: 46 Prozent der gemeldeten Schwachstellen hatten zum Zeitpunkt der öffentlichen Veröffentlichung keinen Patch des Herstellers. Wer Sicherheit als „wir aktualisieren zeitnah“ definiert, hat für knapp die Hälfte der Fälle keine Antwort, weil es nichts zu aktualisieren gibt. Zweitens die Geschwindigkeit: Der nach beobachteter Angriffsintensität gewichtete Median bis zum ersten Ausnutzungsversuch liegt bei fünf Stunden. Unter den stark ausgenutzten Lücken wurden 20 Prozent innerhalb von sechs Stunden angegriffen, 45 Prozent innerhalb von 24 Stunden, 70 Prozent innerhalb von sieben Tagen. Ein monatliches Update-Fenster ist gegen automatisierte Massenscans kein Schutzkonzept. Deshalb ist die erste Maßnahme nicht schnelleres Aktualisieren, sondern eine kürzere Liste.
Deaktivieren räumt nicht auf. Ein deaktiviertes Plugin ist weiterhin Code im Verzeichnis wp-content/plugins, und ob eine seiner Dateien direkt über die URL erreichbar und ausführbar ist, hängt allein daran, ob der Autor sie gegen den direkten Aufruf abgesichert hat. Die übliche Prüfung auf ABSPATH am Dateianfang ist Konvention, keine Pflicht. Deaktivierte Plugins bekommen außerdem weiter Updates angeboten, was die Liste im Update-Fenster verlängert, ohne dass jemand etwas davon hat. Wenn eine Erweiterung nicht gebraucht wird, wird sie gelöscht. Dabei bleibt allerdings meistens etwas zurück: Nur wer eine Deinstallationsroutine über uninstall.php oder register_uninstall_hook mitliefert, räumt seine Optionen, Tabellen und Metadaten wirklich weg. Der Rest hinterlässt Datenreste, die niemand mehr zuordnen kann.
Die dritte Kostenstelle ist die Überschneidung. Zwei Caching-Plugins, die sich gegenseitig die Header überschreiben. Ein SEO-Plugin, das Meta-Angaben setzt, und ein Theme, das dieselben Angaben ein zweites Mal ausgibt. Drei Erweiterungen, die je einen Teil des Cookie-Banners übernehmen. Solche Paare kosten nichts an Lizenz und viel an Fehlersuche, weil das Verhalten von der Ladereihenfolge abhängt und sich nach jedem Update ändern kann. Dazu kommt der laufende Aufwand: Jedes Plugin ist ein Update-Kandidat, ein Kompatibilitätsrisiko bei jedem Major-Release und ein Eintrag, den bei einer Störung jemand ausschließen muss. Zwölf Plugins lassen sich in einem Vormittag einzeln durchschalten. Vierzig nicht.
Das Plugin-Inventar: was wir erheben und was daraus folgt
Das Inventar ist eine Tabelle, nicht ein Gefühl. Erhoben wird pro Erweiterung: Name und Slug, Herkunft (Verzeichnis auf wordpress.org, kommerzieller Anbieter, selbst gebaut, unbekannt), installierte und verfügbare Version, Datum der letzten Aktualisierung durch den Autor, Größenordnung der aktiven Installationen, der Wert aus dem Feld „Tested up to“, offene Sicherheitsmeldungen, Lizenz- und Laufzeitstatus bei kommerziellen Plugins, und in einem Satz der Zweck: welche Funktion im Frontend oder in der Redaktion an dieser Erweiterung hängt. Dazu die Frage, die am häufigsten unbeantwortet bleibt: Wird sie überhaupt noch aufgerufen? Die Grunddaten holen wir über WP-CLI, den Rest über das Verzeichnis, die Änderungshistorie des Anbieters und einen Blick in den Code. Der Vergleich der Dateien gegen die Fassung im Verzeichnis über wp plugin verify-checksums zeigt zusätzlich, ob jemand in einem fremden Plugin herumgeschrieben hat.
Bei der Bewertung des Pflegezustands ist der Warnhinweis im Verzeichnis ein schwaches Signal in beide Richtungen. Der gelbe Kasten „This plugin hasn’t been tested with the latest 3 major releases of WordPress“ erscheint, wenn im Feld „Tested up to“ der readme.txt keine der letzten drei Hauptversionen steht. Er sagt nichts über Fehler aus, und er lässt sich durch eine geänderte Zeile in der readme.txt ausräumen, ohne dass eine Zeile Code angefasst wird. Umgekehrt heißt ein fehlender Hinweis nicht, dass jemand hinsieht. Belastbarer sind vier andere Dinge: Datum und Inhalt der letzten tatsächlichen Code-Änderung, wie viele Support-Anfragen unbeantwortet stehen, wie der Autor auf die letzte gemeldete Lücke reagiert hat, und ob es überhaupt eine benannte Person oder Firma dahinter gibt. Bei kommerziellen Plugins kommt hinzu, ob die Lizenz noch läuft — eine abgelaufene Laufzeit heißt bei den meisten Anbietern: keine Updates, auch keine sicherheitsrelevanten.
Aus dem Inventar wird eine Entscheidung je Zeile, mit vier möglichen Ausgängen. Behalten: Die Erweiterung ist gepflegt, wird gebraucht, hat keinen Doppelgänger. Ersetzen: Die Funktion wird gebraucht, aber der Anbieter ist der schwächere Teil der Konstruktion, oder zwei Plugins tun dasselbe und eines genügt. Ausbauen: Die Funktion wird nicht mehr gebraucht, oder der Core kann sie inzwischen selbst — das kommt häufiger vor, als die Liste ahnen lässt. Selbst bauen: Die Funktion ist geschäftskritisch, und es gibt keinen Anbieter, dem man sie anvertrauen möchte. Jede Zeile bekommt eine Begründung und einen Aufwand, damit die Liste ohne uns weiterverwendbar ist. Und eine Erwartung räumen wir vorher ab: Aufräumen heißt in der Regel nicht halbieren. Die meisten Plugins bleiben. Der Gewinn liegt darin, dass Sie danach für jedes einzelne sagen können, warum.
Wenn der Hersteller aufhört — und wenn der Ausstieg teuer wird
Ein verwaistes Plugin kündigt sich nicht an. Wird eine Erweiterung auf wordpress.org geschlossen, steht auf der Verzeichnisseite nur noch der Hinweis „This plugin has been closed as of [Datum] and is not available for download“, aber in Ihrer Installation ändert sich nichts: Es gibt keine Aktualisierung, also zeigt WordPress das Plugin als aktuell. Der Grund der Schließung wird erst nach 60 Tagen offengelegt, und auch dann nur als grobe Kategorie — Einzelheiten nennt wordpress.org nicht. Die Kategorie entscheidet über die Dringlichkeit. „Author Request“ heißt: Zeit für einen geordneten Ersatz. „Merged Into Core“ heißt: Das Plugin kann weg, die Funktion ist jetzt in WordPress selbst. „Guideline Violation“ oder „Licensing/Trademark Violation“ heißt: prüfen, was da eigentlich läuft. „Security Issue“ heißt: heute handeln. Weil in der Verwaltung nichts davon auftaucht, gehört der Abgleich der installierten Slugs gegen das Verzeichnis in den Wartungsrhythmus — sonst merkt man es erst, wenn jemand die Lücke gefunden hat.
Bei einem verwaisten Plugin gibt es vier Wege, und keiner davon ist Abwarten. Ersatz durch eine gepflegte Alternative ist der Regelfall, kostet aber Datenmigration, wenn die alte Erweiterung eigene Tabellen oder Metafelder benutzt hat. Weiterpflege im eigenen Verantwortungsbereich ist bei GPL-lizenzierten Plugins erlaubt und manchmal sinnvoll, verschiebt aber die Verantwortung vollständig zu Ihnen: Ein Fork, den niemand pflegt, ist nur ein umbenanntes verwaistes Plugin. Übernahme des Plugins im Verzeichnis ist der geordnete Weg, wenn der Autor mitspielt — er kann die Rechte selbst übertragen, und wer ein Plugin abgeben will, kennzeichnet es mit dem Schlagwort adopt-me. Antwortet er nicht, läuft ein Verfahren über plugins@wordpress.org: überarbeiteten Code einreichen, das Plugin-Team schreibt den Autor an, nach 30 Tagen ohne Reaktion kann die Übergabe erfolgen. Bei einem bereits geschlossenen Plugin ist dieser Weg deutlich schwieriger. Bleibt Neuentwicklung der Funktion, wenn sie zu wichtig ist, um an fremdem Code zu hängen. Was der günstigste Weg ist, entscheidet der Funktionsumfang, nicht die Gewohnheit.
Der Sonderfall sind Page-Builder, weil dort nicht nur Funktion, sondern Inhalt am Plugin hängt. Elementor speichert die Seitenstruktur als JSON im Postmeta-Feld _elementor_data; im Feld _elementor_css liegt nicht Inhalt, sondern das daraus erzeugte CSS. Das Feld post_content bleibt dabei oft leer oder rudimentär. Die globalen Einstellungen liegen ebenfalls nicht als Option, sondern in einem eigenen Beitrag — dem Kit —, auf den die Option elementor_active_kit in wp_options nur verweist. WPBakery legt seine Struktur als Shortcodes im post_content ab, was ohne das Plugin sichtbaren Shortcode-Text hinterlässt statt Inhalt. Das Blockmarkup des Core-Editors steht dagegen als HTML mit Kommentaren im post_content und bleibt auch ohne alles lesbares Markup. Der Unterschied ist keine Geschmacksfrage, sondern eine Kostenrechnung für den Tag, an dem der Builder gewechselt oder eingestellt wird: Beim Blockeditor migriert man Markup, bei einem JSON-Builder baut man Seiten neu auf, seitenweise, mit redaktioneller Abnahme.
Deshalb bewerten wir einen laufenden Page-Builder, statt ihn zu verurteilen. Wenn Elementor oder WPBakery seit Jahren funktioniert, die Redaktion damit arbeitet und der Anbieter aktiv ist, gibt es keinen Grund, das Ganze in einem Wartungsprojekt herauszureißen — der Aufwand steht in keinem Verhältnis. Sinnvoll ist der Ausstieg zu genau zwei Anlässen: wenn das Design ohnehin ersetzt wird und die Inhalte in einem Relaunch neu strukturiert werden, oder wenn der Builder selbst zum Risiko wird, weil er ein Major-Update blockiert. Was wir vorher liefern, ist die Zahl, die dabei fehlt: wie viele Seiten tatsächlich im Builder-Format liegen, wie viele davon reine Textseiten sind, die sich mit vertretbarem Aufwand übertragen lassen, und welche Vorlagen von Hand nachgebaut werden müssen.
Eigenentwicklung: wann sie richtig ist und wann nicht
Ein eigenes Plugin ist die richtige Antwort, wenn die Funktion Ihr Geschäft betrifft und nicht das Internet allgemein. Vier Fälle kommen dabei regelmäßig vor. Erstens Regeln, die nur bei Ihnen gelten: Preisstaffeln nach Kundengruppe, Freigabeprozesse, Rabattlogik, Konfigurationsregeln für erklärungsbedürftige Produkte. Zweitens Schnittstellen zu Ihren Systemen — Warenwirtschaft, ERP, PIM, CRM —, weil dort das Datenmodell der Gegenseite entscheidet und nicht das eines Plugin-Anbieters. Drittens Funktionen, die datenschutzrechtlich sauber sein müssen und bei denen niemand erklären kann, wohin ein fertiges Plugin die Daten schickt. Viertens der Fall, in dem drei Erweiterungen plus Klebe-Code nötig sind, um zu erreichen, was ein überschaubares eigenes Plugin direkt tut: Dann ist die Eigenentwicklung nicht die teure, sondern die günstige Variante — und die wartbare.
Bei Standardaufgaben ist die Antwort Nein, auch wenn das gegen den Auftrag geht. Formulare, Backups, Caching, Bildkomprimierung, Metadaten für Suchmaschinen, Weiterleitungen, Zwei-Faktor-Anmeldung, Cookie-Einwilligung: Dort hat ein gepflegtes Plugin über Jahre Randfälle eingesammelt, die Sie nicht kennen und wir auf Anhieb auch nicht — Zeichensatzprobleme in Anhängen, Mailserver, die anders antworten als dokumentiert, Browser, die Dateifelder eigenwillig behandeln. Wer uns bittet, ein Kontaktformular zu entwickeln, bekommt von uns keinen Kostenvoranschlag, sondern zwei Plugin-Namen. Das gilt auch andersherum: Wenn eine Eigenentwicklung sich über die erwartete Nutzungsdauer nicht rechnet, sagen wir das vor dem Angebot und nicht in der zweiten Projektphase. Ein Plugin, das eine Funktion abdeckt, die es fertig gibt, ist auf Dauer Wartungslast ohne Gegenwert.
Was wir bauen, wird so gebaut, dass Updates weiter funktionieren. Das heißt konkret: keine Änderungen im Core, keine Änderungen in fremden Plugin- oder Theme-Verzeichnissen, keine Patches, die beim nächsten Update überschrieben werden. Erweitert wird über Hooks und Filter — add_action und add_filter — und über die dafür vorgesehenen Registrierungen für Blocks, REST-Routen, Custom Post Types und Metafelder. Alles Eigene liegt in einem eigenen Plugin mit eigenem Präfix, damit Funktions- und Optionsnamen nicht mit fremdem Code kollidieren; Theme-Anpassungen gehören in ein Child-Theme, nicht ins Original. Dazu die Pflichtteile, die man von außen nicht sieht: Capability-Prüfungen und Nonces bei jeder schreibenden Aktion, vorbereitete Statements für alles, was in die Datenbank geht, Abhängigkeiten über den seit WordPress 6.5 vorhandenen Header „Requires Plugins“ statt über eine Prüfung im Code, ein Durchlauf mit dem Plugin Check vor der Abnahme, eine Deinstallationsroutine, und der Quellcode in Ihrem Repository. Ein Plugin, das ein WordPress-Update blockiert, ist ein Konstruktionsfehler und kein Feature.
Was WordPress 7.1 an selbstgebauten Erweiterungen bricht
WordPress 7.1 erscheint am 19. August 2026, parallel zur WordCamp US in Phoenix. Vorher eine Klarstellung, weil sie in vielen Prüflisten falsch steht: React 19 kommt nicht mit 7.1. Das Upgrade wurde zurückgenommen, nachdem Inkompatibilitäten zwischen alter und neuer React-Fassung sowie in der Art, wie Plugins React einbinden, aufgetreten waren. 7.1 bleibt auf React 18.3; Gutenberg bietet ein experimentelles Flag, um React 19 zu testen. Wer seine Prüfliste um React-Migrationen herum baut, prüft das Falsche. Die relevanten Bruchstellen liegen an drei anderen Stellen, und sie treffen ausgerechnet den Code, den niemand im Blick hat: eigene Metaboxen, eigene Blöcke, eigene Spalten in Listenansichten, kleine Verwaltungsseiten aus früheren Projekten.
Die erste und wichtigste Änderung: Der Beitragseditor ist ab 7.1 immer in einem iframe — unabhängig vom Theme-Typ, unabhängig von der Block-API-Version der registrierten Blöcke und unabhängig von der der Blöcke im Inhalt. Bis dahin galt die Ausnahme: In 7.0 entschied die Block-API-Version der tatsächlich eingesetzten Blöcke darüber, ob der Editor iframed war, davor die der registrierten Blöcke; Blockthemes erzwangen das iframe ohnehin. Deshalb haben viele Installationen die Änderung nie zu sehen bekommen. Ab 7.1 gibt es keine Ausnahme mehr. Was bricht, ist jeder Code, der im Editor auf das globale document oder window zugreift — also der Großteil dessen, was per jQuery in den Editorbereich hineingreift, MutationObserver auf Editorinhalten, Skripte von Drittanbietern, die im Editor eingehängt werden, und CSS, das über einen globalen Selektor Inhalte im Canvas gestalten soll. Der Weg führt über ein Element im Canvas und dessen Eigenschaften ownerDocument und defaultView statt über die globalen Objekte; Ereignis-Listener am Canvas hängt man über useRefEffect ein und räumt sie dort auch wieder ab. Styles müssen über die dafür vorgesehenen Registrierungen in das iframe gebracht werden; global eingebundenes CSS erreicht den Inhalt nicht mehr.
Die zweite Änderung betrifft die Listentabellen der Beiträge — und damit auch Seiten und eigene Custom Post Types. Das führende th mit scope="row" ist von der Checkbox- in die Titelspalte gewandert: Die Checkbox-Zelle ist jetzt ein td, die Titelzelle ein th, das den Titel als aria-label trägt. Für Screenreader ist das ein Gewinn, für Erweiterungen eine Bruchstelle in Markup, das seit 2010 im Wesentlichen unverändert war. Wer über die CSS-Klasse check-column selektiert, um eine eigene Spalte zu positionieren, eine Zeile zu markieren oder ein Aktionsmenü einzuhängen, greift ins Leere; ebenso bricht Code, der Titel und Row Actions in einem td erwartet. Betroffen sind eigene Spalten in der Beitrags- und Seitenübersicht, Listenansichten eigener Custom Post Types, JavaScript für Sammelaktionen und alles CSS, das auf die alte Spaltenstruktur gerechnet ist; wer beide Fassungen bedienen muss, selektiert übergangsweise td und th zusammen. Die dritte Änderung ist kleiner und fällt trotzdem auf: Die Eigenschaft __next40pxDefaultSize ist wirkungslos geworden, Formularelemente rendern unbedingt mit 40 Pixel Höhe. Wer eigene Panels, Seitenleisten oder Metaboxen auf den früheren Standard von 36 Pixel ausgelegt hat — oder mit size="__unstable-large" gearbeitet hat —, bekommt verschobene Layouts.
Geprüft wird das auf einer Kopie, nicht im Livesystem, und in dieser Reihenfolge: Editor öffnen und die Browser-Konsole mitlesen, jeden eigenen Block und jede eigene Metabox einmal benutzen statt nur ansehen, jede Verwaltungsseite mit Listentabelle durchklicken, WP_DEBUG mit Protokollierung einschalten und danach das Log lesen, eigene Plugins durch den Plugin Check schicken. Der beruhigende Teil daran ist der Zeitpunkt: Minor-Releases spielt WordPress seit Version 3.7 selbstständig ein, Plugins und Themes seit 5.5 auf Wunsch — 7.0.2 vom 17. Juli 2026 kam mit kritischen Sicherheitsfixes sogar als erzwungenes Update. Ein Hauptversionssprung wie 7.1 kommt dagegen nicht von allein. Sie bestimmen den Termin. Das heißt aber auch: Wer ihn nicht bestimmt, verschiebt ihn nur — und prüft dann unter Zeitdruck gegen 7.2, die nach dem am 12. August 2026 veröffentlichten Zeitplan am 9. Dezember 2026 erscheinen soll.