{"id":13515,"date":"2026-09-02T09:48:25","date_gmt":"2026-09-02T07:48:25","guid":{"rendered":"https:\/\/www.lukaswojcik.com\/blog\/werkzeuge\/wordpress-site-health-analyzer\/"},"modified":"2026-09-02T09:48:25","modified_gmt":"2026-09-02T07:48:25","slug":"wordpress-site-health-analyzer","status":"publish","type":"page","link":"https:\/\/www.lukaswojcik.com\/blog\/de\/werkzeuge\/wordpress-site-health-analyzer\/","title":{"rendered":"WordPress Site Health Analyzer"},"content":{"rendered":"<div class=\"gtm-analyser-container\" style=\"background: var(--bg-panel, #1e1e24); padding: 25px; border-radius: 8px; border: 1px solid var(--border, #2a2a35);\">\n<p style=\"color: var(--text-secondary, #a0a0b0); margin-bottom: 20px;\">Eine Adresse gen\u00fcgt. Der Server holt die Startseite, w\u00e4hlt bis zu drei Unterseiten (ein Produkt, eine Kategorie, einen Beitrag) und setzt eine Handvoll Sonden ab: robots.txt, xmlrpc.php, die REST-Nutzerliste, ?author=1, readme.html, das Upload-Verzeichnis, die http-Weiterleitung sowie je eine CSS- und JS-Datei. Daraus ergibt sich, was eine WordPress- oder WooCommerce-Seite besser machen k\u00f6nnte \u2013 mit Punkten und nach Gewicht sortiert. Der Bericht bleibt 24 Stunden gespeichert; nach \u00c4nderungen an der Seite l\u00e4uft die Pr\u00fcfung \u00fcber den Knopf unter dem Bericht erneut und zeigt die Differenz.<\/p>\n<div style=\"margin-bottom: 14px;\">\n        <label for=\"wh-url\" style=\"color: var(--text-secondary, #a0a0b0); display: block; font-size: 0.85rem; margin-bottom: 5px;\">Adresse der WordPress-Seite<\/label><br \/>\n        <input id=\"wh-url\" type=\"text\" value=\"https:\/\/example.com\/\" class=\"form-control\" style=\"width: 100%; padding: 10px; background: var(--bg-body, #14141a); border: 1px solid var(--border, #2a2a35); color: var(--text-primary, #e8e8ee); border-radius: 6px; box-sizing: border-box; font-family: monospace;\">\n    <\/div>\n<p style=\"color: var(--text-secondary, #a0a0b0); font-size: 0.82rem; margin-bottom: 16px;\">Bis zu vierzehn Abrufe gehen von diesem Server an die eingegebene Adresse, als einfaches GET ohne Cookies. Abrufe in private Netze, auf Loopback- und Link-local-Adressen werden verweigert, auch \u00fcber Weiterleitungen. Die Abfrage ist durch reCAPTCHA v3 gesch\u00fctzt; die aufrufende IP-Adresse und das Ziel werden eine Stunde gespeichert, um die Rate zu begrenzen (sechs frische L\u00e4ufe je Stunde). Der Bericht selbst, der nur \u00f6ffentliche Tatsachen \u00fcber die Seite enth\u00e4lt, bleibt 24 Stunden unter einem Hash der Adresse gespeichert.<\/p>\n<p>    <button id=\"wh-btn\" class=\"button\" style=\"background: var(--accent, #7ee787); color: var(--on-accent, #0b1114); border: none; padding: 12px 24px; border-radius: 6px; font-weight: 700; cursor: pointer;\">Seite analysieren<\/button><\/p>\n<div id=\"wh-ausgabe\" style=\"margin-top: 22px;\"><\/div>\n<p style=\"color: var(--text-secondary, #a0a0b0); font-size: 0.8rem; margin: 24px 0 0;\">Grenze, die dazugeh\u00f6rt: Gelesen werden das ausgelieferte HTML und die Kopfzeilen, ausgef\u00fchrt wird nichts. Bilder, die ein Skript sp\u00e4ter einsetzt, Tags, die erst nach der Einwilligung laden, und alles, was der Browser zur Laufzeit misst (Largest Contentful Paint, Layoutverschiebung), bleiben unsichtbar. Der Bericht sagt, wo hinzusehen ist \u2013 nicht, wie schnell sich die Seite anf\u00fchlt.<\/p>\n<\/div>\n<p><script>\n(function () {\n    'use strict';<\/p>\n<p>    const T = {\"einleitung\":\"Eine Adresse gen\u00fcgt. Der Server holt die Startseite, w\u00e4hlt bis zu drei Unterseiten (ein Produkt, eine Kategorie, einen Beitrag) und setzt eine Handvoll Sonden ab: robots.txt, xmlrpc.php, die REST-Nutzerliste, ?author=1, readme.html, das Upload-Verzeichnis, die http-Weiterleitung sowie je eine CSS- und JS-Datei. Daraus ergibt sich, was eine WordPress- oder WooCommerce-Seite besser machen k\u00f6nnte \u2013 mit Punkten und nach Gewicht sortiert. Der Bericht bleibt 24 Stunden gespeichert; nach \u00c4nderungen an der Seite l\u00e4uft die Pr\u00fcfung \u00fcber den Knopf unter dem Bericht erneut und zeigt die Differenz.\",\"label_url\":\"Adresse der WordPress-Seite\",\"datenschutz\":\"Bis zu vierzehn Abrufe gehen von diesem Server an die eingegebene Adresse, als einfaches GET ohne Cookies. Abrufe in private Netze, auf Loopback- und Link-local-Adressen werden verweigert, auch \u00fcber Weiterleitungen. Die Abfrage ist durch reCAPTCHA v3 gesch\u00fctzt; die aufrufende IP-Adresse und das Ziel werden eine Stunde gespeichert, um die Rate zu begrenzen (sechs frische L\u00e4ufe je Stunde). Der Bericht selbst, der nur \u00f6ffentliche Tatsachen \u00fcber die Seite enth\u00e4lt, bleibt 24 Stunden unter einem Hash der Adresse gespeichert.\",\"knopf\":\"Seite analysieren\",\"knopf_erneut\":\"\u00c4nderungen vorgenommen, erneut pr\u00fcfen\",\"laeuft\":\"Startseite, Unterseiten und Sonden werden abgerufen...\",\"laeuft_lang\":\"L\u00e4uft noch. Eine langsame Seite braucht bis zu einer Minute, weil auf jede Seite gewartet wird.\",\"grenze\":\"Grenze, die dazugeh\u00f6rt: Gelesen werden das ausgelieferte HTML und die Kopfzeilen, ausgef\u00fchrt wird nichts. Bilder, die ein Skript sp\u00e4ter einsetzt, Tags, die erst nach der Einwilligung laden, und alles, was der Browser zur Laufzeit misst (Largest Contentful Paint, Layoutverschiebung), bleiben unsichtbar. Der Bericht sagt, wo hinzusehen ist \u2013 nicht, wie schnell sich die Seite anf\u00fchlt.\",\"h_uebersicht\":\"\u00dcbersicht\",\"zeile_endziel\":\"Gelandet auf\",\"zeile_wordpress\":\"WordPress\",\"zeile_woocommerce\":\"WooCommerce\",\"zeile_theme\":\"Theme\",\"zeile_plugins\":\"Im HTML sichtbare Plugins\",\"zeile_server\":\"Server\",\"zeile_http\":\"Protokoll\",\"zeile_seiten\":\"Gepr\u00fcfte Seiten\",\"zeile_limit\":\"Frische L\u00e4ufe in dieser Stunde noch\",\"punkte_label\":\"von 100\",\"aus_cache_hinweis\":\"Dieser Bericht ist {alter} alt und stammt aus dem Speicher. Der Knopf darunter startet eine frische Pr\u00fcfung.\",\"frisch_hinweis\":\"Frischer Bericht, erstellt in {sekunden} s.\",\"vorher_hinweis\":\"Voriger Lauf: {vorher} Punkte. Jetzt: {jetzt} ({diff}).\",\"budget_hinweis\":\"{n} Unterseite(n) wurden \u00fcbersprungen, weil das Zeitbudget ersch\u00f6pft war. Die Seite antwortet langsam; der Bericht beruht auf weniger Seiten als \u00fcblich.\",\"bereich_leistung\":\"Auslieferung\",\"bereich_assets\":\"Skripte und Stile\",\"bereich_bilder\":\"Bilder\",\"bereich_dokument\":\"Dokument\",\"bereich_woocommerce\":\"WooCommerce\",\"bereich_hygiene\":\"Hygiene\",\"h_befunde\":\"Befunde\",\"stufe_hoch\":\"Hoch\",\"stufe_mittel\":\"Mittel\",\"stufe_niedrig\":\"Niedrig\",\"stufe_info\":\"Hinweis\",\"stufe_gut\":\"In Ordnung\",\"keine_befunde\":\"Nichts zu berichten.\",\"h_seiten\":\"Seiten\",\"spalte_seite\":\"Seite\",\"spalte_typ\":\"Art\",\"spalte_ttfb\":\"Zeit bis zum ersten Byte\",\"spalte_groesse\":\"HTML\",\"spalte_skripte\":\"Skripte (blockierend)\",\"spalte_bilder\":\"Bilder\",\"spalte_cache\":\"Cache\",\"typ_start\":\"Startseite\",\"typ_seite\":\"Seite\",\"typ_beitrag\":\"Beitrag\",\"typ_produkt\":\"Produkt\",\"typ_shop\":\"Shop \\\/ Kategorie\",\"typ_warenkorb\":\"Warenkorb\",\"typ_kasse\":\"Kasse\",\"typ_konto\":\"Konto\",\"typ_archiv\":\"Archiv\",\"h_sonden\":\"Sonden\",\"sonde_http\":\"http:\\\/\\\/-Weiterleitung\",\"sonde_robots\":\"robots.txt\",\"sonde_xmlrpc\":\"xmlrpc.php\",\"sonde_rest_users\":\"REST-Nutzerliste\",\"sonde_author\":\"?author=1\",\"sonde_readme\":\"readme.html\",\"sonde_uploads\":\"Upload-Verzeichnis\",\"sonde_css\":\"Eine CSS-Datei\",\"sonde_js\":\"Eine JS-Datei\",\"sonde_budget\":\"\u00fcbersprungen (Zeitbudget)\",\"sonde_fehler\":\"nicht erreichbar\",\"einheit_minuten\":\"min\",\"einheit_stunden\":\"h\",\"ja\":\"ja\",\"nein\":\"nein\",\"wert_keine\":\"keine sichtbar\",\"fehler_kein_token\":\"Die Pr\u00fcfung konnte nicht starten, weil reCAPTCHA nicht geladen wurde.\",\"fehler_captcha\":\"reCAPTCHA hat die Anfrage als automatisiert eingestuft. Ein Neuladen der Seite hilft in der Regel.\",\"fehler_zu_viele\":\"Die Grenze von {limit} frischen L\u00e4ufen je Stunde f\u00fcr diese Adresse ist erreicht. Gespeicherte Berichte werden weiterhin angezeigt.\",\"fehler_adresse\":\"Diese Adresse l\u00e4sst sich nicht verwenden.\",\"fehler_zaehler\":\"Der Z\u00e4hler ist nicht erreichbar, deshalb wurde nichts abgerufen.\",\"fehler_pruefdienst\":\"Der reCAPTCHA-Dienst war nicht erreichbar.\",\"fehler_aufbau\":\"Der Dienst ist nicht richtig eingerichtet. Der Fehler liegt auf dieser Seite.\",\"fehler_eingabe\":\"Die Anfrage war nicht lesbar.\",\"fehler_methode\":\"Falsche Anfragemethode.\",\"fehler_netz\":\"Der Dienst war nicht erreichbar.\",\"fehler_antwort\":\"Die Antwort war nicht lesbar.\",\"fehler_abruf\":\"Die Adresse lie\u00df sich nicht abrufen.\",\"fehler_status\":\"Die Startseite antwortete mit Status {status} statt 200. Es wurde nichts ausgewertet.\",\"fehler_kein_html\":\"Die Adresse liefert etwas anderes als HTML.\",\"fehler_unbekannt\":\"Etwas ging schief, wof\u00fcr es keine eigene Meldung gibt.\",\"grund_leer\":\"Es wurde nichts eingegeben.\",\"grund_zu_lang\":\"Die Adresse ist zu lang.\",\"grund_unlesbar\":\"Das ist keine lesbare Webadresse.\",\"grund_schema\":\"Abgerufen werden nur http und https.\",\"grund_benutzerinfo\":\"Adressen mit Zugangsdaten werden abgelehnt.\",\"grund_kein_punkt\":\"Der Hostname braucht mindestens einen Punkt.\",\"grund_hostform\":\"Der Hostname hat eine unbrauchbare Form.\",\"grund_port\":\"Abgerufen werden nur die Ports 80, 443, 8080 und 8443.\",\"grund_gesperrter_bereich\":\"Diese Adresse zeigt in ein privates oder reserviertes Netz. Solche werden nie abgerufen, auch nicht \u00fcber eine Weiterleitung.\",\"grund_kein_dns\":\"Der Hostname l\u00e4sst sich nicht aufl\u00f6sen.\",\"grund_zu_viele_spruenge\":\"Zu viele Weiterleitungen.\",\"grund_abruf\":\"Der Server hat nicht rechtzeitig geantwortet oder die Verbindung beendet.\",\"befund_wp_nicht_erkannt\":\"Kein WordPress erkannt || Weder \\\/wp-content\\\/, \\\/wp-includes\\\/ noch ein WordPress-Generator-Tag stehen im HTML. Die allgemeinen Pr\u00fcfungen gelten trotzdem; die WordPress-spezifischen Sonden entfallen.\",\"befund_wc_erkannt\":\"WooCommerce erkannt || Die shopspezifischen Pr\u00fcfungen unten gelten: Cart Fragments, Kassenskripte, Block-Stile und das Caching der Seiten au\u00dferhalb von Warenkorb und Kasse.\",\"befund_ttfb_langsam\":\"Langsame Serverantwort: {ms} ms im Median bis zum ersten Byte (schlechtester Wert {max} ms) || \u00dcber 600 ms beginnt jede Seite sp\u00e4t, bevor ein einziges Asset l\u00e4dt. Ein Seitencache, der fertiges HTML ausliefert, bringt das meist unter 200 ms; PHP 8.x, ein Objektcache und weniger Datenbankabfragen je Seite helfen dort, wo kein Cache greifen kann.\",\"befund_ttfb_maessig\":\"M\u00e4\u00dfige Serverantwort: {ms} ms im Median bis zum ersten Byte (schlechtester Wert {max} ms) || Unter 300 ms ist das Ziel f\u00fcr eine gecachte Seite. Zu pr\u00fcfen ist, ob der Cache auf diesen Seiten wirklich trifft und ob ein Plugin bei jeder Anfrage Abfragen ausf\u00fchrt.\",\"befund_ttfb_gut\":\"Schnelle Serverantwort: {ms} ms im Median bis zum ersten Byte || Die Serverseite ist nicht der Engpass.\",\"befund_kein_seitencache\":\"Kein Seitencache erkannt || Keine der gepr\u00fcften Seiten trug eine Cache-Kopfzeile (X-Cache, Age, CF-Cache-Status, X-LiteSpeed-Cache) oder den Fu\u00dfabdruck eines Cache-Plugins. Jeder Besuch wird von PHP gerendert. Ein Seitencache (LiteSpeed Cache, WP Rocket, WP Super Cache, Cache Enabler oder der des Hosters) ist der gr\u00f6\u00dfte einzelne Gewinn f\u00fcr Blog und Shop.\",\"befund_seitencache_teilweise\":\"Seitencache ({name}) auf {n} von {von} cachef\u00e4higen Seiten || Manche Seiten laufen am Cache vorbei. Typische Ursachen: ein Cookie beim ersten Besuch, ein Plugin, das Seiten als nicht cachef\u00e4hig markiert, oder Abfrageparameter, die neue Cache-Schl\u00fcssel erzeugen.\",\"befund_seitencache_erkannt\":\"Seitencache in Betrieb ({name}) || Auf den gepr\u00fcften Seiten wird fertiges HTML ohne PHP ausgeliefert.\",\"befund_html_nicht_komprimiert\":\"HTML wird unkomprimiert ausgeliefert || Weder gzip noch Brotli in der Antwort. Kompression auf dem Webserver (mod_deflate, mod_brotli, gzip in nginx) senkt die HTML-\u00dcbertragung um 70 bis 80 Prozent, ohne WordPress anzufassen.\",\"befund_html_teils_komprimiert\":\"{n} Seite(n) unkomprimiert ausgeliefert || Kompression ist nur f\u00fcr einen Teil der Antworten eingerichtet, oft weil ein Cache gespeicherte Dateien ohne die Kodierungsregel ausliefert.\",\"befund_html_komprimiert\":\"HTML ist komprimiert ({art}) || Die \u00dcbertragungsgr\u00f6\u00dfe wird am Server reduziert.\",\"befund_http1\":\"Nur HTTP\\\/1.1 || Der Server handelt kein HTTP\\\/2 aus. Bei Dutzenden Skripten, Stilen und Bildern je Seite verk\u00fcrzt das Multiplexing von HTTP\\\/2 das Laden sp\u00fcrbar; auf Apache ist das mod_http2 mit Protocols h2, auf nginx das http2-Flag an der listen-Zeile.\",\"befund_http2\":\"HTTP\\\/2 in Betrieb || Anfragen teilen sich eine Verbindung.\",\"befund_http3\":\"HTTP\\\/3 angeboten || Der Server k\u00fcndigt h3 \u00fcber Alt-Svc an; unterst\u00fctzende Browser wechseln auf QUIC.\",\"befund_html_no_store\":\"HTML als nicht cachef\u00e4hig markiert ({wert}) || Ein Cache-Control mit no-store oder private hindert jedes CDN und jeden Proxy daran, die Seite zu behalten. F\u00fcr anonyme Besucher eines Blogs oder Shops ist das selten beabsichtigt.\",\"befund_cookies_erste_antwort\":\"Cookies schon in der ersten anonymen Antwort ({namen}) || Sitzungs- und Testcookies auf jeder Seite lassen die meisten Seitencaches die Antwort \u00fcberspringen und machen jeden Besuch pers\u00f6nlich. Typische Ursachen: eine von einem Plugin gestartete PHP-Sitzung oder WooCommerce-Sitzungscookies au\u00dferhalb von Warenkorb und Kasse.\",\"befund_blockierende_skripte\":\"{n} renderblockierende Skripte im Kopf || Skripte ohne defer oder async im Kopf halten den Parser an, bis sie geladen und ausgef\u00fchrt sind. In die Fu\u00dfzeile verschoben oder mit defer versehen, darf die Seite zuerst rendern; die Liste nennt die betroffenen Dateien.\",\"befund_blockierende_skripte_wenige\":\"{n} renderblockierende(s) Skript(e) im Kopf || Kleine Zahl, trotzdem ein defer-Attribut wert, sofern das Skript nicht vor dem Body laufen muss.\",\"befund_viele_skripte\":\"{n} externe Skripte auf der Startseite || Mehr als 25 Skriptdateien hei\u00dft meist: mehrere Plugins laden ihre Assets auf jeder Seite. Eine Dequeue-Regel je Seitentyp oder ein Asset-Optimierungs-Plugin senkt Anfragen und Ausf\u00fchrungszeit.\",\"befund_viele_stylesheets\":\"{n} Stylesheets || Jedes Stylesheet ist eine blockierende Anfrage. Was zum Theme geh\u00f6rt, l\u00e4sst sich zusammenf\u00fchren; Plugin-Stile geh\u00f6ren nicht auf Seiten, die sie nicht brauchen.\",\"befund_jquery_migrate\":\"jQuery Migrate wird geladen || Die Kompatibilit\u00e4tsschicht existiert nur f\u00fcr alte Plugins. Meldet die Browserkonsole nach dem Entfernen nichts, kann sie per Dequeue weg.\",\"befund_wp_emoji\":\"Emoji-Skript wird geladen || WordPress h\u00e4ngt wp-emoji und einen DNS-Prefetch auf s.w.org an jede Seite. Moderne Browser rendern Emoji nativ; zwei remove_action-Aufrufe entfernen das Skript.\",\"befund_wp_embed\":\"wp-embed-Skript wird geladen || Nur n\u00f6tig zum Einbetten fremder WordPress-Beitr\u00e4ge. Entfernbar, wenn die Seite das nicht nutzt.\",\"befund_wp_polyfill\":\"wp-polyfill im Frontend geladen || Das Polyfill existiert f\u00fcr alte Browser und wird meist von einem Block- oder Plugin-Skript mitgezogen, das im Frontend nicht gebraucht wird.\",\"befund_dashicons\":\"Dashicons f\u00fcr Besucher geladen || Die Admin-Iconschrift wird im Frontend eingebunden, meist von einem Plugin. Anonyme Besucher brauchen sie nicht; Dequeue, sofern das Theme die Icons nicht nutzt.\",\"befund_block_library_css\":\"Block-Library-CSS ohne Blockinhalte || Die wp-block-library-Stile werden geladen, obwohl keine Blockklassen im HTML stehen. Klassische Themes k\u00f6nnen sie per Dequeue entfernen.\",\"befund_global_styles_gross\":\"Global-Styles-Inline-CSS von {kb} KB || Die Ausgabe aus theme.json steht inline auf jeder Seite. Ein gro\u00dfer Wert hei\u00dft viele ungenutzte Voreinstellungen; theme.json k\u00fcrzen oder ungenutzte Varianten entfernen hilft.\",\"befund_inline_css_gross\":\"{kb} KB Inline-CSS || Inline-Stile wiederholen sich auf jeder Seite und werden vom Browser nie gecacht. Page Builder sind die \u00fcbliche Quelle; wiederkehrende Regeln geh\u00f6ren in ein Stylesheet.\",\"befund_google_fonts_extern\":\"Schriften von fonts.googleapis.com || Eine Fremdverbindung, bevor Text rendern kann, und in der EU eine Datenschutzfrage. Selbst gehostete WOFF2-Dateien mit font-display: swap sind schneller und vermeiden die \u00dcbermittlung.\",\"befund_fontawesome_cdn\":\"Font Awesome von einem CDN || Eine ganze Iconschrift f\u00fcr eine Handvoll Icons, von einem fremden Host. Inline-SVG oder eine Teilmenge von der eigenen Domain ist kleiner.\",\"befund_fremde_hosts\":\"{n} fremde Hosts f\u00fcr Skripte und Stile || Jeder Host kostet eine DNS-Aufl\u00f6sung und einen TLS-Handshake vor dem ersten Byte. Die Liste nennt sie; Zusammenlegen oder Selbsthosten entfernt Verbindungen.\",\"befund_kein_preconnect\":\"Kein preconnect f\u00fcr fremde Hosts || Ein preconnect-Link f\u00fcr die fr\u00fch ben\u00f6tigten Hosts (Schriften, Tag Manager) baut die Verbindung auf, bevor der Browser die Ressource entdeckt.\",\"befund_admin_ajax_frontend\":\"admin-ajax.php im Frontend genutzt || Jeder Aufruf l\u00e4dt den ganzen Admin-Bootstrap. F\u00fcr \u00f6ffentliche Daten ist die REST-API leichter und cachef\u00e4hig.\",\"befund_inline_js_gross\":\"{kb} KB Inline-JavaScript || Inline-Skripte werden auf jeder Seite neu geparst und lassen sich nicht cachen. In eine Datei mit defer verschoben, wird das besser.\",\"befund_assets_ohne_cache\":\"Statische Dateien ohne Browser-Caching ({art}) || Die gepr\u00fcfte Datei tr\u00e4gt kein brauchbares max-age und kein Expires. Wiederkehrende Besucher laden jedes Skript und Stylesheet erneut; ein Monat f\u00fcr versionierte Assets ist die \u00fcbliche Einstellung (mod_expires oder expires in nginx).\",\"befund_assets_kurz_gecacht\":\"Statische Dateien nur {tage} Tag(e) gecacht ({art}) || Versionierte Assets d\u00fcrfen monatelang im Cache liegen; der ?ver-Parameter \u00e4ndert sich, wenn die Datei sich \u00e4ndert.\",\"befund_assets_gecacht\":\"Statische Dateien {tage} Tage gecacht ({art}) || Wiederkehrende Besucher verwenden Skripte und Stile erneut.\",\"befund_assets_nicht_komprimiert\":\"Statische Dateien unkomprimiert ausgeliefert ({art}) || Textdateien ohne gzip oder Brotli. Dieselbe Webserver-Einstellung, die HTML komprimiert, sollte CSS und JavaScript einschlie\u00dfen.\",\"befund_bilder_ohne_masse\":\"{n} von {von} Bildern ohne width und height || Ohne Ma\u00dfe kann der Browser keinen Platz reservieren, und das Layout springt, wenn das Bild ankommt (Cumulative Layout Shift). WordPress setzt die Attribute f\u00fcr Bilder aus dem Editor; Themes und Builder lassen sie oft weg.\",\"befund_bilder_ohne_lazy\":\"{n} von {von} Bildern unterhalb des ersten Bildschirms ohne loading=\\u0022lazy\\u0022 || Bilder au\u00dferhalb des ersten Bildschirms d\u00fcrfen warten. WordPress setzt das Attribut standardm\u00e4\u00dfig; ein Theme oder Plugin mit eigenen img-Tags l\u00e4sst es aus.\",\"befund_bilder_altformat\":\"Keine modernen Bildformate ({von} Bilder gepr\u00fcft) || Weder WebP noch AVIF. Seit WordPress 6.5 lassen sich Uploads automatisch umwandeln; ein Bild-Plugin oder der Hoster tut dasselbe. 30 bis 60 Prozent Ersparnis je Bild sind \u00fcblich.\",\"befund_bilder_modern\":\"Moderne Bildformate in Gebrauch ({n} von {von}) || WebP oder AVIF werden f\u00fcr einen Teil der Bilder ausgeliefert.\",\"befund_bilder_ohne_srcset\":\"{n} von {von} Bildern ohne srcset || Ohne responsive Quellen l\u00e4dt jedes Ger\u00e4t dieselbe Datei. WordPress erzeugt die Gr\u00f6\u00dfen beim Hochladen; das Theme muss sie ausgeben.\",\"befund_erstes_bild_lazy\":\"Das erste Bild wird lazy geladen || Das Bild im ersten Bildschirm wird durch genau das Attribut verz\u00f6gert, das es sch\u00fctzen sollte. Es geh\u00f6rt eager geladen, am besten mit fetchpriority=\\u0022high\\u0022.\",\"befund_iframes_ohne_lazy\":\"{n} iframe(s) ohne loading=\\u0022lazy\\u0022 || Eingebettete Videos und Karten laden je eine ganze Seite. Lazy Loading schiebt sie auf, bis sie ins Bild scrollen.\",\"befund_kein_fetchpriority\":\"Kein fetchpriority am Aufmacherbild || Das gr\u00f6\u00dfte sichtbare Bild mit fetchpriority=\\u0022high\\u0022 zu markieren zieht es vor die Skripte und verbessert den Largest Contentful Paint.\",\"befund_html_gross\":\"HTML-Dokument von {kb} KB || Gro\u00dfe Dokumente tragen meist Inline-CSS, Inline-SVG oder das Markup eines Builders. \u00dcber 300 KB braucht allein der Parser auf dem Handy sp\u00fcrbar Zeit.\",\"befund_dom_gross\":\"Etwa {n} DOM-Knoten || Mehr als 2.500 Knoten verlangsamen Stilberechnung und Layout. Page Builder und verschachtelte Wrapper sind die \u00fcbliche Quelle.\",\"befund_viewport_fehlt\":\"Kein Viewport-Meta-Tag || Ohne ihn rendern Handys die Seite in Desktopbreite und verkleinern sie. Jedes Theme sollte width=device-width setzen.\",\"befund_lang_fehlt\":\"Kein lang-Attribut am html-Element || Screenreader und Suchmaschinen erkennen die Sprache nicht; WordPress setzt es aus der Seitensprache, sofern das Theme das html-Tag nicht \u00fcberschreibt.\",\"befund_titel_fehlt\":\"Kein Titel || Das Dokument hat kein title-Element.\",\"befund_beschreibung_fehlt\":\"Keine Meta-Beschreibung || Kein Rankingfaktor, aber der Textauszug, den Suchmaschinen zeigen. Ein SEO-Plugin f\u00fcllt ihn je Seite.\",\"befund_kein_canonical\":\"Kein Canonical-Link || Ohne ihn konkurrieren Dubletten (mit Parametern, mit und ohne Schr\u00e4gstrich am Ende) miteinander. Yoast, Rank Math und der Kern seit 6.x setzen ihn; hier hat ihn etwas entfernt.\",\"befund_noindex\":\"Seite steht auf noindex || Die Startseite sagt Suchmaschinen, sie nicht zu indexieren. Auf einer Staging-Seite gewollt, auf einer Live-Seite ein ernster Fehler.\",\"befund_kopf_ballast\":\"Ballast im Kopf: RSD-Link, wlwmanifest oder shortlink || Reste aus Zeiten der Remote-Publishing-Werkzeuge. Harmlos, aber je ein link-Element und ein Hinweis auf die Plattform; remove_action-Aufrufe nehmen sie heraus.\",\"befund_pingback_offen\":\"Pingback-Endpunkt angek\u00fcndigt || Die X-Pingback-Kopfzeile oder ein Link zeigt auf xmlrpc.php. Pingbacks dienen Spam und Verst\u00e4rkungsangriffen; XML-RPC abzuschalten entfernt beides.\",\"befund_wc_fragments_ueberall\":\"Cart Fragments auf {n} Seite(n) au\u00dferhalb des Warenkorbs geladen || wc-cart-fragments schickt bei jedem Seitenaufruf eine admin-ajax-Anfrage, um den Mini-Warenkorb zu aktualisieren, und umgeht dabei den Seitencache. Au\u00dferhalb von Warenkorb und Kasse per Dequeue entfernen oder die Theme-Einstellung daf\u00fcr nutzen.\",\"befund_wc_fragments_ok\":\"Cart Fragments nur dort, wo sie gebraucht werden || Kein cart-fragments-Skript auf Blog- und Inhaltsseiten.\",\"befund_wc_checkout_skripte_ueberall\":\"Kassenskripte auf {n} Seite(n) au\u00dferhalb der Kasse || Kassen- und Adressskripte sind schwer und werden auf genau einer Seite gebraucht. Ein bedingtes Dequeue h\u00e4lt sie dort.\",\"befund_wc_produktskripte_ueberall\":\"Produktseitenskripte auf {n} Seite(n), die keine Produkte sind || Galerie-, Zoom- und Variantenskripte au\u00dferhalb von Produktseiten geladen.\",\"befund_wc_blocks_css_ueberall\":\"WooCommerce-Block-Stile auf {n} Inhaltsseite(n) || wc-blocks-CSS wird auf Seiten ohne Shop-Bl\u00f6cke geladen. Au\u00dferhalb der Shopseiten per Dequeue entfernen.\",\"befund_wc_layout_css_ueberall\":\"WooCommerce-Layout-Stile auf {n} Blogbeitrag\\\/-beitr\u00e4gen || Die Shop-Stylesheets werden auf Beitr\u00e4gen ohne Shop-Markup geladen.\",\"befund_wc_nicht_gecacht\":\"{n} Shopseite(n) als nicht cachef\u00e4hig markiert || Cache-Control verbietet das Caching auf Seiten, die weder Warenkorb, Kasse noch Konto sind. Meist eine zu fr\u00fch gestartete Sitzung; zu pr\u00fcfen ist, welches Plugin die Kopfzeile setzt.\",\"befund_wc_select2_ueberall\":\"select2 \\\/ selectWoo au\u00dferhalb von Kasse und Konto geladen || Die Dropdown-Bibliothek wird nur auf Formularen gebraucht.\",\"befund_wc_passwortmesser\":\"Passwortst\u00e4rke-Messer im Frontend geladen || zxcvbn wiegt rund 800 KB und geh\u00f6rt allein zum Registrierungsformular.\",\"befund_wc_keine_shopseite_geprueft\":\"Unter den inneren Links wurde keine Produkt- oder Kategorieseite gefunden || Die shopspezifischen Pr\u00fcfungen liefen auf den verf\u00fcgbaren Seiten. Die Shop-Adresse direkt einzugeben ergibt ein vollst\u00e4ndigeres Bild.\",\"befund_generator_version\":\"WordPress-Version {version} im Generator-Tag || Die genaue Version ist \u00f6ffentlich. F\u00fcr sich keine Schwachstelle, aber eine veraltete Installation ist so leicht zu finden; Generator-Tag entfernen und den Kern aktuell halten.\",\"befund_generator_meta\":\"Generator-Meta-Tag vorhanden || Die Plattform wird im Kopf angek\u00fcndigt. Mit einem einzeiligen Filter entfernbar.\",\"befund_x_powered_by\":\"X-Powered-By-Kopfzeile: {wert} || Der Server k\u00fcndigt seinen Stack an. Entfernbar mit expose_php = Off und einer Header-Regel.\",\"befund_php_alt\":\"PHP {version} in Betrieb || Unter 8.1 ist der Interpreter ohne Sicherheitspflege und deutlich langsamer. WordPress und WooCommerce laufen auf 8.2 und 8.3; die Umstellung bietet meist das Kundenmen\u00fc des Hosters.\",\"befund_server_version\":\"Server-Kopfzeile mit Version: {wert} || Die genaue Webserver-Version ist \u00f6ffentlich. ServerTokens Prod auf Apache, server_tokens off auf nginx.\",\"befund_kein_hsts\":\"Kein Strict-Transport-Security || Nach der https-Weiterleitung h\u00e4lt HSTS Browser auf https und erspart bei sp\u00e4teren Besuchen die erste unverschl\u00fcsselte Anfrage.\",\"befund_https_redirect_ok\":\"http leitet auf https um ({status}) || Die unverschl\u00fcsselte Adresse f\u00fchrt zur sicheren.\",\"befund_kein_https_redirect\":\"http antwortet mit 200 statt umzuleiten || Die Seite ist unverschl\u00fcsselt erreichbar, und Suchmaschinen k\u00f6nnen beide Fassungen indexieren. Eine dauerhafte Weiterleitung auf https geh\u00f6rt in die Webserver-Konfiguration.\",\"befund_http_redirect_nicht_https\":\"http leitet um, aber nicht auf https ({ort}) || Das Ziel der Weiterleitung ist wieder eine unverschl\u00fcsselte Adresse; die Kette sollte auf https enden.\",\"befund_xmlrpc_offen\":\"xmlrpc.php ist aktiv || Der XML-RPC-Endpunkt nimmt Anfragen an. Er ist der bevorzugte Weg f\u00fcr Brute-Force- und Pingback-Missbrauch und wird nur von der Mobil-App und Jetpack gebraucht. Auf dem Webserver sperren oder per Filter abschalten.\",\"befund_xmlrpc_gesperrt\":\"xmlrpc.php ist gesperrt ({status}) || Der Endpunkt weist Anfragen ab.\",\"befund_rest_users_offen\":\"Nutzerliste per REST lesbar ({n} Konto\\\/Konten: {liste}) || \\\/wp-json\\\/wp\\\/v2\\\/users liefert jedem die Anmeldenamen der Autoren. Das ist der erste Schritt eines Passwortangriffs; den Endpunkt auf angemeldete Nutzer beschr\u00e4nken.\",\"befund_rest_users_gesperrt\":\"REST-Nutzerliste nicht \u00f6ffentlich ({status}) || Der Endpunkt gibt keine Konten preis.\",\"befund_author_enum\":\"?author=1 verr\u00e4t den Anmeldenamen ({name}) || Die Weiterleitung auf das Autorenarchiv legt das erste Konto offen. Eine Redirect-Regel oder eine Plugin-Einstellung unterbindet das.\",\"befund_readme_offen\":\"readme.html ist \u00f6ffentlich || Die Datei nennt die WordPress-Version. Nach jedem Update l\u00f6schen oder auf dem Webserver sperren.\",\"befund_uploads_listing\":\"Upload-Verzeichnis zeigt seinen Inhalt || \\\/wp-content\\\/uploads\\\/ liefert eine Verzeichnisliste. Options -Indexes auf Apache oder autoindex off auf nginx.\",\"befund_robots_fehlt\":\"Keine robots.txt || WordPress erzeugt sie dynamisch, sofern keine physische Datei oder Rewrite-Regel das verhindert. Eine fehlende Datei ist kein Fehler, aber eine Sitemap-Zeile lohnt sich.\",\"befund_robots_ohne_sitemap\":\"robots.txt ohne Sitemap-Zeile || Eine Zeile Sitemap: mit der Adresse der XML-Sitemap hilft Crawlern, jede Seite zu finden.\",\"befund_robots_sperrt_assets\":\"robots.txt sperrt \\\/wp-content\\\/ oder \\\/wp-includes\\\/ || Google rendert Seiten und braucht CSS und JavaScript. Diese Verzeichnisse zu sperren verschlechtert das Verst\u00e4ndnis der Seite.\",\"befund_robots_sperrt_alles\":\"robots.txt sperrt alles || Disallow: \\\/ h\u00e4lt jeden Crawler fern. Nur auf Staging gewollt.\",\"befund_wp_version_gelesen\":\"WordPress {version} || Gelesen aus dem Generator-Tag oder den Versionsparametern der Assets.\"};<\/p>\n<p>    var ENDPUNKT = '\/lw-wphealth.php';\n    var SITEKEY = '6LcrPkEtAAAAAPo1QCOf-IIM2fCL0UfdJz4y2iSY';\n    var STUFEN = ['hoch', 'mittel', 'niedrig', 'info', 'gut'];\n    var BEREICHE = ['leistung', 'assets', 'bilder', 'dokument', 'woocommerce', 'hygiene'];<\/p>\n<p>    \/\/ =========================================================================\n    \/\/ Bewertung - rein\n    \/\/ =========================================================================<\/p>\n<p>    function liste(w) { return Array.isArray(w) ? w : []; }\n    function zahl(w) { return (typeof w === 'number' && isFinite(w)) ? w : null; }<\/p>\n<p>    \/** Platzhalter {x} aus den Befunddaten einsetzen. *\/\n    function text(schluessel, daten) {\n        var t = T[schluessel];\n        if (typeof t !== 'string') { return null; }\n        return t.replace(\/\\{([a-z_]+)\\}\/g, function (m, k) {\n            if (daten && daten[k] !== undefined && daten[k] !== null) {\n                return Array.isArray(daten[k]) ? daten[k].join(', ') : String(daten[k]);\n            }\n            return m;\n        });\n    }<\/p>\n<p>    function bewerten(antwort) {\n        var a = antwort || {};\n        if (a.fehler) {\n            return { fehler: a.fehler, grund: a.grund || null, status: zahl(a.status), limit: zahl(a.limit), kette: liste(a.kette) };\n        }\n        var p = (a.punkte && typeof a.punkte === 'object') ? a.punkte : {};\n        var bereiche = [];\n        BEREICHE.forEach(function (b) {\n            if (p.bereiche && zahl(p.bereiche[b]) !== null) { bereiche.push({ name: b, punkte: p.bereiche[b] }); }\n        });\n        var befunde = liste(a.befunde).map(function (f) {\n            return { key: String(f.key || ''), stufe: STUFEN.indexOf(f.stufe) === -1 ? 'info' : f.stufe,\n                     punkte: zahl(f.punkte) || 0, bereich: f.bereich || '', daten: (f.daten && typeof f.daten === 'object') ? f.daten : {} };\n        });\n        var gruppen = {};\n        STUFEN.forEach(function (s) { gruppen[s] = befunde.filter(function (f) { return f.stufe === s; }); });\n        var gesamt = zahl(p.gesamt);\n        var farbe = gesamt === null ? 'grau' : (gesamt >= 85 ? 'gut' : (gesamt >= 60 ? 'mittel' : 'schlecht'));\n        var vorher = (a.vorher && zahl(a.vorher.punkte) !== null) ? { punkte: a.vorher.punkte, erstellt: a.vorher.erstellt || null } : null;\n        return {\n            fehler: null,\n            url: a.url || '', endziel: a.endziel || a.url || '',\n            wordpress: !!a.wordpress, wpVersion: a.wp_version || null,\n            woocommerce: !!a.woocommerce, wcVersion: a.wc_version || null,\n            theme: a.theme || null, plugins: liste(a.plugins),\n            server: (a.server && typeof a.server === 'object') ? a.server : {},\n            seiten: liste(a.seiten),\n            sonden: (a.sonden && typeof a.sonden === 'object') ? a.sonden : {},\n            gesamt: gesamt, farbe: farbe, bereiche: bereiche,\n            befunde: befunde, gruppen: gruppen,\n            ausCache: !!a.aus_cache, alterS: zahl(a.alter_s) || 0,\n            erstellt: a.erstellt || null, dauer: zahl(a.dauer_ms),\n            limitRest: zahl(a.limit_rest), vorher: vorher,\n            uebersprungen: zahl(a.unterseiten_uebersprungen) || 0\n        };\n    }<\/p>\n<p>    \/\/ =========================================================================\n    \/\/ Abruf\n    \/\/ =========================================================================<\/p>\n<p>    function skriptLaden() {\n        return new Promise(function (auf) {\n            if (window.grecaptcha) { auf(true); return; }\n            var s = document.createElement('script');\n            s.src = 'https:\/\/www.google.com\/recaptcha\/api.js?render=' + SITEKEY;\n            s.onload = function () { auf(true); };\n            s.onerror = function () { auf(false); };\n            document.head.appendChild(s);\n            setTimeout(function () { auf(!!window.grecaptcha); }, 8000);\n        });\n    }\n    \/** grecaptcha.ready abwarten - execute ist bei onload noch nicht da. *\/\n    function tokenHolen() {\n        return skriptLaden().then(function (da) {\n            if (!da || !window.grecaptcha || !window.grecaptcha.ready) { return null; }\n            return new Promise(function (auf) {\n                var fertig = false;\n                function einmal(w) { if (!fertig) { fertig = true; auf(w); } }\n                setTimeout(function () { einmal(null); }, 12000);\n                try {\n                    window.grecaptcha.ready(function () {\n                        if (fertig) { return; }\n                        if (!window.grecaptcha.execute) { einmal(null); return; }\n                        window.grecaptcha.execute(SITEKEY, { action: 'wphealth' })\n                            .then(function (t) { einmal(t || null); }, function () { einmal(null); });\n                    });\n                } catch (e) { einmal(null); }\n            });\n        }, function () { return null; });\n    }\n    function abfragen(url, erneut) {\n        return tokenHolen().then(function (token) {\n            return fetch(ENDPUNKT, {\n                method: 'POST', headers: { 'Content-Type': 'application\/json' },\n                body: JSON.stringify({ url: url, token: token || '', erneut: !!erneut })\n            }).then(function (r) {\n                return r.json().then(function (j) { return j; }, function () { return { fehler: 'antwort' }; });\n            }, function () { return { fehler: 'netz' }; });\n        });\n    }<\/p>\n<p>    window.LW_TEST = window.LW_TEST || {};\n    window.LW_TEST.WH = { bewerten: bewerten, darstellen: null, text: text, ENDPUNKT: ENDPUNKT, STUFEN: STUFEN, BEREICHE: BEREICHE, T: T };<\/p>\n<p>    \/\/ =========================================================================\n    \/\/ Oberflaeche\n    \/\/ =========================================================================<\/p>\n<p>    var btn = document.getElementById('wh-btn');\n    var out = document.getElementById('wh-ausgabe');\n    if (!btn || !out) { return; }<\/p>\n<p>    function el(tag, stil, txt) {\n        var e = document.createElement(tag);\n        if (stil) { e.setAttribute('style', stil); }\n        if (txt !== undefined && txt !== null) { e.textContent = txt; }\n        return e;\n    }\n    function wert(id) { var e = document.getElementById(id); return e ? e.value : ''; }<\/p>\n<p>    var UEBERSCHRIFT = 'font-family: \"Nunito Sans\", sans-serif; font-weight: 700; color: var(--text-primary, #e8e8ee); font-size: 0.95rem; margin: 22px 0 8px;';\n    var ZELLE = 'padding: 5px 12px 5px 0; color: var(--text-secondary, #a0a0b0); font-size: 0.87rem;';\n    var ZELLE_WERT = 'padding: 5px 12px 5px 0; color: var(--text-primary, #e8e8ee); font-size: 0.87rem; font-family: monospace; word-break: break-all;';\n    var KASTEN = 'background: var(--bg-body, #14141a); border: 1px solid var(--border, #2a2a35); border-radius: 8px; padding: 14px 16px; margin: 0 0 10px;';\n    var GUT = ' color: #7ee787;';\n    var WARN = ' color: #ffa94d;';\n    var ROT = ' color: #ff7b72;';\n    var GRAU = ' color: #8a8a99;';\n    var FARBEN = { hoch: '#ff7b72', mittel: '#ffa94d', niedrig: '#e3b341', info: '#8a8a99', gut: '#7ee787' };\n    var PUNKTFARBE = { gut: '#7ee787', mittel: '#ffa94d', schlecht: '#ff7b72', grau: '#8a8a99' };<\/p>\n<p>    function gitter(sp) { return el('div', 'display: grid; grid-template-columns: ' + sp + '; gap: 0 18px; align-items: baseline;'); }\n    function paar(g, n, w, stil) {\n        g.appendChild(el('div', ZELLE, n));\n        g.appendChild(el('div', ZELLE_WERT + (stil || ''), w));\n    }\n    function balken(ziel, beschriftung, punkte, breite) {\n        var z = el('div', 'display: grid; grid-template-columns: 160px 1fr 44px; gap: 10px; align-items: center; margin: 4px 0;');\n        z.appendChild(el('div', ZELLE + ' padding: 0;', beschriftung));\n        var hg = el('div', 'height: 10px; border-radius: 5px; background: var(--border, #2a2a35); overflow: hidden;');\n        var f = punkte >= 85 ? PUNKTFARBE.gut : (punkte >= 60 ? PUNKTFARBE.mittel : PUNKTFARBE.schlecht);\n        hg.appendChild(el('div', 'height: 100%; width: ' + Math.max(2, Math.min(100, punkte)) + '%; background: ' + f + '; border-radius: 5px;'));\n        z.appendChild(hg);\n        z.appendChild(el('div', ZELLE_WERT + ' padding: 0; text-align: right;', String(punkte)));\n        ziel.appendChild(z);\n    }\n    function dauerText(s) {\n        if (s < 3600) { return Math.max(1, Math.round(s \/ 60)) + ' ' + T.einheit_minuten; }\n        return Math.round(s \/ 3600) + ' ' + T.einheit_stunden;\n    }\n\n    function darstellen(b, ziel) {\n        ziel.innerHTML = '';\n        if (b.fehler) {\n            var txt = T['fehler_' + b.fehler] || T.fehler_unbekannt;\n            if (b.grund &#038;&#038; T['grund_' + b.grund]) { txt = txt + ' ' + T['grund_' + b.grund]; }\n            if (b.limit !== null) { txt = txt.replace('{limit}', String(b.limit)); }\n            if (b.status !== null) { txt = txt.replace('{status}', String(b.status)); }\n            ziel.appendChild(el('p', ZELLE + WARN + ' margin: 0;', txt));\n            return;\n        }\n\n        \/\/ --- Kopf: Punkte und Herkunft ---\n        var kopf = el('div', KASTEN + ' display: flex; flex-wrap: wrap; gap: 18px 28px; align-items: center;');\n        var pk = el('div', 'text-align: center; min-width: 110px;');\n        pk.appendChild(el('div', 'font-family: \"Nunito Sans\", sans-serif; font-weight: 800; font-size: 2.6rem; line-height: 1; color: ' + PUNKTFARBE[b.farbe] + ';', b.gesamt === null ? '-' : String(b.gesamt)));\n        pk.appendChild(el('div', ZELLE + ' padding: 4px 0 0; font-size: 0.78rem; text-transform: uppercase; letter-spacing: 0.5px;', T.punkte_label));\n        kopf.appendChild(pk);\n        var bb = el('div', 'flex: 1 1 320px;');\n        b.bereiche.forEach(function (x) { balken(bb, T['bereich_' + x.name] || x.name, x.punkte); });\n        kopf.appendChild(bb);\n        ziel.appendChild(kopf);\n\n        var hinweise = el('div', 'margin: 0 0 6px;');\n        if (b.ausCache) {\n            hinweise.appendChild(el('p', ZELLE + GRAU + ' margin: 0 0 6px;', text('aus_cache_hinweis', { alter: dauerText(b.alterS) })));\n        } else if (b.dauer !== null) {\n            hinweise.appendChild(el('p', ZELLE + GRAU + ' margin: 0 0 6px;', text('frisch_hinweis', { sekunden: (b.dauer \/ 1000).toFixed(1) })));\n        }\n        if (b.vorher &#038;&#038; b.gesamt !== null) {\n            var diff = b.gesamt - b.vorher.punkte;\n            var stil = diff > 0 ? GUT : (diff < 0 ? ROT : GRAU);\n            hinweise.appendChild(el('p', ZELLE + stil + ' margin: 0 0 6px; font-weight: 700;',\n                text('vorher_hinweis', { vorher: b.vorher.punkte, jetzt: b.gesamt, diff: (diff > 0 ? '+' : '') + diff })));\n        }\n        if (b.uebersprungen > 0) { hinweise.appendChild(el('p', ZELLE + WARN + ' margin: 0 0 6px;', text('budget_hinweis', { n: b.uebersprungen }))); }\n        ziel.appendChild(hinweise);<\/p>\n<p>        \/\/ --- Erneut pruefen ---\n        var erneutBtn = el('button', 'background: transparent; color: var(--accent, #7ee787); border: 1px solid var(--accent, #7ee787); padding: 9px 16px; border-radius: 6px; font-weight: 700; cursor: pointer; font-size: 0.85rem; margin: 4px 0 10px;', T.knopf_erneut);\n        erneutBtn.className = 'button wh-erneut';\n        erneutBtn.setAttribute('data-url', b.url);\n        ziel.appendChild(erneutBtn);<\/p>\n<p>        \/\/ --- Uebersicht ---\n        ziel.appendChild(el('div', UEBERSCHRIFT, T.h_uebersicht));\n        var g = gitter('auto auto');\n        paar(g, T.zeile_endziel, b.endziel);\n        paar(g, T.zeile_wordpress, b.wordpress ? (b.wpVersion ? T.ja + ' (' + b.wpVersion + ')' : T.ja) : T.nein, b.wordpress ? GUT : WARN);\n        if (b.woocommerce) { paar(g, T.zeile_woocommerce, b.wcVersion ? T.ja + ' (' + b.wcVersion + ')' : T.ja, GUT); }\n        if (b.theme) { paar(g, T.zeile_theme, b.theme); }\n        paar(g, T.zeile_plugins, b.plugins.length ? b.plugins.join(', ') : T.wert_keine, GRAU);\n        if (b.server.software) { paar(g, T.zeile_server, b.server.software + (b.server.x_powered_by ? ' \/ ' + b.server.x_powered_by : ''), GRAU); }\n        if (b.server.http) { paar(g, T.zeile_http, 'HTTP\/' + b.server.http + (b.server.kompression ? ', ' + b.server.kompression : ''), GRAU); }\n        paar(g, T.zeile_seiten, String(b.seiten.length), GRAU);\n        if (b.limitRest !== null) { paar(g, T.zeile_limit, String(b.limitRest), GRAU); }\n        ziel.appendChild(g);<\/p>\n<p>        \/\/ --- Befunde ---\n        ziel.appendChild(el('div', UEBERSCHRIFT, T.h_befunde));\n        var irgendwas = false;\n        STUFEN.forEach(function (s) {\n            var gr = b.gruppen[s];\n            if (!gr.length) { return; }\n            irgendwas = true;\n            ziel.appendChild(el('div', 'font-weight: 700; font-size: 0.82rem; text-transform: uppercase; letter-spacing: 0.5px; margin: 14px 0 6px; color: ' + FARBEN[s] + ';', T['stufe_' + s] + ' (' + gr.length + ')'));\n            gr.forEach(function (f) {\n                var k = el('div', KASTEN + ' border-left: 3px solid ' + FARBEN[s] + ';');\n                var titel = text('befund_' + f.key, f.daten) || f.key;\n                var teile = titel.split(' || ');\n                var z1 = el('div', 'display: flex; justify-content: space-between; gap: 12px; align-items: baseline;');\n                z1.appendChild(el('div', 'color: var(--text-primary, #e8e8ee); font-size: 0.9rem; font-weight: 700;', teile[0]));\n                if (f.punkte > 0) { z1.appendChild(el('div', ZELLE_WERT + ' padding: 0; white-space: nowrap;' + GRAU, '-' + f.punkte)); }\n                k.appendChild(z1);\n                if (teile[1]) { k.appendChild(el('div', ZELLE + ' padding: 6px 0 0; line-height: 1.55;', teile[1])); }\n                if (Array.isArray(f.daten.liste) && f.daten.liste.length) {\n                    var l = el('ul', 'margin: 8px 0 0 18px; padding: 0; color: var(--text-secondary, #a0a0b0); font-size: 0.8rem; font-family: monospace; word-break: break-all;');\n                    f.daten.liste.forEach(function (x) { l.appendChild(el('li', '', String(x))); });\n                    k.appendChild(l);\n                }\n                ziel.appendChild(k);\n            });\n        });\n        if (!irgendwas) { ziel.appendChild(el('p', ZELLE + ' margin: 0;', T.keine_befunde)); }<\/p>\n<p>        \/\/ --- Seiten ---\n        if (b.seiten.length) {\n            ziel.appendChild(el('div', UEBERSCHRIFT, T.h_seiten));\n            var tabelle = el('div', 'overflow-x: auto;');\n            var gs = gitter('minmax(160px, 2fr) auto auto auto auto auto auto');\n            [T.spalte_seite, T.spalte_typ, T.spalte_ttfb, T.spalte_groesse, T.spalte_skripte, T.spalte_bilder, T.spalte_cache].forEach(function (s) {\n                gs.appendChild(el('div', ZELLE + ' font-weight: 700; color: var(--text-primary, #e8e8ee); white-space: nowrap;', s));\n            });\n            b.seiten.forEach(function (s) {\n                gs.appendChild(el('div', ZELLE_WERT, s.url));\n                gs.appendChild(el('div', ZELLE, T['typ_' + s.typ] || s.typ));\n                var t = zahl(s.ttfb_ms);\n                gs.appendChild(el('div', ZELLE_WERT + (t === null ? '' : (t >= 600 ? ROT : (t >= 300 ? WARN : GUT))), t === null ? '-' : t + ' ms'));\n                gs.appendChild(el('div', ZELLE_WERT, s.kb + ' KB'));\n                gs.appendChild(el('div', ZELLE_WERT, s.skripte + (s.blockierend ? ' (' + s.blockierend + ')' : '')));\n                gs.appendChild(el('div', ZELLE_WERT, String(s.bilder)));\n                var c = s.cache && s.cache.erkannt;\n                gs.appendChild(el('div', ZELLE + (c ? GUT : WARN), c ? (s.cache.name || T.ja) : T.nein));\n            });\n            tabelle.appendChild(gs);\n            ziel.appendChild(tabelle);\n        }<\/p>\n<p>        \/\/ --- Sonden ---\n        var so = b.sonden;\n        if (so.gelaufen) {\n            ziel.appendChild(el('div', UEBERSCHRIFT, T.h_sonden));\n            var gso = gitter('auto auto');\n            Object.keys(so.gelaufen).forEach(function (n) {\n                var lauf = so.gelaufen[n];\n                var w = '';\n                if (lauf !== 'ok') { w = lauf === 'budget' ? T.sonde_budget : T.sonde_fehler; }\n                else if (n === 'http' && so.http) { w = so.http.status + (so.http.ort ? ' \u2192 ' + so.http.ort : ''); }\n                else if (n === 'author' && so.author) { w = so.author.status + (so.author.ort ? ' \u2192 ' + so.author.ort : ''); }\n                else if ((n === 'css' || n === 'js') && so[n]) { w = so[n].status + (so[n].cache_control ? ' \u00b7 ' + so[n].cache_control : '') + (so[n].kompression ? ' \u00b7 ' + so[n].kompression : ''); }\n                else { w = String(so[n] === null || so[n] === undefined ? '-' : so[n]); }\n                paar(gso, T['sonde_' + n] || n, w, GRAU);\n            });\n            ziel.appendChild(gso);\n        }\n    }\n    window.LW_TEST.WH.darstellen = darstellen;<\/p>\n<p>    var laeuft = false;\n    function lauf(url, erneut) {\n        if (laeuft) { return; }\n        laeuft = true; btn.disabled = true;\n        out.innerHTML = '';\n        out.appendChild(el('p', ZELLE + GRAU + ' margin: 0;', T.laeuft));\n        var spaet = setTimeout(function () {\n            var p = out.querySelector('p');\n            if (p && laeuft) { p.textContent = T.laeuft_lang; }\n        }, 12000);\n        abfragen(url, erneut).then(function (a) {\n            clearTimeout(spaet);\n            darstellen(bewerten(a), out); laeuft = false; btn.disabled = false;\n        }, function () {\n            clearTimeout(spaet);\n            darstellen(bewerten({ fehler: 'netz' }), out); laeuft = false; btn.disabled = false;\n        });\n    }\n    btn.addEventListener('click', function () { lauf(wert('wh-url'), false); });\n    out.addEventListener('click', function (ev) {\n        var t = ev.target;\n        if (t && t.classList && t.classList.contains('wh-erneut')) {\n            ev.preventDefault();\n            lauf(t.getAttribute('data-url') || wert('wh-url'), true);\n        }\n    });\n})();\n<\/script><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Eine Adresse gen\u00fcgt: Der Bericht bewertet einen WordPress-Blog oder WooCommerce-Shop nach Seitencache, Kompression, HTTP\/2, blockierenden Skripten, Bildladeverhalten, Cart Fragments auf jeder Seite, Versionslecks und offenem XML-RPC \u2013 mit Punkten. Berichte bleiben einen Tag gespeichert; ein Knopf pr\u00fcft nach \u00c4nderungen erneut.<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":9283,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"template-tool-base.php","meta":{"footnotes":""},"tags":[92107,92292,92071,92277],"class_list":["post-13515","page","type-page","status-publish","hentry","tag-e-commerce-de","tag-web-performance-de","tag-web-security-de","tag-wordpress-de"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v28.1 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>WordPress Site Health Analyzer - Lukas Wojcik - Blog<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.lukaswojcik.com\/blog\/de\/werkzeuge\/wordpress-site-health-analyzer\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"WordPress Site Health Analyzer - Lukas Wojcik - Blog\" \/>\n<meta property=\"og:description\" content=\"Eine Adresse gen\u00fcgt: Der Bericht bewertet einen WordPress-Blog oder WooCommerce-Shop nach Seitencache, Kompression, HTTP\/2, blockierenden Skripten, Bildladeverhalten, Cart Fragments auf jeder Seite, Versionslecks und offenem XML-RPC \u2013 mit Punkten. Berichte bleiben einen Tag gespeichert; ein Knopf pr\u00fcft nach \u00c4nderungen erneut.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.lukaswojcik.com\/blog\/de\/werkzeuge\/wordpress-site-health-analyzer\/\" \/>\n<meta property=\"og:site_name\" content=\"Lukas Wojcik - Blog\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/08\/og-default.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"1200\" \/>\n\t<meta property=\"og:image:height\" content=\"630\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data1\" content=\"1 minute\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/de\\\/werkzeuge\\\/wordpress-site-health-analyzer\\\/\",\"url\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/de\\\/werkzeuge\\\/wordpress-site-health-analyzer\\\/\",\"name\":\"WordPress Site Health Analyzer - Lukas Wojcik - Blog\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#website\"},\"datePublished\":\"2026-09-02T07:48:25+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/de\\\/werkzeuge\\\/wordpress-site-health-analyzer\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/de\\\/werkzeuge\\\/wordpress-site-health-analyzer\\\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/de\\\/werkzeuge\\\/wordpress-site-health-analyzer\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Toolbox\",\"item\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/toolbox-2\\\/\"},{\"@type\":\"ListItem\",\"position\":3,\"name\":\"WordPress Site Health Analyzer\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#website\",\"url\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/\",\"name\":\"Lukas Wojcik - Blog\",\"description\":\"\",\"publisher\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#\\\/schema\\\/person\\\/895f7604f9b6b71aad9bba33af28d0f9\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":[\"Person\",\"Organization\"],\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#\\\/schema\\\/person\\\/895f7604f9b6b71aad9bba33af28d0f9\",\"name\":\"luky\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/lw-x2.jpg\",\"url\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/lw-x2.jpg\",\"contentUrl\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/lw-x2.jpg\",\"width\":424,\"height\":636,\"caption\":\"luky\"},\"logo\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/lw-x2.jpg\"},\"sameAs\":[\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\"]}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"WordPress Site Health Analyzer - Lukas Wojcik - Blog","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.lukaswojcik.com\/blog\/de\/werkzeuge\/wordpress-site-health-analyzer\/","og_locale":"en_US","og_type":"article","og_title":"WordPress Site Health Analyzer - Lukas Wojcik - Blog","og_description":"Eine Adresse gen\u00fcgt: Der Bericht bewertet einen WordPress-Blog oder WooCommerce-Shop nach Seitencache, Kompression, HTTP\/2, blockierenden Skripten, Bildladeverhalten, Cart Fragments auf jeder Seite, Versionslecks und offenem XML-RPC \u2013 mit Punkten. Berichte bleiben einen Tag gespeichert; ein Knopf pr\u00fcft nach \u00c4nderungen erneut.","og_url":"https:\/\/www.lukaswojcik.com\/blog\/de\/werkzeuge\/wordpress-site-health-analyzer\/","og_site_name":"Lukas Wojcik - Blog","og_image":[{"width":1200,"height":630,"url":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/08\/og-default.jpg","type":"image\/jpeg"}],"twitter_card":"summary_large_image","twitter_misc":{"Est. reading time":"1 minute"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/www.lukaswojcik.com\/blog\/de\/werkzeuge\/wordpress-site-health-analyzer\/","url":"https:\/\/www.lukaswojcik.com\/blog\/de\/werkzeuge\/wordpress-site-health-analyzer\/","name":"WordPress Site Health Analyzer - Lukas Wojcik - Blog","isPartOf":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/#website"},"datePublished":"2026-09-02T07:48:25+00:00","breadcrumb":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/de\/werkzeuge\/wordpress-site-health-analyzer\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.lukaswojcik.com\/blog\/de\/werkzeuge\/wordpress-site-health-analyzer\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/www.lukaswojcik.com\/blog\/de\/werkzeuge\/wordpress-site-health-analyzer\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.lukaswojcik.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Toolbox","item":"https:\/\/www.lukaswojcik.com\/blog\/toolbox-2\/"},{"@type":"ListItem","position":3,"name":"WordPress Site Health Analyzer"}]},{"@type":"WebSite","@id":"https:\/\/www.lukaswojcik.com\/blog\/#website","url":"https:\/\/www.lukaswojcik.com\/blog\/","name":"Lukas Wojcik - Blog","description":"","publisher":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/#\/schema\/person\/895f7604f9b6b71aad9bba33af28d0f9"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.lukaswojcik.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":["Person","Organization"],"@id":"https:\/\/www.lukaswojcik.com\/blog\/#\/schema\/person\/895f7604f9b6b71aad9bba33af28d0f9","name":"luky","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/07\/lw-x2.jpg","url":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/07\/lw-x2.jpg","contentUrl":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/07\/lw-x2.jpg","width":424,"height":636,"caption":"luky"},"logo":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/07\/lw-x2.jpg"},"sameAs":["https:\/\/www.lukaswojcik.com\/blog"]}]}},"_links":{"self":[{"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/pages\/13515","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/comments?post=13515"}],"version-history":[{"count":0,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/pages\/13515\/revisions"}],"up":[{"embeddable":true,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/pages\/9283"}],"wp:attachment":[{"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/media?parent=13515"}],"wp:term":[{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/tags?post=13515"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}