Schlagwort: core

  • login-gate


    Login Gate


    Das Login-Gate-Modul schützt die Login-Seite mit einer vorgeschalteten „Vorraum“-Seite: Statt direkt das Login-Formular zu sehen, müssen Besucher erst einen Button klicken. Das blockiert einen Großteil automatisierter Bot-Angriffe, bevor überhaupt ein Login-Versuch stattfindet.

    Allgemein

    Ablauf


    Ruft ein Besucher die Login-Seite auf, erscheint zunächst nur die Gate-Seite mit einem einzelnen Button „Jetzt einloggen“. Ein Klick darauf setzt (optional nach erfolgreicher reCAPTCHA-Prüfung im Hintergrund) einen kurzlebigen Cookie und leitet zurück zur Login-Seite – erst jetzt erscheint das eigentliche Formular für Benutzername und Passwort.

    Netzwerkweit, zentral gesteuert


    Anders als die meisten Module lässt sich das Login Gate nicht pro Site ein- oder ausschalten – es gibt eine einzige, zentrale Einstellung unter Weinhold Netzwerk → Login Gate, die für alle Sites gleichzeitig gilt. Zusätzlich lässt sich einstellen, wie lange der Gate-Cookie nach dem Klick gültig bleibt (1–60 Minuten).

    Zusammenspiel mit reCAPTCHA


    Ist das reCAPTCHA-Modul aktiv, wird beim Klick auf den Gate-Button zusätzlich ein unsichtbarer reCAPTCHA-Score geprüft, bevor der Cookie gesetzt wird. Ohne aktives reCAPTCHA-Modul funktioniert das Gate trotzdem – dann zählt allein der Button-Klick.

    Dateien

    modules/login_gate_core.php – einzige Datei des Moduls (Core-Modul, das _core.php-Suffix lädt es immer): Cookie-/Token-Verwaltung, POST-Handler für den Gate-Klick, Gate-Seiten-Rendering, Admin-Einstellungen, Cleanup.

    Für Entwickler

    Einhängepunkt: weinhold_auth_login_override


    Login Gate hängt sich mit Priorität 5 in denselben Filter weinhold_auth_login_override ein, über den auch das Gerätesicherheit-Modul seine Challenge-Seite anzeigt. Ist das Gate aktiv und kein gültiger Cookie vorhanden, liefert es HTML für die Vorraum-Seite statt null zurück – das Benutzerverwaltung-Modul zeigt dieses HTML dann anstelle des normalen Login-Formulars.

    Cookie & Transient


    Nach dem Button-Klick wird ein zufälliger Token erzeugt, als Transient wf_gate_{token} mit der konfigurierten Lebensdauer gespeichert und zusätzlich als HttpOnly-Cookie wf_login_gate (SameSite=Strict, Secure bei SSL) im Browser abgelegt. weinhold_login_gate_has_valid_cookie() prüft bei jedem Login-Seitenaufruf, ob Cookie-Wert und Transient noch zusammenpassen.

    Schutz vor direkten POST-Angriffen


    Das Security-Manager-Modul liest denselben Cookie-Namen (wf_login_gate) und denselben Transient-Präfix in seiner eigenen Funktion weinhold_security_block_gateless_post() – ein POST direkt auf die Login-Verarbeitung ohne gültigen Gate-Cookie wird dort blockiert, unabhängig vom Gate-Rendering selbst. Die beiden Module sind also bewusst über den Cookie-Namen gekoppelt, nicht über einen direkten Funktionsaufruf.

    Besonderheiten

    Keine Per-Site-Steuerung: Bewusste Design-Entscheidung, weil ein Bot-Schutz nur netzwerkweit konsistent wirksam ist – eine einzelne ungeschützte Subsite würde sonst weiterhin direkte Angriffe erlauben.

    reCAPTCHA-Prüfung passiert zweimal im vollen Flow: einmal beim Gate-Klick (dieses Modul) und ein zweites Mal beim eigentlichen Login-Submit (Benutzerverwaltung-Modul, sofern dort ebenfalls aktiviert) – zwei unabhängige Kontrollpunkte statt einem.

    Fehlermeldungen (ungültiger Nonce, fehlgeschlagene reCAPTCHA-Prüfung) werden IP-basiert als kurzlebiger Transient zwischengespeichert und beim nächsten Aufruf der Gate-Seite einmalig angezeigt – kein Session- oder Cookie-basierter Mechanismus dafür nötig.

    Versionshistorie

    VersionDatumÄnderung
    1.0.022.09.2026Einführung der Versionierung.


  • security-manager


    Security Manager


    Der Security Manager ist ein Core-Modul des Weinhold Frameworks und schützt alle Sites im Netzwerk vor Brute-Force-Angriffen und unerwünschten IPs. Er arbeitet still im Hintergrund und greift so früh wie möglich ein, teils schon bevor WordPress selbst reagiert.

    Allgemein

    IP-Blacklist


    Bestimmte IP-Adressen können dauerhaft auf eine Sperrliste gesetzt werden. Anfragen von diesen IPs werden sofort mit 403 blockiert – noch bevor der WordPress-Login-Prozess startet.

    Login-Lockout


    Nach einer konfigurierbaren Anzahl fehlgeschlagener Login-Versuche wird die betreffende IP automatisch für einen festgelegten Zeitraum gesperrt (429, Wartezeit in der Fehlermeldung genannt). Besonders geschützte Benutzerkonten (z. B. Administratoren) bekommen zusätzlich eine eigene, strengere Sperre nach Benutzername statt nach IP.

    Vertrauenswürdige IPs & Notfall-Zugang


    Fest hinterlegte vertrauenswürdige IPs umgehen alle Sperren komplett. Zusätzlich gibt es einen Notfall-Token: ein per URL-Parameter übergebenes Geheimnis, das bei Übereinstimmung sämtliche Sperren für die aktuelle IP sowie alle geschützten Konten aufhebt und eine zehnminütige Vertrauens-Session setzt – gedacht für den Fall, dass man sich selbst ausgesperrt hat.

    Administration & Protokollierung


    Im Dashboard unter Weinhold → Security Manager können gesperrte IPs eingesehen, entsperrt oder dauerhaft blockiert werden. Alle Lockout-Ereignisse werden automatisch im Audit-Log protokolliert, sodass verdächtige Aktivitäten nachvollziehbar bleiben.

    Dateien

    modules/security_manager_core.php – einzige Datei des Moduls (Core-Modul, das _core.php-Suffix lädt es immer): Einstellungen, IP-Sperren, Lockout-Logik, Login-Hooks, Admin-Oberfläche.

    Für Entwickler

    Einstellungen (Option weinhold_security_settings)


    SchlüsselBedeutung
    lockout_thresholdFehlversuche bis zur IP-Sperre (Standard 5)
    lockout_durationSperrdauer in Minuten (Standard 15)
    blacklistDauerhaft gesperrte IP-Adressen
    trusted_ipsIPs, die alle Sperren umgehen
    emergency_tokenGeheimnis für den Notfall-Zugang per URL-Parameter
    protected_usersZusätzlich geschützte Benutzernamen (Super-Admins sind bei Multisite automatisch geschützt)
    protected_threshold,protected_lockout_durationStrengere Schwelle/Dauer speziell für geschützte Konten
    lockout_ip_on_protected_failOb ein Fehlversuch bei einem geschützten Konto zusätzlich die IP sperrt
    disable_xmlrpcXML-RPC komplett deaktivieren (Standard an)

    Login-Flow (Hooks)


    HookPrioritätZweck
    init0weinhold_security_handle_emergency_token() – prüft den URL-Parameter wf_emergency und hebt bei Treffer alle Sperren auf
    init1weinhold_security_check_ip() – blockiert blacklistete/gesperrte IPs auf JEDEM Request, nicht nur beim Login
    login_init1weinhold_security_block_native_auth() – leitet wp-login.php-Aufrufe auf die eigenen Auth-Seiten des user_management-Moduls um
    login_init2weinhold_security_block_locked_login() – blockiert Login-POSTs gesperrter IPs, bevor WordPress die Zugangsdaten prüft
    login_init3weinhold_security_block_gateless_post() – blockiert Login-POSTs ohne gültiges Login-Gate-Cookie, falls das login_gate-Modul aktiv ist
    authenticate30weinhold_security_authenticate() – liefert WP_Error bei gesperrter IP oder gesperrtem geschütztem Konto
    wp_login_failed10weinhold_security_login_failed() – zählt Fehlversuche hoch, versendet Benachrichtigungs-Mails

    IP-Ermittlung


    weinhold_security_get_client_ip() prüft der Reihe nach CF-Connecting-IP, X-Real-IP, X-Forwarded-For und REMOTE_ADDR und nimmt die erste gültige IP-Adresse – wichtig hinter Reverse-Proxy/CDN, damit nicht die Proxy-IP statt der echten Besucher-IP gesperrt wird.

    Besonderheiten

    Läuft parallel zum user_management-Modul: Beide Module leiten wp-login.php-Aufrufe auf die eigenen Auth-Seiten um (security_manager auf login_init, user_management ebenfalls) – bewusst redundant abgesichert, nicht als Bug zu verstehen.

    Blacklist- und Lockout-Prüfung laufen bereits auf init mit Priorität 1, also auf JEDEM Seitenaufruf der ganzen Website, nicht nur beim Login – eine geblacklistete IP kommt gar nicht erst auf normale Seiten.

    Der Notfall-Token gibt nie einen Hinweis, ob er falsch war (stiller Fehlschlag) – verhindert, dass jemand per Trial-and-Error herausfindet, ob überhaupt ein Token konfiguriert ist.

    E-Mail-Adressen im Login-Feld werden vor der Sperrprüfung auf den echten Benutzernamen aufgelöst, damit Lockout-Zähler für „admin“ und „admin@example.com“ nicht getrennt gezählt werden.

    XML-RPC wird standardmäßig komplett deaktiviert (xmlrpc_enabled-Filter auf false) – ein häufiges Ziel für Brute-Force-Bots, das WordPress sonst parallel zum normalen Login offen lässt.

    Versionshistorie

    VersionDatumÄnderung
    1.0.022.09.2026Einführung der Versionierung.


  • geraetesicherheit


    Gerätesicherheit


    Die Gerätesicherheit ist ein Core-Modul des Weinhold Frameworks – es ist immer geladen (lässt sich aber über eine eigene Einstellung ein-/ausschalten) und wirkt netzwerkweit auf allen Sites. Es erkennt unbekannte Geräte beim Login und verlangt eine Sicherheitsfrage, bevor der Zugang gewährt wird – eine zusätzliche Schutzschicht, die auch bei einem kompromittierten Passwort greift.

    Allgemein

    Wie es funktioniert


    Beim Login prüft das Modul per Cookie, ob das aktuelle Gerät bereits als vertrauenswürdig hinterlegt ist. Ist das Gerät unbekannt und hat der Nutzer Sicherheitsfragen eingerichtet, wird der Login abgefangen und eine zufällig ausgewählte Frage gestellt. Erst nach korrekter Antwort wird der Nutzer eingeloggt; auf Wunsch merkt sich das Modul das Gerät danach für eine konfigurierbare Anzahl Tage.

    Hat ein Nutzer noch keine Sicherheitsfragen hinterlegt, wird der Login trotzdem erlaubt – im Profil erscheint dann ein Hinweis, sie einzurichten. So wird niemand ausgesperrt, der die Funktion noch nicht konfiguriert hat.

    Sicherheitsfragen (Profil)


    Jeder Nutzer richtet im eigenen Profil bis zu drei Sicherheitsfragen ein (die erste ist Pflicht, sobald mindestens eine gespeichert werden soll). Zur Auswahl stehen sechs vorgeschlagene Fragen oder ein freier Text. Die Antworten werden nie im Klartext gespeichert, sondern nur als Hash – beim Bearbeiten muss deshalb jedes Feld neu ausgefüllt werden; ein leer gelassenes Antwortfeld behält die bestehende gespeicherte Antwort.

    Vertrauenswürdige Geräte


    Im Profil sieht jeder Nutzer eine Liste seiner vertrauenswürdigen Geräte (Browser-/Geräte-Kennung, IP, zuletzt genutzt) und kann einzelne Geräte entfernen. Der Button „Auf allen Geräten ausloggen“ beendet zusätzlich alle aktiven Sitzungen und löscht alle gespeicherten Geräte auf einen Schlag.

    Admin-Einstellungen


    Unter Weinhold Netzwerk → Gerätesicherheit lässt sich das Modul aktivieren/deaktivieren, die Benachrichtigungs-Mail bei neuem Gerät ein-/ausschalten und die Gültigkeitsdauer eines vertrauenswürdigen Geräts festlegen (1–3650 Tage). Da das Modul netzwerkweit wirkt, gibt es keine Einstellungen pro Site – ein Site-Admin wird beim Aufruf automatisch zum Netzwerk-Admin weitergeleitet.

    Dateien

    modules/device_security_core.php – einzige Datei des Moduls (Core-Modul, das _core.php-Suffix lädt es immer): Datenbank, Einstellungen, Cookie- und Token-Verwaltung, Sicherheitsfragen, Login-Hooks, Profil- und Admin-Oberfläche.

    Für Entwickler

    Datenbank


    SpalteTypBedeutung
    idbigint,Auto-IncrementPrimärschlüssel
    user_idbigintZugehöriger Nutzer
    token_hashvarchar(64),uniqueSHA-256-Hash des Geräte-Tokens
    labelvarchar(255)Kurzbeschreibung, meist der User-Agent
    ipvarchar(45)IP-Adresse bei der Verifizierung
    created_atdatetimeErstellt (UTC)
    last_useddatetimeZuletzt genutzt (UTC)

    Tabellenname über weinhold_device_table(), Installation via weinhold_device_maybe_install() (versioniert über die Option weinhold_device_security_db_version auf der Hauptseite).

    Login-Flow (Hooks)


    HookPrioritätZweck
    authenticate35weinhold_device_authenticate() – nach erfolgreicher WP-Authentifizierung: bekanntes Gerät durchlassen, unbekanntes Gerät mit vorhandenen Fragen liefert WP_Error(‚weinhold_device_challenge‘, …, $chal_token) statt des Logins
    wp_login_failed5weinhold_device_handle_login_failed() – fängt den Error-Code weinhold_device_challenge ab und leitet zur Challenge-Seite um
    wp_login10weinhold_device_on_login_success() – aktualisiert last_used bei bekanntem Gerät

    Die Challenge selbst liegt 5 Minuten als Transient (weinhold_dev_chal_{32-Zeichen-Hex-Token}) und enthält Nutzer-ID, „Angemeldet bleiben“-Flag, Redirect-Ziel und den Index der gestellten Frage.

    Wichtige Funktionen


    FunktionBeschreibung
    weinhold_device_is_trusted($user_id,$raw_token):boolPrüft ob ein Geräte-Token zu diesem Nutzer gehört
    weinhold_device_save_token($user_id,$raw_token,$label,$ip)Speichert ein neues vertrauenswürdiges Gerät
    weinhold_device_revoke_token($device_id,$user_id)Entfernt ein einzelnes Gerät
    weinhold_device_revoke_all($user_id)Entfernt alle Geräte eines Nutzers
    weinhold_device_logout_everywhere($user_id)Zerstört alle Sessions (WP_Session_Tokens) und alle Geräte-Tokens
    weinhold_device_has_questions($user_id):boolOb der Nutzer Sicherheitsfragen eingerichtet hat
    weinhold_device_verify_answer($user_id,$question_index,$raw_answer):boolPrüft eine Antwort per hash_equals() gegen den gespeicherten SHA-256-Hash

    Integrationspunkte


    Filter weinhold_auth_login_override – rendert das Challenge-Formular anstelle des normalen Login-Formulars, wenn der GET-Parameter device_challenge gesetzt ist (genutzt vom user_management-Modul).

    Filter weinhold_auth_profile_extra – hängt die Profil-Sektion (Sicherheitsfragen, Geräteliste) an die Profilseite an.

    Filter weinhold_email_templates – registriert die zwei modul-eigenen Vorlagen device_new und device_challenge_failed beim E-Mail-Versand-Modul.

    Filter weinhold_audit_modules – meldet sich beim Audit-Log mit den Aktionen device_verified, device_revoked, challenge_failed, logout_everywhere an.

    Besonderheiten

    Netzwerkweit statt pro Site – es gibt bewusst keine Site-Einstellungen; ein Site-Admin, der die Modulseite aufruft, wird automatisch zum Netzwerk-Admin weitergeleitet.

    Sicherheitsfragen werden nur als hash(’sha256′, …) der kleingeschriebenen, getrimmten Antwort gespeichert, nie im Klartext – der Abgleich läuft über hash_equals(), um Timing-Angriffe zu vermeiden.

    Kein Zwang zur Einrichtung: Ohne gespeicherte Sicherheitsfragen wird der Login trotzdem erlaubt, nur ein Hinweis-Transient (10 Minuten) sorgt für einen Einrichtungs-Hinweis im Profil.

    Geräte-Cookie weinhold_device_trust_{COOKIEHASH} ist HttpOnly und SameSite=Strict, bei SSL zusätzlich Secure – auf PHP-Versionen unterhalb von 7.3 übernimmt ein Fallback mit manuell zusammengesetztem Pfad-String dieselbe SameSite-Einstellung.

    Eine fehlgeschlagene Sicherheitsfrage löst eine separate Warn-Mail aus (device_challenge_failed) – anders als eine neue erfolgreiche Verifizierung, die nur informiert.

    Versionshistorie

    VersionDatumÄnderung
    1.0.022.09.2026Einführung der Versionierung.


  • benutzerverwaltung


    Benutzerverwaltung


    Die Benutzerverwaltung ist ein Core-Modul des Weinhold Frameworks und das zentrale Authentifizierungssystem – Registrierung, Login, Profilbearbeitung, Passwort-Reset und Rollenzuweisung laufen netzwerkweit über eigene Shortcode-Seiten statt über die WordPress-Standardseiten.

    Allgemein

    Eigene Login-Seiten statt wp-login.php


    Login, Registrierung, Profil und Passwort-vergessen laufen über eigene, per Shortcode gebaute Seiten (meist auf der Hauptsite, netzwerkweit gültig). Aufrufe von wp-login.php werden automatisch auf die passende eigene Seite umgeleitet – nur der eigentliche Formular-POST für den Login selbst sowie technische Flows (Logout, Postpass, Bestätigungslinks) bleiben unangetastet.

    In der Praxis – weinify.de


    Auf weinify.de und allen Subsites läuft das komplette Login- und Registrierungssystem über dieses Modul. Der weinhold_auth_nav-Shortcode ist im Custom Header eingebunden und sorgt für die siteübergreifende Navigation zwischen Login, Profil und weiteren Seiten.

    Rollen & Berechtigungen


    Administratoren weisen Rollen und Modulberechtigungen zentral im Dashboard unter Weinhold → Nutzerverwaltung → Modulberechtigungen zu. So kann pro Modul konfiguriert werden, welche Rollen Lese- oder Schreibzugriff haben. Die Rolle eines Nutzers wird dabei immer pro Site einzeln ermittelt (Multisite-Capabilities), nicht netzwerkweit einheitlich.

    Profilbild (Avatar)


    Nutzer können über das Profil ein eigenes Profilbild hochladen, das Gravatar/Identicon ersetzt – wahlweise netzwerkweit gültig (global) oder nur für die aktuelle Site (lokal, überschreibt global). Fallback-Reihenfolge: Site-spezifisch → Global → WordPress-Standard.

    Shortcodes

    ShortcodeBeschreibung
    weinhold_auth_loginLogin-Formular
    weinhold_auth_registerRegistrierungsformular für neue Benutzer
    weinhold_auth_profileProfilansicht und -bearbeitung für angemeldete Benutzer (Passwort ändern, Avatar hochladen)
    weinhold_auth_lostpasswordFormular zum Zurücksetzen des Passworts
    weinhold_auth_navNavigationsleiste mit Links zu Login, Profil und weiteren Bereichen
    weinhold_show_on_loginUmschlossener Inhalt wird nur angemeldeten Besuchern angezeigt
    weinhold_show_on_logoutUmschlossener Inhalt wird nur abgemeldeten Besuchern (Gästen) angezeigt

    Dateien

    modules/user_management_core.php – einzige Datei des Moduls (Core-Modul, das _core.php-Suffix lädt es immer, mit Abstand die größte Moduldatei des Frameworks): Auth-Seiten-Verwaltung, Shortcode-Formulare, Rollen-/Rechte-Auflösung, Redirect-Schutz, Netzwerk- und Site-Admin-Seiten, Avatar-System.

    Für Entwickler

    Auth-Seiten (zentral konfiguriert)


    Die Ziel-Seiten für Login/Registrierung/Profil/Passwort-vergessen werden als Post-IDs in der Netzwerk-Option weinhold_network_auth_settings gespeichert (auth_blog_id plus je eine Page-ID pro Zweck). weinhold_user_management_get_auth_page_url($key) löst daraus die tatsächliche Permalink-URL auf (wechselt bei Multisite kurz auf den konfigurierten auth_blog_id via switch_to_blog()).

    Rollen & Capabilities


    FunktionBeschreibung
    weinhold_user_management_get_roles_for_site($site_id)Editierbare Rollen einer Site (get_editable_roles(), pro Site via switch_to_blog())
    weinhold_user_management_get_user_role_for_site($user_id,$site_id)Liest die Rolle eines Nutzers direkt aus dessen Capabilities-Meta der jeweiligen Site
    weinhold_user_management_get_default_role($roles)Vorbelegte Rolle bei der Registrierung (subscriber, falls vorhanden, sonst die erste verfügbare)
    weinhold_user_management_sort_roles_for_display($roles)Sortiert Rollen fuer die Anzeige: WordPress-Systemrollen zuerst in fester Reihenfolge, Rest alphabetisch

    Redirect-Validierung


    weinhold_user_management_validate_login_redirect_target($redirect_raw) normalisiert und prüft jedes redirect_to-Ziel gegen Open-Redirect-Angriffe: HTML-Entities und mehrfach URL-kodierte Werte werden dekodiert, schema-lose Domains erkannt, und am Ende nur relative Pfade, per wp_validate_redirect() erlaubte Hosts oder (bei Multisite) Domains anderer Netzwerk-Sites akzeptiert – sonst greift ein Fallback auf die Startseite.

    Profilbild-Auflösung


    Eingehängt über den WordPress-Filter pre_get_avatar_data, wirkt dadurch automatisch überall wo get_avatar_url()/get_avatar() aufgerufen wird. Zwei Speicherebenen: global per update_user_meta($uid,’weinhold_avatar_global‘,$url) (netzwerkweit) und lokal per update_user_option($uid,’weinhold_avatar_local‘,$url,false) (nur aktuelle Site, hat Vorrang). weinhold_um_get_avatar_url($user_id) liefert die aufgelöste URL oder einen leeren String, wenn kein eigenes Bild hinterlegt ist. Upload-Verzeichnis: uploads/weinhold-avatars/ (bei Multisite-Subsites entsprechend unter uploads/sites/{id}/).

    Besonderheiten

    wp-login.php bleibt technisch erreichbar (WordPress braucht es intern), wird aber bei GET-Aufrufen automatisch auf die konfigurierte eigene Seite umgeleitet – der Login-POST selbst läuft weiterhin über wp-login.php, damit WordPress-Auth-Cookies korrekt gesetzt werden.

    Fehlgeschlagene Logins über wp-login.php werden ebenfalls abgefangen (wp_login_failed-Hook), damit Fehlermeldungen auf der eigenen Login-Seite statt auf der WordPress-Standardseite erscheinen.

    Angemeldete Nutzer, die eine Auth-Seite (Login/Registrierung) direkt aufrufen, werden per template_redirect automatisch weggeleitet (z. B. zum Profil) – verhindert ein erneutes Login-Formular für bereits eingeloggte Besucher.

    Admin-Bar im Frontend ist standardmäßig ausgeblendet (auch für Administratoren, konfigurierbar unter Weinhold → Nutzerverwaltung → UI-Einstellungen) – Ausnahme lässt sich pro Einstellung gezielt wieder aktivieren.

    allowed_redirect_hosts wird um alle Domains des Multisite-Netzwerks erweitert, damit wp_safe_redirect() auch netzwerkinterne Ziel-Sites als sicher akzeptiert.

    Versionshistorie

    VersionDatumÄnderung
    1.0.022.09.2026Einführung der Versionierung.


  • audit-log


    Audit-Log


    Der Audit-Log ist ein Core-Modul des Weinhold Frameworks – er ist immer aktiv und kann nicht deaktiviert werden. Er protokolliert alle relevanten Aktionen im gesamten Multisite-Netzwerk in einer gemeinsamen Tabelle, getrennt nach Site-ID.

    Allgemein

    Was wird protokolliert?


    Der Audit-Log ist in drei Kategorien unterteilt:
    WordPress-Ereignisse – werden automatisch vom Modul erfasst:
    Auth – Login (erfolgreich & fehlgeschlagen), Logout, Passwort-Reset-Anfragen und Resets inkl. IP-Adresse
    Benutzer & Rollen – Registrierung, Löschung, Rollenwechsel, Profiländerungen, Zuweisung zu und Entfernung aus einzelnen Sites
    E-Mail – Erfolgreicher Versand und fehlgeschlagene E-Mails inkl. Betreff und Empfänger
    Content – Erstellung, Aktualisierung und Löschung von Beiträgen, Seiten, Medien, Kommentaren sowie Taxonomie-Begriffen
    System – Plugin-Aktivierungen und -Deaktivierungen, Theme-Wechsel, Update-Prozesse
    Framework – Änderungen an Weinhold-Framework-Einstellungen (netzwerkweit & pro Site)
    Weinhold-Module – registrieren sich selbst über einen Filter (z.B. Kalender, Security Manager, Highlights)
    Eigene Plugins – externe Plugins können sich über einen separaten Filter eintragen

    Zwei Admin-Ansichten


    Pro Site unter Weinhold → Audit-Log – zeigt ausschließlich Einträge der aktuellen Website, blätterbar (25/50/100/200 pro Seite, Sprung zu beliebiger Seite)
    Netzwerkweit unter Weinhold Netzwerk → Audit-Log – zeigt Einträge aller Sites im Netzwerk, mit zusätzlichem Filter nach Site

    Filtern & Exportieren


    Beide Ansichten lassen sich filtern nach: Modul, Aktion, Status (ok / warning / error / info), Benutzer und Freitextsuche in Nachricht und Kontext. Alle gefilterten Einträge können als CSV exportiert werden – der Export selbst wird ebenfalls im Log protokolliert.

    Statistiken


    Der Tab Statistiken gibt einen grafischen Überblick über die Aktivität im gewählten Zeitraum. Filterbar nach Site, Zeitraum (7 / 14 / 30 / 90 / 180 / 365 Tage) und Modul.
    Kacheln – Gesamtanzahl der Ereignisse sowie Aufschlüsselung nach Status (ok, warning, error, info)
    Verlauf – Tägliches Balkendiagramm der Ereignisanzahl im gewählten Zeitraum
    Ereignisse nach Modul – Horizontale Balken zeigen welche Module am aktivsten sind
    Top Aktionen – Die 15 häufigsten Modul-Aktions-Kombinationen

    Einstellungen


    Die Einstellungen sind in drei Blöcke gegliedert:
    WordPress-Ereignisse – Einzelne Kategorien (Auth, Benutzer, E-Mail Erfolg/Fehler, Content, System, Framework) lassen sich netzwerkweit ein- oder ausschalten
    Weinhold-Module – Master-Schalter + pro Modul individuell aktivierbar/deaktivierbar
    Eigene Plugins – Master-Schalter + pro Plugin individuell aktivierbar/deaktivierbar
    Screenshot


    Zusätzlich gibt es eine Aufbewahrungsfrist (1–3650 Tage, Standard: 90 Tage).

    Pro-Site-Overrides


    Jede Untersite kann den Netzwerk-Standard für jede einzelne Kategorie und für jedes einzelne Modul übersteuern – mit drei Optionen: Vererben (Netzwerk-Standard), Aktivieren oder Deaktivieren. So lässt sich z.B. die Gerätesicherheit nur auf einer bestimmten Untersite aktivieren, während sie auf den anderen vererbt-deaktiviert bleibt.

    Aufbewahrung


    Ein täglicher Cron-Job löscht automatisch alle Einträge die älter als die konfigurierte Aufbewahrungsfrist sind – in Batches von 500 Einträgen um die Datenbank nicht zu belasten.
    Dateien

    modules/audit_log_core.php – Lade-Stub (nur Modul-Header, wird vom Framework-Core erkannt und geladen)
    modules/audit_log/audit_log.php – Daten- und Hook-Logik: Einstellungen, Datenbank-Installation, alle WordPress-Event-Hooks, die öffentliche API (log_event, get_rows, count_rows, get_stats, get_user_history). Wird auf jedem Seitenaufruf geladen, auch im Frontend.
    modules/audit_log/admin.php – Die komplette Admin-Oberfläche: Formular-Verarbeitung, CSV-Export sowie das Rendering aller Tabs (Log, Statistiken, Einstellungen, Bereinigung). Wird nur im WordPress-Backend geladen (is_admin()-Prüfung in audit_log.php) – auf normalen Website-Seiten muss PHP diese Datei gar nicht erst einlesen.
    Kein eigenes CSS oder JS – das Modul nutzt ausschließlich WordPress-Admin-Standardstile.
    Für Entwickler

    Alle Funktionen in diesem Abschnitt liegen in modules/audit_log/audit_log.php (siehe „Dateien“ oben) – sie sind unabhängig vom Admin-Bereich nutzbar.
    Es gibt zwei separate Registrierungswege – je nachdem ob es sich um ein Weinhold-Modul oder ein externes Plugin handelt:
    Weinhold-Module – Schritt 1: Modul registrieren

    add_filter( ‚weinhold_audit_modules‘, function( $modules ) {
    $modules[‚mein_modul‘] = array(
    ‚label‘ => ‚Mein Modul‘,
    ‚description‘ => ‚Kurzbeschreibung für die Einstellungsseite.‘,
    ‚actions‘ => array(
    ‚eintrag_erstellt‘ => ‚Eintrag erstellt‘,
    ‚eintrag_geloescht‘ => ‚Eintrag gelöscht‘,
    ),
    );
    return $modules;
    } );

    Eigene Plugins – Schritt 1: Plugin registrieren

    add_filter( ‚weinhold_audit_custom_modules‘, function( $modules ) {
    $modules[‚mein_plugin‘] = array(
    ‚label‘ => ‚Mein Plugin‘,
    ‚description‘ => ‚Kurzbeschreibung.‘,
    ‚actions‘ => array(
    ‚aktion_a‘ => ‚Aktion A‘,
    ),
    );
    return $modules;
    } );

    Schritt 2 – Event auslösen (gleich für beide)

    if ( function_exists( ‚weinhold_audit_log_log_event‘ ) ) {
    weinhold_audit_log_log_event(
    ‚mein_modul‘, // module_id (muss mit Registrierung übereinstimmen)
    ‚eintrag_erstellt‘, // action
    ‚Neuer Eintrag wurde angelegt.‘,
    array(
    ’status‘ => ‚ok‘,
    ‚context‘ => array( ‚eintrag_id‘ => 42 ),
    )
    );
    }

    Die Funktion prüft selbst ob das Logging für das Modul aktiv ist und ob der jeweilige Master-Schalter gesetzt ist – kein eigenes Checking nötig.

    Verfügbare Kontext-Felder


    FeldTypBedeutung
    statusstringok, warning, error oder info
    contextarrayBeliebige zusätzliche Daten – werden als JSON gespeichert und sind durchsuchbar
    actor_user_idintWer hat die Aktion ausgelöst (Standard: eingeloggter Nutzer)
    target_user_idintWer ist betroffen (optional)
    site_idintFür welche Site (Standard: aktuelle Site)

    Datenstruktur eines Log-Eintrags


    So sieht ein gespeicherter Eintrag in der Datenbank aus:
    SpalteTypBedeutung
    idbigint, Auto-IncrementPrimärschlüssel
    created_at_gmtdatetimeZeitstempel in UTC
    site_idbigintWelche Site im Netzwerk
    actor_user_idbigint, NULLmöglich Wer hat die Aktion ausgelöst (NULL = System)
    target_user_idbigint, NULLmöglich Wen betrifft es (optional)
    modulevarchar(64)Modul-ID, z.B. auth, content, mein_modul
    actionvarchar(100)Aktion, z.B. login, post_updated
    statusvarchar(20)ok / warning / error / info
    messagetextLesbare Beschreibung
    contextlongtextJSON-String mit Zusatzdaten – durchsuchbar

    Daten lesen


    FunktionBeschreibung
    weinhold_audit_log_get_rows( array $filters, int $limit = 50, int $offset = 0 ):array Gibt gefilterte Log-Einträge zurück. Filter: site_id, module, action, status, user_id, search, date_from, date_to. $limit ist auf 50.000 begrenzt.
    weinhold_audit_log_count_rows( array $filters ):int Gesamtanzahl für Pagination – gleiche Filter wie oben.
    weinhold_audit_log_get_stats( int $site_id = 0, int $days = 30, string $module_filter = “ ):array Liefert die Daten hinter dem Statistiken-Tab: Gesamtanzahl, Status-Aufschlüsselung, täglicher Verlauf, Ereignisse nach Modul, Top-Aktionen.
    weinhold_audit_log_get_user_history( int $user_id, int $site_id = 0, int $limit = 20 ):array Letzte Aktionen eines bestimmten Benutzers.

    Registrierte Module abfragen


    Funktionen

    weinhold_audit_get_weinhold_modules(): array // Nur Weinhold-eigene Module
    weinhold_audit_get_custom_modules(): array // Nur externe/eigene Plugins
    weinhold_audit_get_registered_modules(): array // Beide kombiniert

    Wo die Einstellungen gespeichert werden


    OptionSpeicherortEnthält
    weinhold_audit_log_settingsNetzwerk-OptionBool-Schalter pro WP-Kategorie, log_weinhold_modules/log_custom_modules (Master-Schalter), weinhold_toggles/custom_toggles (Array pro Modul-ID), retention_days
    weinhold_audit_log_site_overridesPro-Site-OptionGleiche Felder wie oben, aber dreiwertig: inherit / on / off. Modul-Overrides in weinhold_module_overrides / custom_module_overrides

    Besonderheiten

    Keine IP-Adress-Spalte in der Datenbank – IP-Adressen landen im context-JSON statt in einer eigenen Spalte. Die Freitextsuche durchsucht auch context, eine eigene Spalte war daher nicht nötig.
    weinhold_audit_log_get_user_history() existiert, wird aber bewusst nicht im Benutzerprofil angezeigt – die Funktion ist fertig und nutzbar, aber (noch) an keiner Stelle im Admin verlinkt.
    Kein doppeltes Logging bei neuen Beiträgen – transition_post_status überspringt Übergänge, bei denen der alte Status new oder auto-draft war, weil die Erstellung bereits über den save_post-Hook erfasst wird.
    DB-Migrationen laufen versioniert – Pattern: aktuelle Version aus get_site_option(‚weinhold_audit_log_db_version‘, 0) lesen, dann if ($installed_version < N) { … }-Blöcke nacheinander abarbeiten. So bleiben Updates idempotent, auch wenn jemand mehrere Versionen überspringt.

    Versionshistorie

    VersionDatumÄnderung
    1.0.022.09.2026Einführung der Versionierung.



  • shortcodes


    Shortcodes


    Das Shortcode-Modul ist ein Core-Modul und das Rückgrat des Weinhold Frameworks. Es stellt eine zentrale Registry bereit, über die alle anderen Module ihre Shortcodes registrieren – inklusive Beschreibung und Parameterdokumentation.

    Allgemein

    Wie es funktioniert


    Jedes Modul ruft beim Laden weinhold_add_shortcode() auf und übergibt Tag, Callback, Beschreibung und optionale Parameter-Dokumentation. Das Modul sammelt alle Einträge und listet sie übersichtlich im Admin-Dashboard unter Weinhold → Shortcodes auf – so hat man immer alle verfügbaren Shortcodes im Blick, ohne den Code der einzelnen Module durchsuchen zu müssen.

    Warum Core?


    Dieses Modul wird immer geladen, unabhängig davon ob andere Module aktiv sind. Ohne es würden keine Shortcodes anderer Module registriert. Es ist die stille Grundlage für alles, was auf der Seite sichtbar wird.

    Dateien

    modules/shortcode_core.php – einzige Datei des Moduls (Core-Modul, das _core.php-Suffix lädt es immer): Registrierungsfunktion, Fehlerbehandlung pro Shortcode, Parameter-Katalog als Fallback, Admin-Übersichtsseite.

    Für Entwickler

    Registrierung


    weinhold_add_shortcode($tag,$callback,$description,$parameters=null) ist die empfohlene Art, einen Shortcode zu registrieren – nutzt intern die normale WordPress-Funktion add_shortcode(), wickelt den Callback dabei aber in einen eigenen try/catch. So kann eine unbehandelte Exception oder ein Fehler in EINEM Modul-Shortcode nicht die ganze Seite mit einem PHP-Fatal-Error zum Absturz bringen.

    Parameter-Dokumentation


    Wird $parameters beim Aufruf nicht mitgegeben, versucht weinhold_resolve_shortcode_parameters() der Reihe nach: einen fest hinterlegten Eintrag im internen Parameter-Katalog (vor allem für die zahlreichen pnp_book_*-Shortcodes des PnP-Book-Moduls, deren Parameter historisch hier statt im jeweiligen Modul gepflegt werden), einen Treffer per normalisiertem Tag-Namen (Umlaute/Akzente werden dabei vereinheitlicht, z. B. pnp_book_effektivitaeten und pnp_book_effektivitäten gelten als derselbe Eintrag), oder das Auslesen eines „Attribute: …“-Hinweises direkt aus der Beschreibung.

    Admin-Übersicht


    weinhold_render_core_shortcode_page() rendert unter Weinhold → Shortcodes eine alphabetisch sortierte Tabelle aller registrierten Shortcodes mit Tag, Beschreibung und aufgelösten Parametern.

    Besonderheiten

    Fehlerbehandlung ist rollenabhängig: Schlägt ein Shortcode fehl, sehen Administratoren (manage_options) die vollständige Fehlermeldung inkl. Datei und Zeile direkt auf der Seite, alle anderen Besucher nur einen neutralen Hinweis ohne technische Details. Der volle Fehler landet zusätzlich immer im PHP-Error-Log.

    Nur Module, die tatsächlich weinhold_add_shortcode() statt des nativen add_shortcode() nutzen, profitieren vom Error-Handling und tauchen in der Admin-Übersicht auf – ein Modul kann trotzdem direkt add_shortcode() verwenden, verliert dann aber beides.

    Der Parameter-Katalog enthält deutlich mehr Einträge als aktuell aktive Module Shortcodes registrieren (u. a. alle pnp_book_*-Varianten) – bewusst als zentrale Fallback-Dokumentation gepflegt, unabhängig davon, ob das jeweilige Modul gerade aktiv ist.

    Versionshistorie

    VersionDatumÄnderung
    1.0.022.09.2026Einführung der Versionierung.