PHP 8.2 ist zum Jahresende EOL, 8.6 kommt im November – mein Migrationsfahrplan für Kundenseiten
Am 31. Dezember 2026 fällt PHP 8.2 aus dem Security-Support. Für den 19. November ist PHP 8.6 geplant. Dazwischen liegen zwölf Wochen, in denen ich jede Kundenseite anfassen muss, die noch auf 8.2 oder älter steht. Das ist bei mir ungefähr ein Drittel.
Hier ist, wie ich das abarbeite. Kein Grundsatzartikel über PHP-Versionen, sondern der konkrete Plan.
TL;DR:
- Stand heute: 8.5.10 ist aktuell, 8.4 wird aktiv gepflegt, 8.3 und 8.2 bekommen nur noch Security-Fixes. 8.2 endet am 31.12.2026.
- Mein Ziel für Kundenseiten: 8.4. Nicht 8.5, nicht 8.6. Begründung unten – das ist meine Betriebsstrategie, keine WordPress-Empfehlung.
- 8.6 ist für den 19.11. geplant und geht bei mir auf keinen Produktivserver vor Frühjahr 2027.
- Was von 8.2 auf 8.4 geprüft werden muss: implizit nullable Parameter, ausgelagerte Extensions wie
imap, deprecated MySQLi-APIs, einzelne BC-Änderungen. AlteE_STRICT-Konfigurationen sind überflüssig und deprecated – ein Fatal Error entsteht daraus unter 8.4 aber nicht.
Die Daten, auf die es ankommt
| Version | Status heute (Sept. 2026) | Security-Support bis |
|---|---|---|
| 8.6 | Beta, Hard Feature Freeze 22.9., RC1 24.9., GA geplant 19.11. | – |
| 8.5 | aktuell (8.5.10) | 31.12.2029 |
| 8.4 | aktiv gepflegt | 31.12.2028 |
| 8.3 | nur Security | 31.12.2027 |
| 8.2 | nur Security | 31.12.2026 |
| 8.1 und älter | EOL | – |
Quelle: php.net/supported-versions. Das Modell: zwei Jahre aktive Pflege, dann zwei Jahre Security-Fixes. Release im November, EOL vier Jahre später zum Jahresende. Den 8.6-Status vor dem Veröffentlichen dieses Artikels nochmal gegen php.net prüfen – Release-Pläne verschieben sich.
Für WordPress heißt das: 7.0 und 7.1 laufen offiziell auf 7.4 bis 8.5. Das „Beta-Support“-Label, das WordPress früher für neue PHP-Versionen vergeben hat, wurde im Mai abgeschafft und rückwirkend entfernt – 6.9 und 7.0 unterstützen 8.5 vollständig, 6.8+ unterstützt 8.4 vollständig. Das Label hat mehr Verwirrung gestiftet als geholfen.
Warum ich 8.4 nehme und nicht 8.5
Ich werde das öfter gefragt, weil 8.5 ja „das aktuelle“ ist. Das ist meine Praxis, kein offizieller Rat. Meine Gründe:
Plugin-Ökosystem. WordPress-Core ist auf 8.5 sauber. Die Plugins nicht alle. Ich habe im August noch ein Formular-Plugin gesehen, das auf 8.5 mit Using null as an array offset is deprecated das Admin-Interface vollgeschrieben hat – Deprecation, kein Fatal, aber der Kunde sieht gelbe Boxen und ruft an. Auf 8.4 war das Plugin still. Bei 8.4 haben die Plugin-Autoren jetzt fast zwei Jahre Vorlauf gehabt, bei 8.5 zehn Monate.
Support-Fenster. 8.4 bekommt bis Ende 2028 Security-Fixes. Bis dahin gibt es keinen versionsbedingten Zwang, die Seite anzufassen. Wer jetzt auf 8.4 geht und in zwei Jahren auf 8.6 oder 8.7, hat einen entspannten Rhythmus.
Neue Features brauche ich auf Kundenseiten nicht. Pipe-Operator, array_first(), Fatal-Error-Backtraces – nett für eigene Projekte, irrelevant für ein WordPress mit Fremd-Plugins.
Ausnahme: Neuprojekte, die ich selbst entwickle und bei denen ich die Plugins kontrolliere. Da nehme ich 8.5. Und bei Kunden, die schon auf 8.4 sind, lasse ich das so.
Was auf keinen Fall passiert: 8.6 im Dezember
8.6 ist für den 19. November geplant. Hard Feature Freeze am 22. September, RC1 zwei Tage später. Das ist ein solides Release-Verfahren, aber es ändert nichts daran, dass am 20. November kein Plugin-Autor der Welt seine Kompatibilität durch hat.
Was in 8.6 drin ist, ist für WordPress-Betrieb ohnehin unspektakulär: json_decode() sagt endlich, wo das JSON kaputt ist. Eine clamp()-Funktion. trim() schneidet jetzt auch Form-Feed ab. readonly-Properties dürfen Defaults haben. Dazu eine Reihe Deprecations, die auf PHP 9.0 vorbereiten – php.watch zählt aktuell 26 deprecatete und 15 entfernte Funktionen, vieles davon Randbereiche.
Das eigentlich große Feature ist Partial Function Application – angenommen mit 33:0, implementiert, Syntax str_replace(' ', '_', ?) gibt dir eine Closure zurück. Zusammen mit dem Pipe-Operator aus 8.5 ist das der Schritt, der PHP funktional ernst nehmen lässt. Ebenfalls konkret beschrieben für 8.6: eine Deprecation der stillen Cast-Truncation ((int) "123abc" → 123 ohne Warnung). Noch in Diskussion: BackedEnum::values().
Alles Zeug für eigene Codebasen, nicht für Hoster-Kunden.
Meine Regel: Neue PHP-Minor-Version frühestens nach dem ersten Patch-Release (.1) auf Staging, nach dem zweiten in Produktion. Für 8.6 heißt das realistisch März 2027.
Was von 8.2 auf 8.4 geprüft werden muss
Das ist der Teil, für den ich diesen Artikel eigentlich schreibe. Zwischen 8.2 und 8.4 liegen zwei Releases, und die haben ein paar Dinge geändert, die in altem Plugin- und Theme-Code regelmäßig vorkommen.
8.3: für WordPress-Code unspektakulär
get_class() und get_parent_class() ohne Argument sind deprecated. unserialize() wirft bei kaputten Daten E_WARNING statt E_NOTICE – das kann Logs füllen, wenn ein Plugin Müll in wp_options geschrieben hat. Typed Class Constants, granulare DateTime-Exceptions. Für typischen WordPress-Code ist 8.3 der harmloseste Schritt der Reihe; der vollständige Migration Guide auf php.net listet trotzdem mehr, als hier steht.
8.4: hier wird’s konkret
Implizit nullable Parameter. Das ist der Klassiker. Jede Signatur dieser Form wirft jetzt eine Deprecation:
php
// deprecated seit 8.4
function render_box( array $args = null ) { ... }
// richtig
function render_box( ?array $args = null ) { ... }
Kein Fatal, aber in Themes und Plugins von 2018 bis 2022 ist das überall. Wer WP_DEBUG an hat, sieht die Seite voll damit. Wer WP_DEBUG aus hat, sieht nichts. Die Deprecation bereitet eine spätere Verschärfung vor – deshalb jetzt migrieren, nicht erst, wenn es knallt.
E_STRICT ist nur noch ein Relikt. Hier muss ich mich selbst korrigieren – in der ersten Fassung dieses Artikels stand, dass die Konstante weg ist und einen Fatal wirft. Stimmt nicht. In 8.4 wurde das Error-Level E_STRICT entfernt; die Konstante existiert weiter und ist deprecated. Code wie error_reporting( E_ALL & ~E_STRICT ) läuft also, tut aber nichts Sinnvolles mehr und produziert eine Deprecation. Aufräumen ja, Panik nein.
bash
grep -rn "E_STRICT" wp-config.php wp-content/
imap, pspell, oci8, pdo_oci sind nicht mehr Teil der PHP-Distribution und werden separat bereitgestellt, unter anderem über PECL. Relevant: alte Mail-Piping-Plugins und Ticket-Systeme, die IMAP direkt nutzen. Wenn php -m | grep imap auf 8.2 etwas ausgibt, vorher klären, ob das ein Plugin braucht – und ob der Hoster die Extension auf 8.4 überhaupt anbietet.
mysqli_ping() und mysqli::ping() deprecated. Kommt in Custom-Code vor, der lange Verbindungen offen hält. Selten in WordPress, aber ich hatte es in einem Import-Cronjob.
Rundungslogik von round() überarbeitet – Grenzfälle, in denen die alte Pre-Rounding-Logik falsche Ergebnisse geliefert hat, sind gefixt. Normale WooCommerce-Preisberechnung ist davon nicht gefährdet. Ich klicke trotzdem einmal eine Testbestellung mit krummen Beträgen durch, weil das dreißig Sekunden kostet.
8.5: falls du doch dorthin gehst
Die Deprecations sind überschaubar: nicht-kanonische Casts ((integer), (boolean), (double)), curl_close(), xml_parser_free(), mysqli_execute(), socket_set_timeout(), alle MHASH_*-Konstanten, Ausgabe aus Output-Buffer-Handlern. Dazu die oben erwähnte Null-als-Array-Offset-Deprecation. Das sind Deprecations, keine unmittelbaren Fatals – aber sie machen Logs voll.
Neu und im Betrieb tatsächlich nützlich: max_memory_limit als Obergrenze in der php.ini, die ein Plugin per ini_set('memory_limit', ...) nicht mehr überschreiten kann. Default ist -1, also keine Grenze – das muss der Hoster oder du explizit setzen. Und Fatal Errors können jetzt einen Stack Trace ausgeben (fatal_error_backtraces). Beides Gründe, warum 8.5 für eigene Projekte die bessere Wahl ist.
Der Fahrplan, Woche für Woche
Jetzt: Inventur
Ich brauche eine Liste. Welche Seite läuft auf welcher PHP-Version, bei welchem Hoster, mit welchem Wartungsstatus. Bei mir ist das ein Sheet, das ich seit Jahren pflege. Wer das nicht hat, holt sich die Version pro Seite so:
bash
# per WP-CLI, wenn SSH da ist
wp cli info | grep "PHP version"
wp eval 'echo PHP_VERSION . PHP_EOL;'
# ohne SSH: Werkzeuge > Website-Zustand > Bericht > Server
Der Punkt ist: Die Liste muss existieren, bevor irgendwas passiert.
Woche 1–2: Statische Analyse
Bevor ich irgendeine PHP-Version umschalte, laufe ich mit phpcs und dem PHPCompatibility-Standard über wp-content:
bash
composer global require --dev phpcompatibility/php-compatibility \
dealerdirect/phpcodesniffer-composer-installer
phpcs -p \
--standard=PHPCompatibility \
--runtime-set testVersion 8.4 \
--extensions=php \
--ignore='*/node_modules/*,*/vendor/*' \
--report=summary \
wp-content/plugins wp-content/themes wp-content/mu-plugins
Das findet direkte Verwendungen deprecateter oder entfernter APIs – je nach Sniff-Version auch die implizit nullablen Parameter. Was es nicht findet, ist Laufzeitverhalten: Arrays, die plötzlich null sind, Funktionen mit geänderten Rückgabewerten, Extensions, die nur indirekt gebraucht werden. Dafür gibt es Schritt 3.
Mit --report=summary bekomme ich eine Liste pro Plugin. Plugins mit vielen Fehlern schaue ich mir an: Gibt es ein Update? Ist das Plugin überhaupt noch gepflegt? Zwei Drittel meiner Funde lösen sich durch „Plugin aktualisieren“ oder „Plugin ersetzen“.
Woche 3–6: Staging, eine Seite nach der anderen
Staging-Kopie hochziehen, PHP-Version dort umstellen, WP_DEBUG_LOG an, Seite durchklicken. Nicht nur das Frontend – Admin-Screens der Plugins, Formulare absenden, Cronjobs anstoßen, bei Shops eine Bestellung mit Gutschein und krummem Betrag.
php
// wp-config.php auf Staging
define( 'WP_DEBUG', true );
define( 'WP_DEBUG_LOG', true );
define( 'WP_DEBUG_DISPLAY', false );
Danach:
bash
grep -i "deprecated\|fatal\|warning" wp-content/debug.log | sort | uniq -c | sort -rn | head -40
Das ist die Liste, die ich mit dem Kunden bespreche. Nicht die vollständige – die eindeutig zuzuordnende: „Plugin X ist seit 2021 nicht aktualisiert und wirft 40 Deprecations, wir tauschen es gegen Y.“
Wie die PHP-Version umgestellt wird, ist Hoster-Sache. Bei Plesk und cPanel ist es ein Dropdown pro Domain. Bei manchen Shared-Hostern geht es über .htaccess, bei anderen über .user.ini oder das Kundenmenü:
apache
# Beispiel, Handler-Name ist hosterspezifisch – Doku lesen
AddHandler php84-cgi .php
Wer Docker oder einen eigenen Server hat, weiß es selbst. Wichtig ist nur: Der Weg zurück muss genauso schnell gehen wie der Weg hin. Bevor ich Produktion umschalte, habe ich den Rollback einmal auf Staging geübt.
Woche 7–10: Produktion
Umstellung in einem Zeitfenster mit wenig Traffic, mit dem Kunden abgesprochen. Vorher volles Backup, das ich einmal probeweise zurückgespielt habe. Umschalten, debug.log zehn Minuten beobachten, Kernfunktionen einmal durchklicken, fertig. Bei den meisten Seiten dauert das eine halbe Stunde. Bei den drei bis vier mit altem Custom-Code einen halben Tag.
Nach der Umstellung lasse ich WP_DEBUG_LOG noch ein paar Tage an, ohne WP_DEBUG_DISPLAY. Zwei Dinge dazu: debug.log kann Pfade, Query-Fragmente und im schlechtesten Fall Nutzerdaten enthalten – die Datei darf nicht öffentlich abrufbar sein. Entweder per WP_DEBUG_LOG einen Pfad außerhalb des Webroots angeben oder den Zugriff auf wp-content/debug.log in der Serverkonfiguration sperren. Und: so kurz wie möglich. Einmal auswerten, dann aus.
php
// Log außerhalb des Webroots
define( 'WP_DEBUG_LOG', '/var/log/wp/kunde-debug.log' );
Woche 11–12: Puffer
Weil immer etwas dazwischenkommt. Und weil ich nicht am 23. Dezember eine Seite umstellen will.
Die Hoster-Frage
Das Bild ist uneinheitlich. Die größeren Anbieter haben 8.4 und 8.5 im Angebot. Was mit 8.2 nach dem Supportende passiert, hängt vom Hoster ab: Manche bieten kostenpflichtigen Extended Support an, manche stellen nach Ankündigung automatisch auf eine neuere Version um, manche schalten irgendwann ab, manche lassen es einfach laufen. Alle vier Varianten habe ich gesehen.
Die kritische ist die automatische Umstellung. Sie kommt per E-Mail, die der Kunde nicht zuordnen kann, und drei Wochen später ist die Seite weiß, weil ein Plugin von 2019 auf 8.4 nicht läuft. Das ist der Moment, in dem Kunden ohne Wartungsvertrag anrufen.
Ich schreibe deshalb im Oktober jedem Kunden ohne Wartungsvertrag eine Mail: Welche PHP-Version läuft, was der Hoster laut dessen Ankündigungen vorhat, was ich anbiete. Manche nehmen es an, manche nicht. Aber niemand kann im Januar sagen, er hätte es nicht gewusst.
Was ich Kunden dazu sage
Kurzfassung, die ich verschicke, in etwa:
Ihre Website läuft auf PHP 8.2. Diese Version bekommt ab Januar 2027 keine Sicherheitsupdates mehr. Ihr Hoster kann sie danach abschalten, automatisch auf eine neuere Version umstellen oder nur noch gegen Aufpreis weiterbetreiben – was genau, steht in dessen Ankündigungen. Ich empfehle eine geplante Umstellung auf PHP 8.4, die bis Ende 2028 gepflegt wird. Aufwand: eine Testumgebung, ein Termin für die Umstellung, ca. X Stunden. Ohne geplante Umstellung riskieren Sie, dass die Seite bei einer automatischen Umstellung durch den Hoster ausfällt.
Keine Technik, keine Versionsnummern-Diskussion. Das Risiko und der Preis.
Fazit
8.2 EOL ist kein Notfall, aber ein Termin. Wer die Liste hat, phpcs einmal drüberlaufen lässt und pro Woche zwei Seiten auf Staging testet, ist Ende November durch – bevor die Hoster anfangen, von sich aus umzuschalten.
8.4 ist mein Ziel für Kundenseiten. 8.5 für eigene Projekte. 8.6 im Frühjahr, wenn die Plugins nachgezogen haben.
Und E_STRICT aus der wp-config.php löschen. Nicht weil es knallt – sondern weil es seit zwei PHP-Versionen nichts mehr tut.
Quellen
- PHP: Supported Versions
- PHP 8.6 Release Plan (PHP Wiki)
- PHP 8.3 Migration Guide
- PHP 8.4 Migration Guide
- PHP 8.5 Migration Guide
- PHP RFC: Partial Function Application (v2)
- PHP RFC: clamp()
- PHP.Watch: PHP 8.6 – What’s New and Changed
- PHP.Watch: PHP 8.5 – What’s New and Changed
- PHP Compatibility and WordPress Versions (Core Handbook)
- PHP support clarification, spring 2026 edition (Make/Core)
- PHP 8.5 support in WordPress 6.9 (Make/Core)
- PHPCompatibility Coding Standard (GitHub)