WordPress ist ein Kraftpaket, aber die Standardeinstellungen nach dem Prinzip “eine Lösung für alle” bedeuten, dass es oft mit Ballast ausgeliefert wird, den die meisten modernen Projekte nicht brauchen. Über die Jahre habe ich ein spezifisches Set an Snippets verfeinert, um das System zu entschlacken, ohne das Kernerlebnis zu beeinträchtigen.
Dieser Guide ist mehr als nur eine Liste von Dingen, die man löschen kann; es ist ein strategischer Ansatz für Performance. Inspiriert von Terence Edens exzellenter Liste, ergänzt um meine eigenen, im Produktivbetrieb erprobten Lösungen. Jeder Hook-Name unten wurde gegen den Quellcode von WordPress 7.1.3 geprüft (laut Versionsabfrage bei api.wordpress.org die aktuelle Version am 12. Oktober 2026), und Snippets, die sich als veraltet, falsch oder schädlich erwiesen haben, sind entsprechend markiert. Wenn Sie die Arbeit lieber abgeben möchten, finden Sie hier unsere WordPress-Entwicklung als Dienstleistung.
Warum WordPress entschlacken
Warum sollte man sich über ein paar kleine Skripte Gedanken machen? Weil sie sich summieren. Jede unnötige Zeile ist ein potenzieller Konflikt, eine winzige Rendering-Verzögerung oder ein verschwendetes Byte.
Unsere Ziele:
- DOM-Größe, Entfernen nicht genutzter Inline-Styles.
- HTTP-Overhead, Dequeuing von Skripten, die nicht geladen werden sollten.
- Sicherheitsfläche, Deaktivierung veralteter Protokolle wie XML-RPC.
- Core Web Vitals, Direkter Einfluss auf LCP und CLS durch Entfernen renderblockierender Elemente.
[!IMPORTANT] Vorsicht geboten: Nicht jeder “Ballast” ist nutzlos. Wenn Sie auf das spezifische Styling des Classic Editors angewiesen sind oder die eingebauten Emojis für ältere Browser brauchen, sind manche dieser Fixes eventuell nicht für Sie geeignet. Testen Sie Änderungen zuerst in einer Staging-Umgebung.
Wie man ein komplettes Debloat-Skript für WordPress einsetzt
Fügen Sie Folgendes zur functions.php-Datei Ihres Themes hinzu, oder besser in ein MU-Plugin (siehe letzter Abschnitt), damit der Code einen Theme-Wechsel übersteht. Jeder Abschnitt ist mit Erklärungen und Quelllinks kommentiert.
1. Classic Theme Styles entfernen
WordPress fügt “classic-theme-styles” bei Themes ohne theme.json-Datei hinzu. Der Core lädt das Stylesheet nur, wenn wp_theme_has_theme_json() false zurückgibt; ein Block-Theme oder ein klassisches Theme mit theme.json lädt es also nie. Wenn Ihres es lädt, entfernen Sie es:
// Obligatorisches Classic Theme entfernen.
function disable_classic_theme_styles() {
wp_deregister_style( "classic-theme-styles" );
wp_dequeue_style( "classic-theme-styles" );
}
add_action( "wp_enqueue_scripts", "disable_classic_theme_styles" );2. Emoji-Unterstützung entfernen
WordPress gibt ein kleines Erkennungsskript aus. Nur wenn der Browser aktuelle Emojis nicht darstellen kann, lädt es ein größeres Skript nach, das Emoji-Zeichen durch SVG-Bilder ersetzt. Wenn Ihr Publikum aktuelle Browser nutzt, ist das unnötig:
// WP Emoji entfernen.
// https://www.denisbouquet.com/remove-wordpress-emoji-code/
remove_action( "wp_head", "print_emoji_detection_script", 7 );
remove_action( "wp_print_styles", "print_emoji_styles" );
remove_action( "admin_print_scripts", "print_emoji_detection_script" );
remove_action( "admin_print_styles", "print_emoji_styles" );
// Die SVG-Basis-URL in den Emoji-Einstellungen leeren.
add_filter( "emoji_svg_url", "__return_false" );
// Emoji-Ersetzung mit Bildern in RSS / Atom Feeds stoppen
// https://danq.me/2023/09/04/wordpress-stop-emoji-images/
remove_filter( "the_content_feed", "wp_staticize_emoji" );
remove_filter( "comment_text_rss", "wp_staticize_emoji" );3. Automatische Textformatierung deaktivieren
WordPress “texturisiert” Ihren Inhalt: gerade Anführungszeichen werden typografisch, ASCII -- / --- werden zu Halbgeviert- bzw. Geviertstrich (U+2013 / U+2014). Das zerlegt Code-Beispiele und widerspricht einer ASCII-Bindestrich-Policy (- oder --, keine Langstrich-Glyphen in der Quelle). Auf technischem Content abschalten:
// Automatische Formatierung entfernen.
// https://css-tricks.com/snippets/wordpress/disable-automatic-formatting/
remove_filter( "the_content", "wptexturize" );
remove_filter( "the_excerpt", "wptexturize" );
remove_filter( "comment_text", "wptexturize" );
remove_filter( "the_title", "wptexturize" );
// Weitere Formatierungsfilter.
add_action("init", function() {
remove_filter( "the_content", "convert_smilies", 20 );
foreach ( array( "the_content", "the_title", "wp_title", "document_title" ) as $filter ) {
remove_filter( $filter, "capital_P_dangit", 11 );
}
remove_filter( "comment_text", "capital_P_dangit", 31 );
// NUR für Classic-Editor-Seiten: Diese Zeile stoppt jedes Block-Rendering.
remove_filter( "the_content", "do_blocks", 9 );
}, 11);Hinweis: Der Filter
capital_P_dangitist die Art, wie WordPressWordpress(mit kleinem p) automatisch inWordPresskorrigiert. Er ist aggressiv und manchmal unerwünscht.
[!WARNING] Wenn Sie
do_blocksausthe_contententfernen, wird Block-Markup nicht mehr geparst. Dynamische Blöcke (Query Loop, neueste Beiträge, Navigation) geben nichts mehr aus. Behalten Sie diese Zeile nur auf einer Seite, deren Beiträge ausnahmslos im Classic Editor geschrieben wurden.
4. Gutenberg-Styles und -Skripte entfernen
Wenn Sie ein benutzerdefiniertes Theme verwenden und nicht auf die Frontend-Styles von Gutenberg angewiesen sind, entfernen Sie sie. Auf einem Block-Theme lassen Sie das bleiben: Die globalen Styles tragen das gesamte Design aus theme.json.
// Gutenberg Styles entfernen.
// https://wordpress.org/support/topic/how-to-disable-inline-styling-style-idglobal-styles-inline-css/
remove_action( "wp_enqueue_scripts", "wp_enqueue_global_styles" );
// Bei klassischen Themes hängt der Core es zusätzlich mit Priorität 1 an wp_footer.
remove_action( "wp_footer", "wp_enqueue_global_styles", 1 );
// Gutenberg Editing Widgets entfernen.
// Von https://wordpress.org/plugins/classic-widgets/
// Verhindert, dass der Block-Editor im Gutenberg-Plugin die Widgets verwaltet.
add_filter( "gutenberg_use_widgets_block_editor", "__return_false" );
// Verhindert, dass der Block-Editor die Widgets verwaltet.
add_filter( "use_widgets_block_editor", "__return_false" );
// Gutenberg Block Library CSS vom Frontend-Laden entfernen.
// https://smartwp.com/remove-gutenberg-css/
function remove_wp_block_library_css() {
wp_dequeue_style( "wp-block-library" );
wp_dequeue_style( "wp-block-library-theme" );
}
add_action( "wp_enqueue_scripts", "remove_wp_block_library_css", 100 );5. Header-Meta-Tags entfernen
Bereinigen Sie Ihren <head>-Abschnitt, indem Sie unnötige Meta-Tags entfernen:
// Shortlink entfernen.
// https://stackoverflow.com/questions/42444063/disable-wordpress-short-links
remove_action( "wp_head", "wp_shortlink_wp_head" );
// RSD entfernen.
// https://wpengineer.com/1438/wordpress-header/
remove_action( "wp_head", "rsd_link" );
// Extra Feed-Links entfernen.
// https://developer.wordpress.org/reference/functions/feed_links/
add_filter( "feed_links_show_comments_feed", "__return_false" );
add_filter( "feed_links_show_posts_feed", "__return_false" );
// api.w.org Link entfernen.
// https://wordpress.stackexchange.com/questions/211467/remove-json-api-links-in-header-html
remove_action( "wp_head", "rest_output_link_wp_head" );
// https://wordpress.stackexchange.com/questions/211817/how-to-remove-rest-api-link-in-http-headers
// https://developer.wordpress.org/reference/functions/rest_output_link_header/
remove_action( "template_redirect", "rest_output_link_header", 11, 0 );6. Bildverbesserungen entfernen
WordPress fügt Bildern die Attribute srcset, sizes, loading, decoding und fetchpriority hinzu. Wenn Sie diese selbst handhaben, entfernen Sie sie, aber lesen Sie vorher den Bildabschnitt weiter unten, denn diese Attribute schützen LCP und CLS:
// WordPress erzwungene Bildgröße entfernen
// https://core.trac.wordpress.org/ticket/62413#comment:40
add_filter( "wp_img_tag_add_auto_sizes", "__return_false" );
// <img> Verbesserungen entfernen
// https://developer.wordpress.org/reference/functions/wp_filter_content_tags/
remove_filter( "the_content", "wp_filter_content_tags", 12 );
// Umschreiben von http:// URLs für die Hauptdomain stoppen.
// https://developer.wordpress.org/reference/hooks/wp_should_replace_insecure_home_url/
remove_filter( "the_content", "wp_replace_insecure_home_url", 10 );
// Attachment-Stuff entfernen
// https://developer.wordpress.org/news/2024/01/building-dynamic-block-based-attachment-templates-in-themes/
remove_filter( "the_content", "prepend_attachment" );
// Block-Filter entfernen
remove_filter( "the_content", "apply_block_hooks_to_content_from_post_object", 8 );7. Browser-Check und andere Admin-Funktionen entfernen
// Browser-Check aus dem Admin-Dashboard entfernen.
// https://core.trac.wordpress.org/attachment/ticket/27626/disable-wp-check-browser-version.0.2.php
if ( !empty( $_SERVER["HTTP_USER_AGENT"] ) ) {
add_filter( "pre_site_transient_browser_" . md5( $_SERVER["HTTP_USER_AGENT"] ), "__return_null" );
}
// Hovercards auf Kommentar-Links im Admin-Bereich entfernen.
// https://wordpress.org/support/topic/how-to-disable-mshots-service/#post-12946617
add_filter( "akismet_enable_mshots", "__return_false" );Was man in WordPress zusätzlich entfernen sollte
Über die obigen Techniken hinaus sind hier meine eigenen Lösungen für weitere Optimierung:
8. XML-RPC deaktivieren
Wenn Sie keine externen Apps zum Posten auf WordPress verwenden, schalten Sie die XML-RPC-Methoden ab, die eine Anmeldung erfordern, und gleich mit ihnen die Pingback-Methoden. Der Filter xmlrpc_enabled allein schaltet den Endpunkt nicht ab (Details weiter unten):
// XML-RPC-Methoden deaktivieren, die eine Authentifizierung erfordern
add_filter( 'xmlrpc_enabled', '__return_false' );
// Pingback-Methoden entfernen, die sonst offen bleiben
add_filter( 'xmlrpc_methods', function( $methods ) {
unset( $methods['pingback.ping'], $methods['pingback.extensions.getPingbacks'] );
return $methods;
} );
// XML-RPC-Link aus dem Head entfernen
remove_action( 'wp_head', 'rsd_link' );9. jQuery Migrate entfernen
Moderne WordPress-Themes und -Plugins benötigen selten jQuery Migrate. Wenn Ihre Website ohne es funktioniert, entfernen Sie es:
function remove_jquery_migrate( $scripts ) {
if ( ! is_admin() && isset( $scripts->registered['jquery'] ) ) {
$script = $scripts->registered['jquery'];
if ( $script->deps ) {
$script->deps = array_diff( $script->deps, array( 'jquery-migrate' ) );
}
}
}
add_action( 'wp_default_scripts', 'remove_jquery_migrate' );10. oEmbed deaktivieren
Wenn keine andere Website Ihre Beiträge einbetten muss, schalten Sie die Anbieterseite von oEmbed ab. Einbettungen von YouTube und anderen registrierten Anbietern in Ihren eigenen Beiträgen funktionieren weiter, weil WordPress die automatische Erkennung nur für URLs ausführt, die nicht auf seiner eingebauten Anbieterliste stehen:
// oEmbed-Discovery-Links entfernen
remove_action( 'wp_head', 'wp_oembed_add_discovery_links' );
remove_action( 'wp_head', 'wp_oembed_add_host_js' );
// oEmbed REST API Endpoint entfernen
remove_action( 'rest_api_init', 'wp_oembed_register_route' );
// oEmbed Auto-Discovery deaktivieren
add_filter( 'embed_oembed_discover', '__return_false' );11. JavaScript-Laden verzögern
Fügen Sie defer zu nicht-kritischen Skripten für bessere Performance hinzu. Der Filter unten ist der alte Weg und ignoriert die Abhängigkeitsregeln, die der Core seit WordPress 6.3 anwendet; der Abschnitt zur Ladestrategie weiter unten zeigt den unterstützten Weg:
function add_defer_attribute( $tag, $handle ) {
// Skripte, die NICHT verzögert werden sollten
$scripts_to_not_defer = array( 'jquery-core' );
if ( in_array( $handle, $scripts_to_not_defer ) || str_contains( $tag, ' defer' ) ) {
return $tag;
}
return str_replace( ' src', ' defer src', $tag );
}
add_filter( 'script_loader_tag', 'add_defer_attribute', 10, 2 );Wie man die Wirkung von WordPress Debloat misst
Nachdem Sie diese Änderungen implementiert haben, testen Sie Ihre Website mit:
- Google PageSpeed Insights, Überprüfen Sie Ihre Core Web Vitals
- GTmetrix, Detaillierte Wasserfall-Analyse
- WebPageTest, Mehrere Teststandorte und Verbindungsgeschwindigkeiten
Sie sollten sehen:
- Reduzierte Seitengröße (weniger CSS/JS-Bytes)
- Weniger HTTP-Anfragen
- Besserer Largest Contentful Paint (LCP), wenn ein entferntes Asset renderblockierend war
Die Serverantwortzeit (TTFB) bewegt sich kaum, weil keines dieser Snippets ändert, wie PHP die Seite aufbaut. Die TTFB verbessert erst eine Caching-Schicht.
Was eine Standardinstallation von WordPress 7.1 lädt
Bevor Sie etwas entfernen, hilft es zu wissen, was jede Funktion kostet. Die Größen unten wurden an den Dateien im offiziellen wordpress-7.1.3.zip gemessen: Rohgröße auf der Festplatte und Größe nach gzip auf Stufe 9, was nahe an dem liegt, was ein Server tatsächlich überträgt.
| Asset | Datei | Roh | Gzip | Wann es lädt |
|---|---|---|---|---|
| Emoji-Loader (inline, Footer) | wp-emoji-loader.min.js | 2.977 B | 1.290 B | Auf jeder Frontend-Seite |
| Emoji-Ersetzungsskript | wp-emoji-release.min.js | 22.752 B | 5.310 B | Nur wenn der Browser den Emoji-Test nicht besteht |
| Classic Theme Styles | classic-themes.min.css | 291 B | 233 B | Themes ohne theme.json |
| Kombinierte Block Library | block-library/style.min.css | 140.829 B | 18.938 B | Nur wenn Block-Styles bei Bedarf deaktiviert sind |
| Theme-Styles der Block Library | block-library/theme.min.css | 2.752 B | 751 B | Themes, die wp-block-styles deklarieren, bei deaktiviertem Laden nach Bedarf |
| jQuery | jquery.min.js | 87.553 B | 30.356 B | Wenn das Theme oder ein Plugin es einreiht |
| jQuery Migrate | jquery-migrate.min.js | 13.577 B | 4.891 B | Zusammen mit dem Handle jquery |
| Dashicons | dashicons.min.css | 59.004 B | 35.693 B | Admin-Leiste für angemeldete Nutzer oder ein Plugin |
| Host-Skript für Beitrags-Embeds | wp-embed.min.js | 1.251 B | 710 B | Nur auf Seiten, die einen WordPress-Beitrag einbetten |
| Heartbeat | heartbeat.min.js | 5.947 B | 2.058 B | Admin-Bildschirme, im Frontend nur auf Anforderung eines Plugins |
| Kommentarantwort | comment-reply.min.js | 2.950 B | 1.371 B | Wenn das Theme oder der Kommentar-Block es einreiht |
Zwei Zahlen fallen auf. jQuery plus Migrate ist meist das Schwerste, was ein klassisches Theme ausliefert, deshalb spart der Verzicht auf jQuery im eigenen Theme-Code mehr als alle Anpassungen an Head-Tags zusammen. Und das 140 KB große Stylesheet der Block Library wird bei einer Standardinstallation nicht mehr komplett geladen: Block-Themes laden seit WordPress 5.9 nur die Styles der Blöcke, die tatsächlich auf der Seite stehen, und seit 6.9 aktiviert der Core dasselbe Laden nach Bedarf über wp_load_classic_theme_block_styles_on_demand() auch für klassische Themes, solange der Ausgabepuffer für Templates aktiv ist. Ein Theme schaltet das ab, indem es aus den Filtern should_load_separate_core_block_assets und should_load_block_assets_on_demand false zurückgibt.
Was eine bestimmte Seite wirklich lädt, zeigt der Browser. Öffnen Sie in den Chrome DevTools den Tab “Network”, laden Sie die Seite bei deaktiviertem Cache neu, filtern Sie nach Ihrer eigenen Domain und sortieren Sie nach Größe. Lighthouse im selben DevTools-Panel listet ungenutztes CSS und JavaScript pro Datei auf. WP-CLI hilft hier nicht: Ein Aufruf von wp eval rendert nie ein Template, daher sind die ausgegebenen Skript- und Style-Warteschlangen leer. Ein protokollierender Footer-Hook funktioniert dagegen:
// Jedes eingereihte Handle bei Frontend-Seitenaufrufen protokollieren (nur Staging).
add_action( 'wp_footer', function () {
if ( is_admin() ) {
return;
}
foreach ( wp_scripts()->queue as $handle ) {
error_log( 'script: ' . $handle . ' ' . wp_scripts()->registered[ $handle ]->src );
}
foreach ( wp_styles()->queue as $handle ) {
error_log( 'style: ' . $handle . ' ' . wp_styles()->registered[ $handle ]->src );
}
}, 999 );Welche WordPress-Funktionen man deaktivieren kann, Funktion für Funktion
Das Skript oben ist die Kurzfassung. Im Folgenden bekommt jede Funktion den Kontext, den Sie für die Entscheidung brauchen, ob sie auf Ihre Seite gehört.
Was Classic Theme Styles sind und was sie kosten
WordPress 6.1 hat ein kleines Stylesheet eingeführt, das klassischen Themes sinnvolle Standards für Block-Markup gibt, etwa Abstände bei Button- und Datei-Blöcken. Es wiegt 291 Bytes und wird von wp_enqueue_classic_theme_styles() nur eingereiht, wenn das aktive Theme keine theme.json hat. Entfernen Sie es bei einem klassischen Theme mit eigenem Block-CSS. Behalten Sie es bei klassischen Themes, die darauf angewiesen sind, dass Core-Block-Markup ohne Zusatzaufwand richtig aussieht, und kümmern Sie sich bei Block-Themes gar nicht darum, denn dort lädt es nie.
Warum WordPress ein Emoji-Skript lädt
Die Emoji-Funktion erledigt zwei Aufgaben: Sie prüft, ob der Browser aktuelle Emojis zeichnen kann, und falls nicht, lädt sie wp-emoji-release.min.js, das die Zeichen durch Bilder von s.w.org ersetzt. In WordPress 7.1.3 ist dieser Test ein Inline-Skript mit type="module" im Footer, blockiert das Rendering also nicht mehr, und die Ergebnisse werden in sessionStorage zwischengespeichert. Dazu kommt ein kleines Inline-Stylesheet für img.emoji. Das Entfernen der Aktion wp_print_styles funktioniert weiterhin: wp_enqueue_emoji_styles() prüft, ob diese Aktion vorhanden ist, und lässt das Inline-CSS weg, wenn sie fehlt.
Der Filter emoji_svg_url setzt inzwischen nur noch die SVG-Basis-URL in den Emoji-Einstellungen. Ältere Anleitungen nutzten ihn, um einen DNS-Prefetch zu s.w.org zu entfernen; wp_resource_hints() fügt diesen Hinweis in 7.1.3 nicht mehr hinzu, die Zeile schadet also nicht, spart aber auch keine DNS-Abfrage mehr. Behalten Sie die Emoji-Unterstützung, wenn Besucher in Kommentaren oder Foren von alten Geräten aus schreiben, deren Schriften keine aktuellen Emojis enthalten. Die vollständige Variante deckt auch E-Mails und den Classic Editor ab:
function disable_emojis_completely() {
remove_action( 'wp_head', 'print_emoji_detection_script', 7 );
remove_action( 'wp_print_styles', 'print_emoji_styles' );
remove_action( 'admin_print_scripts', 'print_emoji_detection_script' );
remove_action( 'admin_print_styles', 'print_emoji_styles' );
remove_action( 'embed_head', 'print_emoji_detection_script' );
remove_filter( 'the_content_feed', 'wp_staticize_emoji' );
remove_filter( 'comment_text_rss', 'wp_staticize_emoji' );
remove_filter( 'wp_mail', 'wp_staticize_emoji_for_email' );
add_filter( 'tiny_mce_plugins', function ( $plugins ) {
return array_diff( $plugins, array( 'wpemoji' ) );
} );
}
add_action( 'init', 'disable_emojis_completely' );Was wptexturize an Ihren Inhalten ändert
wptexturize() macht aus geraden Anführungszeichen typografische, aus -- und --- Halbgeviert- und Geviertstriche und aus drei Punkten ein Auslassungszeichen. Bei technischen Inhalten beschädigt das Shortcodes sowie HTML- und PHP-Fragmente, die Leser kopieren. Die ganze Funktion lässt sich mit einem einzigen Filter abschalten, statt sie aus jedem Hook einzeln zu entfernen:
add_filter( 'run_wptexturize', '__return_false' );Behalten Sie sie nur auf redaktionellen Seiten, die typografische Anführungszeichen wollen und nie Code veröffentlichen.
Was der Filter capital_P_dangit macht
capital_P_dangit() ersetzt Wordpress durch WordPress. In Titeln ersetzt er jedes Vorkommen, in Inhalten und Kommentaren nur nach einem Leerzeichen, einem Anführungszeichen, > oder (. URLs fasst er nicht an, weil ein Schrägstrich vor dem Wort nicht passt. Das eigentliche Risiko ist Code: Ein Beispiel, das Wordpress nach einem Leerzeichen enthält, wird stillschweigend verändert.
Welche Styles und Skripte der Block-Editor hinzufügt
Im Frontend steuert der Block-Editor wp-block-library (das Block-CSS), wp-block-library-theme (meinungsstarke Theme-Styles) und die aus theme.json erzeugten Inline-global-styles bei. wp-components gehört zu den Editor-Bildschirmen, daher bewirkt ein Dequeue im Frontend nichts. Ältere Snippets entfernen außerdem wp_global_styles_render_svg_filters aus wp_body_open; diese Funktion wurde in 6.3.0 als veraltet markiert und hängt an keinem Hook mehr. Entfernen Sie Block-CSS nur auf Seiten, die im Frontend keine Blöcke rendern. Auf einem Block-Theme nimmt das Entfernen der globalen Styles dem Theme sein Design.
Welche Head-Tags WordPress hinzufügt und welche man entfernen sollte
Ein standardmäßiges wp_head gibt in 7.1.3 unter anderem Folgendes aus:
<meta name="generator" content="WordPress 7.1.3" />
<link rel="shortlink" href="https://example.com/?p=123" />
<link rel="EditURI" type="application/rsd+xml" title="RSD" href="https://example.com/xmlrpc.php?rsd" />
<link rel="https://api.w.org/" href="https://example.com/wp-json/" />
<link rel="alternate" type="application/json" href="https://example.com/wp-json/wp/v2/posts/123" />| Tag | Risiko | Empfehlung |
|---|---|---|
| generator | Gering, die Version steht ohnehin als ?ver= an Core-Assets | Nach Belieben entfernen, es verbirgt wenig |
| shortlink | Keines | Entfernen |
| RSD (EditURI) | Verweist Clients auf xmlrpc.php | Zusammen mit XML-RPC entfernen |
| REST-API-Links | Gering | Behalten, wenn etwas Ihre API automatisch erkennt |
Zwei Entfernungen, die in vielen Anleitungen noch auftauchen, bewirken in aktuellen Versionen nichts: wlwmanifest_link wurde in 6.3.0 als veraltet markiert und wird nicht mehr ausgegeben, und adjacent_posts_rel_link_wp_head nutzt der Core seit 5.6.0 nicht mehr. Eine aktuelle Bereinigung ist kürzer:
add_action( 'init', function () {
remove_action( 'wp_head', 'wp_generator' );
remove_action( 'wp_head', 'wp_shortlink_wp_head' );
remove_action( 'template_redirect', 'wp_shortlink_header', 11 );
remove_action( 'wp_head', 'rsd_link' );
} );Was WordPress zu Bildern hinzufügt
wp_filter_content_tags() ergänzt srcset und sizes, width und height, wo sie fehlen, loading="lazy" bei Bildern unterhalb des sichtbaren Bereichs sowie decoding="async" und fetchpriority="high" beim voraussichtlichen LCP-Bild. Der Filter wp_img_tag_add_auto_sizes kam mit 6.7.0, nicht früher. Das Entfernen dieser Funktionen verschlechtert meist CLS und LCP, also das Gegenteil des Ziels; tun Sie es nur, wenn ein CDN oder Ihr eigenes Markup alle diese Attribute setzt. Um nur das Lazy Loading abzuschalten:
add_filter( 'wp_lazy_loading_enabled', '__return_false' );Wie der Browser-Check im Dashboard funktioniert
wp_check_browser_version() fragt bei api.wordpress.org nach, ob der Browser des Admins veraltet ist, und speichert die Antwort eine Woche lang als Site-Transient, dessen Schlüssel ein MD5 des User-Agents ist. Das ist eine externe Anfrage pro Browser und Woche, nicht pro Aufruf einer Admin-Seite. Die PHP-Versionsprüfung arbeitet genauso, aber der Transient-Schlüssel ist php_check_ plus ein MD5 von PHP_VERSION, nicht des User-Agents; Snippets, die pre_site_transient_phpcompat_ filtern, bewirken deshalb nichts:
add_filter( 'pre_site_transient_php_check_' . md5( PHP_VERSION ), '__return_null' );Behalten Sie diese Prüfung, solange niemand sonst die PHP-Version überwacht, denn sie ist die Warnung, die Seitenbetreibern sagt, dass ihre PHP-Version nicht mehr unterstützt wird.
Was der Filter xmlrpc_enabled wirklich abschaltet
XML-RPC ist das Protokoll für entferntes Veröffentlichen hinter älteren mobilen Clients, Desktop-Editoren und Pingbacks. Der Filtername klingt nach einem Hauptschalter, doch der Quellcode von WordPress 7.1.3 sagt im Docblock der Methode wp_xmlrpc_server::set_is_enabled() etwas anderes:
“Entgegen seinem Namen steuert dieser Filter nicht, ob XML-RPC vollständig aktiviert ist, sondern nur, ob XML-RPC-Methoden aktiviert sind, die eine Authentifizierung erfordern, etwa zum Veröffentlichen.”
Quelle: Docblock von wp_xmlrpc_server::set_is_enabled() (eigene Übersetzung).
Nach add_filter( 'xmlrpc_enabled', '__return_false' ) antwortet xmlrpc.php also weiterhin, und pingback.ping funktioniert nach wie vor. Pingbacks sind der Teil, der für reflektierten Traffic missbraucht wird, und mit system.multicall kann eine einzige Anfrage viele Anmeldeversuche transportieren; das stoppt der Filter tatsächlich, weil diese Methoden eine Authentifizierung brauchen. Das Snippet in Abschnitt 8 entfernt zusätzlich die Pingback-Methoden über xmlrpc_methods. Der HTTP-Header X-Pingback wird nur bei einzelnen Beiträgen gesendet, die Pings erlauben, daher entfernt das Schließen der Pings (siehe folgende Abschnitte) auch ihn. Um den Endpunkt vollständig abzuschalten, sperren Sie xmlrpc.php auf Webserver-Ebene; prüfen Sie danach jedes Plugin und jede App, die aus der Ferne veröffentlicht, denn sie funktioniert dann nicht mehr.
Wofür jQuery Migrate da ist
jQuery Migrate stellt jQuery-APIs wieder her, die in späteren jQuery-Versionen entfernt wurden, und protokolliert Warnungen, wenn alter Code sie aufruft. WordPress registriert das Handle jquery als Alias für jquery-core plus jquery-migrate; deshalb bearbeitet das Snippet in Abschnitt 9 die Abhängigkeitsliste, statt eine Datei aus der Warteschlange zu nehmen. Bevor Sie es auf der Produktivseite entfernen, laden Sie die Seite auf Staging mit define( 'SCRIPT_DEBUG', true );. Damit liefert WordPress das nicht minifizierte jquery-migrate.js aus, das der Core zum Debuggen bereithält, und Sie können in der Konsole nach JQMIGRATE-Warnungen zu veralteten Aufrufen suchen. Rufen Sie im Frontend nicht wp_deregister_script( 'jquery-migrate' ) auf; jedes Plugin, das jquery-migrate als Abhängigkeit deklariert, verlöre dann sein eigenes Skript, weil WordPress ein Skript mit fehlender Abhängigkeit nicht ausgibt.
Wie oEmbed in WordPress funktioniert
oEmbed hat zwei Seiten. Als Konsument macht WordPress aus einem eingefügten YouTube- oder Vimeo-Link einen Player, gestützt auf seine eingebaute Anbieterliste; das funktioniert auch nach dem Snippet in Abschnitt 10 weiter. Als Anbieter gibt Ihre Seite Discovery-Links aus und stellt /wp-json/oembed/1.0/embed bereit, damit andere WordPress-Seiten Ihre Beiträge einbetten können. Das Skript wp-embed (710 Bytes gzip-komprimiert) wird nur auf Seiten eingereiht, die eine solche Beitragseinbettung enthalten. Zwei Zeilen aus älterem Code zum Abschalten von Embeds sollten Sie nicht übernehmen: Das Entfernen von wp_filter_oembed_result aus oembed_dataparse schaltet die Bereinigung ab, die der Core auf HTML von Anbietern außerhalb der vertrauenswürdigen Liste anwendet, und das TinyMCE-Plugin wpembed gibt es nicht mehr, daher bewirkt das Herausfiltern aus tiny_mce_plugins nichts.
Wie man die REST API einschränkt, ohne den Block-Editor zu beschädigen
Die REST API antwortet unter /wp-json/ und wird vom Block-Editor, vom Site-Editor und von vielen Plugins genutzt. Das offizielle REST API Handbook ist in seinen häufig gestellten Fragen eindeutig:
“Sie sollten die REST API nicht deaktivieren; damit legen Sie Funktionen im WordPress-Admin lahm, die darauf angewiesen sind, dass die API aktiv ist.”
Quelle: Häufig gestellte Fragen im REST API Handbook (eigene Übersetzung).
Stattdessen empfiehlt das Handbook, über den Filter rest_authentication_errors eine Authentifizierung zu verlangen. Angemeldete Redakteure arbeiten weiter, anonyme Anfragen erhalten einen 401:
add_filter( 'rest_authentication_errors', function( $result ) {
// Wenn bereits eine vorherige Authentifizierungsprüfung lief,
// dieses Ergebnis unverändert weitergeben.
if ( true === $result || is_wp_error( $result ) ) {
return $result;
}
// Bisher wurde keine Authentifizierung durchgeführt.
// Fehler zurückgeben, wenn der Nutzer nicht angemeldet ist.
if ( ! is_user_logged_in() ) {
return new WP_Error(
'rest_not_logged_in',
__( 'You are not currently logged in.' ),
array( 'status' => 401 )
);
}
// Unsere eigene Authentifizierungsprüfung soll keinen Einfluss
// auf angemeldete Anfragen haben
return $result;
});Das legt für anonyme Besucher jede Frontend-Funktion lahm, die /wp-json/ aufruft: Formulare, die über REST absenden, Such- oder Filter-Widgets, die JSON abrufen, ein Headless-Frontend sowie andere Seiten, die Ihre Beiträge über den oEmbed-Endpunkt einbetten. Eine engere Variante ist das Ausblenden einzelner Routen mit dem Filter rest_endpoints, zum Beispiel des Users-Endpunkts, der die Slugs der Autoren auflistet. Testen Sie nach der Änderung jedes Formular und jeden interaktiven Block im abgemeldeten Zustand.
Wie man die WordPress Heartbeat API anpasst
Heartbeat ist eine Abfrageschleife in heartbeat.js, die in einem festen Intervall eine Anfrage an admin-ajax.php sendet. Sie trägt die Beitragssperre (den Hinweis, dass gerade jemand anderes bearbeitet), Autosave-Daten im Classic Editor und die Prüfung auf abgelaufene Anmeldungen, die den Dialog zur erneuten Anmeldung anzeigt. In WordPress 7.1.3 beträgt das Standard-mainInterval 60 Sekunden, der erlaubte Bereich liegt bei 1 bis 3.600 Sekunden, die Schleife kann vorübergehend auf 5 Sekunden beschleunigen und verlangsamt sich auf 120 Sekunden, wenn der Tab im Hintergrund ist. Das Intervall auf 60 zu setzen ändert daher nichts; ein langsameres Intervall ist der sinnvolle Hebel bei großen Admin-Teams oder schwachem Hosting:
add_filter( 'heartbeat_settings', function ( $settings ) {
$settings['interval'] = 120;
return $settings;
} );Im Frontend lädt der Core Heartbeat für Besucher nicht; es erscheint nur, wenn ein Plugin es einreiht. Dort können Sie es gefahrlos abmelden, sofern Sie danach die Funktion dieses Plugins prüfen. Melden Sie es im Admin nie ab: Beitragssperren und Warnungen zum Sitzungsablauf hängen davon ab.
Wie man Beitragsrevisionen mit WP_POST_REVISIONS begrenzt
Revisionen bremsen das Frontend nicht, weil sie auf öffentlichen Seiten nie abgefragt werden. Sie vergrößern die Tabelle wp_posts und verlangsamen Backups und Exporte. Gesteuert wird das über eine Konstante in wp-config.php, die wp_revisions_to_keep() ausliest:
define( 'WP_POST_REVISIONS', 10 ); // die 10 neuesten Revisionen pro Beitrag behalten
// define( 'WP_POST_REVISIONS', false ); // gar keine RevisionenDer Standardwert ist true, also unbegrenzt. false oder 0 schaltet Revisionen ab; eine positive Zahl behält entsprechend viele. Der Filter wp_revisions_to_keep überschreibt die Konstante, und seit WordPress 5.8 setzt der Filter wp_{$post_type}_revisions_to_keep ein Limit pro Beitragstyp. Das Limit greift beim nächsten Speichern eines Beitrags, überzählige Revisionen bleiben bis dahin bestehen. Wer Revisionen abschaltet, nimmt Redakteuren das Sicherheitsnetz, daher ist eine kleine Zahl meist der bessere Kompromiss.
Autosave hat eine eigene Konstante. Einen Filter autosave_interval gibt es im Core nicht, Code, der einen solchen hinzufügt, bewirkt also nichts; setzen Sie das Intervall stattdessen in Sekunden in wp-config.php:
define( 'AUTOSAVE_INTERVAL', 120 ); // Standard ist 60Wie man Kommentare auf der ganzen Website deaktiviert
Eine Website ohne Kommentare rendert trotzdem Kommentarformulare, wo das Theme sie anfordert, behält den Link zum Kommentar-Feed im Head und behält die Pingback-Mechanik. Kommentare und Pings über Filter zu schließen deckt jeden Beitragstyp ab, ohne Beiträge in der Datenbank zu bearbeiten:
add_filter( 'comments_open', '__return_false', 20, 2 );
add_filter( 'pings_open', '__return_false', 20, 2 );
add_filter( 'feed_links_show_comments_feed', '__return_false' );
add_action( 'admin_menu', function () {
remove_menu_page( 'edit-comments.php' );
} );
add_action( 'init', function () {
remove_post_type_support( 'post', 'comments' );
remove_post_type_support( 'page', 'comments' );
} );Das Schließen der Pings entfernt auch den Header X-Pingback, weil der Core ihn nur sendet, wenn pings_open() true ist. Bestehende Kommentare bleiben in der Datenbank und können weiterhin erscheinen, wenn das Theme sie unabhängig von comments_open() ausgibt. Das Skript comment-reply lohnt keinen eigenen Aufwand: Der Core registriert es mit der Strategie async und niedriger Abrufpriorität, und es hat gzip-komprimiert 1.371 Bytes.
Wie man Skripte mit der Loading Strategy API verzögert
Seit WordPress 6.3 akzeptieren wp_register_script() und wp_enqueue_script() ein Argument strategy mit den Werten defer oder async. Der Core prüft dann den Abhängigkeitsbaum, bevor er das Attribut ausgibt: Ein Skript, an das in der Position after ein Inline-Skript angehängt ist, wird nie verzögert, und ein defer-Skript fällt auf blockierendes Laden zurück, wenn ein abhängiges Skript es vorher ausgeführt braucht. Diese Logik steckt in WP_Scripts::get_eligible_loading_strategy(). Der Filter script_loader_tag aus Abschnitt 11 übergeht all das, und genau so landen verzögerte Skripte hinter Inline-Code, der sie aufruft.
// Ihr eigenes Skript.
wp_enqueue_script( 'site-main', get_theme_file_uri( 'js/main.js' ), array(), '1.4.0', array(
'in_footer' => true,
'strategy' => 'defer',
) );
// Ein von einem Plugin registriertes Skript.
add_action( 'wp_enqueue_scripts', function () {
wp_script_add_data( 'some-plugin-handle', 'strategy', 'defer' );
}, 20 );Sehen Sie sich danach den Seitenquelltext an: Hat der Core entschieden, dass ein Handle nicht verzögert werden kann, fehlt das Attribut einfach.
Wie man die WordPress-Performance vor und nach dem Entschlacken testet
Ein einzelner Lauf von PageSpeed Insights ist keine Messung, weil Laborwerte zwischen den Läufen schwanken. Ein Ablauf, der vergleichbare Zahlen liefert:
- Vorbereiten: Seiten-Cache leeren, für beide Durchgänge dasselbe Hosting und dieselben URLs verwenden und die Versionen von WordPress, Theme und Plugins notieren.
- Ausgangswert: PageSpeed Insights oder Lighthouse dreimal pro URL laufen lassen und den Median behalten, dann übertragene Bytes und Anzahl der Anfragen aus dem Network-Tab der DevTools bei deaktiviertem Cache notieren.
- Den Debloat-Code auf Staging einspielen und den Cache erneut leeren.
- Dieselben Läufe auf denselben URLs wiederholen.
- Übertragene Bytes, Anzahl der Anfragen, LCP und CLS vergleichen. Die Felddaten im Bereich Chrome UX Report von PageSpeed Insights aktualisieren sich über 28 Tage, prüfen Sie sie daher einen Monat später noch einmal.
Die Größentabelle oben nennt die Obergrenze. Bei einem klassischen Theme, das Block-Styles bereits nach Bedarf lädt, sparen Emoji, Classic Theme Styles und die Head-Tags zusammen ein paar Kilobyte und einige Zeilen HTML; die großen Zahlen stecken in jQuery und in Plugin-Assets.
Wie man nach dem Entschlacken die Kompatibilität prüft
Prüfen Sie nach jeder Änderung drei Bereiche:
- Frontend: Layout, Menüs, Slider und Formulare sowie die Browserkonsole auf JavaScript-Fehler.
- Admin: den Beitragseditor, die Mediathek, den Widget-Bildschirm und jede Plugin-Einstellungsseite, die Sie nutzen.
- Abgemeldet: Kontaktformulare, Kommentare (falls Sie sie behalten), die Suche und alles, was Daten ohne Neuladen der Seite holt.
Schalten Sie während der Tests die Protokollierung ein und die Anzeige aus, damit Besucher keine Hinweise sehen:
define( 'WP_DEBUG', true );
define( 'WP_DEBUG_LOG', true );
define( 'WP_DEBUG_DISPLAY', false );| Problem | Wahrscheinliche Ursache | Lösung |
|---|---|---|
| jQuery-Fehler in der Konsole | jQuery Migrate entfernt | Migrate wiederherstellen oder das Plugin aktualisieren, das veraltete APIs aufruft |
| Blöcke wirken ungestylt | Block Library oder globale Styles entfernt | Die Styles auf Seiten mit Block-Inhalten wiederherstellen |
| Query Loop oder Navigation zeigt nichts an | do_blocks aus the_content entfernt | Diese Zeile entfernen |
| Formulare scheitern im abgemeldeten Zustand | REST API auf angemeldete Nutzer beschränkt | Die Route des Plugins freigeben oder die Einschränkung aufheben |
| Mobile App oder Remote-Publishing scheitert | XML-RPC blockiert | Wieder aktivieren oder den Client auf Anwendungspasswörter und REST umstellen |
| Einbettungen Ihrer Beiträge auf anderen Seiten brechen | oEmbed-Anbieterseite entfernt | Erwartet; wiederherstellen, wenn Partner es brauchen |
Wie man den Debloat-Code als MU-Plugin verpackt
Code in functions.php verschwindet, wenn das Theme wechselt. Ein Must-Use-Plugin in wp-content/mu-plugins/ lädt bei jeder Anfrage, lässt sich im Admin nicht deaktivieren und hält die Debloat-Einstellungen unabhängig vom Theme. WordPress lädt PHP-Dateien, die direkt in diesem Ordner liegen, aber keine Dateien in Unterordnern; behalten Sie also entweder eine einzige Datei oder ergänzen Sie einen kleinen Loader:
wp-content/
mu-plugins/
debloat-loader.php
debloat/
emoji.php
head-cleanup.php
xmlrpc.php
heartbeat.php<?php
/**
* Plugin Name: Debloat
* Description: Removes front-end features this site does not use.
*/
defined( 'ABSPATH' ) || exit;
foreach ( array( 'emoji', 'head-cleanup', 'xmlrpc', 'heartbeat' ) as $module ) {
$file = __DIR__ . '/debloat/' . $module . '.php';
if ( is_readable( $file ) ) {
require_once $file;
}
}Jedes Modul enthält die Snippets aus den Abschnitten oben. Zwei Dinge gehören nicht in ein Debloat-Plugin. Automatische Plugin- und Theme-Updates mit auto_update_plugin und auto_update_theme abzuschalten ist eine Frage der Wartungsstrategie, keine Performance-Einstellung, und schaltet Sicherheitsupdates zusammen mit Funktionsupdates ab. Und Limits für Revisionen und Autosave sind Konstanten; sie gehören in wp-config.php, nicht in ein Plugin, das erst lädt, nachdem diese Konstanten ausgelesen wurden.
Zusammenfassung
Der “Batteries included”-Ansatz von WordPress ist großartig für Anfänger, aber Entwickler, die maximale Performance suchen, müssen das Fett trimmen. Die Techniken in diesem Leitfaden, inspiriert von Terence Edens ausgezeichnetem Debloat-Skript, helfen Ihnen zu einer schlankeren, schnelleren WordPress-Installation.
Mehrere klassische Snippets bewirken unter WordPress 7.1 nichts mehr (WLW-Manifest, Links zu benachbarten Beiträgen, SVG-Filter, der Filter autosave_interval), und einige richten Schaden an (Entfernen von do_blocks, Entfernen der oEmbed-Bereinigung, komplettes Sperren der REST API). Jede Codezeile, die Sie entfernen, ist ein potenzieller Fehlerpunkt weniger; prüfen Sie deshalb jedes Snippet gegen die Version, die Sie betreiben, bevor es in die Produktion geht.







