Schlagwort: modul

  • cookie-consent


    Cookie Consent


    Das Cookie-Consent-Modul stellt einen DSGVO-konformen Cookie-Banner bereit. Auch auf weinify.de ist dieses Modul aktiv – der Banner, der beim ersten Besuch erscheint, kommt direkt aus diesem Modul.

    Allgemein

    Einwilligungskategorien


    Die Einwilligung wird in vier Kategorien unterteilt: Notwendig (immer aktiv, nicht abwählbar), Funktional, Statistik und Marketing. Banner-Titel, Text und alle Schaltflächenbeschriftungen lassen sich pro Subsite individuell anpassen.

    Seitenspezifische Texte


    Für einzelne Seiten lässt sich der Standard-Bannertext überschreiben – etwa um auf einer speziellen Landingpage einen abweichenden Hinweistext zu zeigen. Ist keine Überschreibung hinterlegt, gilt der allgemeine Text der Subsite.

    Datenschutz- & Impressum-Links


    Der Banner kann Links zu Datenschutzerklärung und Impressum anzeigen. Beide Quellen sind pro Subsite frei wählbar: eine lokale WordPress-Seite, eine manuell eingetragene URL, oder – im Multisite-Netzwerk – eine netzwerkweit zentral hinterlegte URL (unter Weinhold Netzwerk → Cookie Consent), die sich alle Subsites teilen können.

    Erneut öffnen


    Ein dauerhaft sichtbarer Button (optional nur als Icon) sowie der Shortcode weinhold_cookie_settings erlauben es Besuchern, ihre Cookie-Einstellungen jederzeit nachträglich zu ändern – ideal platziert auf einer Datenschutzseite.

    Shortcodes

    ShortcodeBeschreibung
    weinhold_cookie_settingsButton, der das Cookie-Einstellungspanel erneut öffnet

    Dateien

    modules/cookie_consent.php – einzige PHP-Datei des Moduls: Einstellungen, Netzwerk-Links, Frontend-Konfiguration, Admin-Oberflächen (Site + Netzwerk), Cleanup. Frontend-Verhalten (Banner ein-/ausblenden, Cookie setzen) läuft über assets/weinhold_cookie_consent_front.js und die zugehörige CSS-Datei.

    Für Entwickler

    Übergabe an das Frontend


    weinhold_cookie_consent_build_frontend_config() stellt ein Konfigurationsobjekt zusammen (Cookie-Name, Lebensdauer in Tagen, Texte, Button-Beschriftungen, aufgelöste Datenschutz-/Impressum-Links) und übergibt es per wp_localize_script() als weinholdCookieConsentConfig an das Frontend-JS. Die eigentliche Banner-Logik (Anzeigen, Speichern der Auswahl als Cookie, Wiederöffnen) läuft vollständig im JS, PHP liefert nur Konfiguration und das leere HTML-Grundgerüst.

    Einstellungen (Option weinhold_cookie_consent_settings, pro Site)


    SchlüsselBedeutung
    enabledModul auf dieser Site aktiv
    consent_lifetime_daysGültigkeitsdauer der Einwilligung (30–3650 Tage)
    banner_title,banner_text_defaultStandardtexte des Banners
    page_text_overridesArray Seiten-ID zu Override-Text
    privacy_link_source,imprint_link_sourcelocal_page/manual_url/network_global bzw. disabled/manual_url/network_global
    button_accept_all,button_necessary_only,button_save_selection,button_customize,manage_button_labelAlle Button-Beschriftungen einzeln konfigurierbar

    Netzwerkweite Datenschutz-/Impressum-URLs liegen separat in der Netzwerk-Option weinhold_cookie_consent_network_links.

    Besonderheiten

    Abwärtskompatibilität beim Impressum: War imprint_link_source früher auf disabled gespeichert, aber inzwischen ist eine netzwerkweite Impressum-URL hinterlegt, wird beim Auslesen automatisch auf network_global umgestellt – ältere Installationen zeigen das Impressum dann ohne manuelles Nachpflegen an.

    Cleanup ist zweistufig: weinhold_cookie_consent_cleanup() löscht nur die Einstellungen der aktuellen Site, weinhold_cookie_consent_network_cleanup() räumt zusätzlich die Netzwerk-Links auf UND löscht die Site-Einstellungen aller Subsites im Netzwerk einzeln.

    Der Banner wird nie im Admin-Bereich oder bei AJAX-Requests ausgegeben (eigene Prüfung in Enqueue- und Render-Funktion) – verhindert, dass er versehentlich im WordPress-Backend oder in AJAX-Antworten auftaucht.

    Versionshistorie

    VersionDatumÄnderung
    1.0.022.09.2026Einführung der Versionierung.


  • custom-footer


    Custom Footer


    Das Custom-Footer-Modul funktioniert genauso wie der Custom Header – nur für den unteren Bereich der Seite. Den Footer, den du gerade auf weinify.de siehst, wurde mit diesem Modul gestaltet.

    Allgemein

    Buttons & Drag and Drop


    Buttons werden über den Platzhalter –buttons– in den Footer-Inhalt eingefügt und können per Drag & Drop sortiert werden. Sub-Buttons für verschachtelte Menüs sind ebenfalls möglich, öffnen im Footer aber nach oben statt nach unten. Pro Button lässt sich die Sichtbarkeit festlegen: immer, nur für eingeloggte oder nur für ausgeloggte Besucher.

    Freies HTML


    Der Footer-Inhalt kann beliebiges HTML enthalten – Texte, Links, Icons, Copyright-Hinweise oder ganze Layout-Strukturen.

    Pro Site, kein Shortcode


    Wie beim Header ist jede Subsite vollständig unabhängig konfiguriert. Der Footer wird automatisch auf allen Seiten der Subsite ausgegeben, sobald er im Dashboard konfiguriert und aktiviert wurde – ohne Shortcode.

    Dateien

    modules/custom_footer.php – dünner Modul-Stub (Init, Admin-Seite, Cleanup), delegiert die komplette Logik an das gemeinsam mit Custom Header genutzte includes/weinhold_custom_layout_helpers.php.

    Für Entwickler

    Gemeinsamer Unterbau mit Custom Header


    Header und Footer sind keine zwei getrennten Implementierungen, sondern dieselbe Logik in includes/weinhold_custom_layout_helpers.php, parametrisiert über $layout (‚header‘ oder ‚footer‘). Für den Footer liefert weinhold_custom_layout_get_config(‚footer‘) entsprechend den Hook wp_footer, öffnende Sub-Menüs nach oben statt unten, und keinen –auth—Platzhalter (der ist dem Header vorbehalten).

    Speicherung (Optionen pro Site)


    OptionInhalt
    weinhold_custom_footer_enabledOb der Footer aktiv ausgegeben wird
    weinhold_custom_footer_htmlDer HTML-Inhalt mit dem Platzhalter –buttons–
    weinhold_custom_footer_linksArray der Buttons (Beschriftung, Ziel-URL, übergeordneter Button für Sub-Buttons, Sichtbarkeit)

    Wichtige Funktionen


    FunktionBeschreibung
    weinhold_custom_layout_init($layout)Hängt den Render-Callback an wp_footer, baut das Button-HTML inkl. Sub-Buttons zusammen
    weinhold_custom_layout_resolve_link_url($value)Löst Spezial-Tokens in Button-Zielen auf
    weinhold_custom_layout_sanitize_html($html)Bereinigt gespeichertes HTML über eine eigene, erweiterte Erlaubnisliste (weinhold_custom_layout_allowed_html())
    weinhold_custom_layout_get_button_visibility_class($link)Übersetzt die Sichtbarkeitseinstellung eines Buttons in die CSS-Klasse weinhold-show-on-login bzw. weinhold-show-on-logout

    Ausführlichere Details zum gemeinsamen Unterbau (inkl. Rückwärtskompatibilität älterer Buttons) siehe der Custom-Header-Beitrag.

    Besonderheiten

    Wird auf Auth-Seiten (Login, Registrierung, Profil, Passwort-vergessen) automatisch unterdrückt – weinhold_user_management_is_auth_page() prüft das vor jeder Ausgabe.

    Freies HTML ohne Whitelisting von Grund auf – erlaubt sind bewusst mehr Tags/Attribute als WordPress‘ Standard-Editor zulässt, damit auch komplexere Layout-Strukturen im Footer möglich sind.

    Sub-Button-Menüs öffnen im Footer nach oben (statt wie im Header nach unten) – rein visuell, damit das Dropdown nicht aus dem sichtbaren Bereich am unteren Seitenrand herausragt.

    Versionshistorie

    VersionDatumÄnderung
    1.0.022.09.2026Einführung der Versionierung.


  • custom-header


    Custom Header


    Das Custom-Header-Modul ermöglicht die Erstellung eines vollwertigen Headers mit Navigationsbuttons und frei definierbarem HTML – komplett über das Admin-Dashboard, ohne Theme-Anpassungen. Den Header, den du gerade auf weinify.de siehst, wurde mit diesem Modul gebaut.

    Allgemein

    Buttons & Drag and Drop


    Buttons werden über den Platzhalter –buttons– an einer beliebigen Stelle im Header-Inhalt eingefügt. Die Reihenfolge lässt sich per Drag & Drop anpassen. Buttons können Sub-Buttons enthalten, die beim Hover ein Dropdown-Menü öffnen. Pro Button lässt sich außerdem die Sichtbarkeit festlegen: immer, nur für eingeloggte oder nur für ausgeloggte Besucher.

    Login-Navigation per Platzhalter


    Zusätzlich zu –buttons– gibt es den Platzhalter –auth–, der an dieser Stelle die Login/Profil-Navigation des Benutzerverwaltung-Moduls einfügt (identisch zum Shortcode weinhold_auth_nav). Nur im Header verfügbar, nicht im Footer.

    Pro Site, kein Shortcode


    Jede Subsite konfiguriert ihren eigenen Header unabhängig. Inhalt, Buttons und Styling sind vollständig voneinander getrennt – dkj.weinify.de kann einen völlig anderen Header haben als weinify.de. Der Header wird automatisch in jede Seite der jeweiligen Subsite eingebunden, sobald er im Dashboard konfiguriert und aktiviert wurde. Kein Shortcode nötig.

    Social-Vorschau


    Unter den Header-Einstellungen gibt es einen eigenen Abschnitt „Social-Vorschau“. Er legt fest, welches Bild, welchen Titel und welche Beschreibung Discord, WhatsApp, Signal & Co. anzeigen, wenn ein Link zur Subsite geteilt wird (Open Graph und Twitter Card im Seitenkopf). Das Bild wird aus der Mediathek gewählt, empfohlen sind 1200 × 630 Pixel. Unterseiten verwenden ihren eigenen Titel, ein gesetztes Beitragsbild und einen bewusst geschriebenen Auszug. Ohne eigene Angaben greifen Titel, Untertitel und Website-Icon der Subsite. Optional wird die Beschreibung zusätzlich als Meta-Beschreibung für Suchmaschinen ausgegeben.

    Dateien

    modules/custom_header.php – Modul-Datei (Init, Admin-Seite, Cleanup) und die komplette Social-Vorschau (nur Header). Die Header-Ausgabe selbst delegiert sie an das gemeinsam mit Custom Footer genutzte includes/weinhold_custom_layout_helpers.php.

    Für Entwickler

    Gemeinsamer Unterbau mit Custom Footer


    Header und Footer sind keine zwei getrennten Implementierungen, sondern dieselbe Logik in includes/weinhold_custom_layout_helpers.php, parametrisiert über $layout (‚header‘ oder ‚footer‘). weinhold_custom_layout_get_config($layout) liefert dazu Hook-Name (wp_head bzw. wp_footer), HTML-Tag, ob der –auth—Platzhalter unterstützt wird (nur Header) und die Öffnungsrichtung der Sub-Button-Menüs.

    Speicherung (Optionen pro Site)


    OptionInhalt
    weinhold_custom_header_enabledOb der Header aktiv ausgegeben wird
    weinhold_custom_header_htmlDer HTML-Inhalt mit den Platzhaltern –buttons– / –auth–
    weinhold_custom_header_linksArray der Buttons (Beschriftung, Ziel-URL, übergeordneter Button für Sub-Buttons, Sichtbarkeit)
    weinhold_custom_header_social_settingsSocial-Vorschau: enabled, image_id, title, description, prefer_featured, output_description

    Beim Footer entsprechend mit dem Präfix weinhold_custom_footer_* (ohne Social-Vorschau).

    Wichtige Funktionen


    FunktionBeschreibung
    weinhold_custom_layout_init($layout)Hängt den Render-Callback an wp_head bzw. wp_footer, baut das Button-HTML inkl. Sub-Buttons zusammen
    weinhold_custom_layout_resolve_link_url($value)Löst Spezial-Tokens in Button-Zielen auf (z. B. Links auf Auth-Seiten)
    weinhold_custom_layout_sanitize_html($html)Bereinigt gespeichertes HTML über eine eigene, erweiterte Erlaubnisliste (weinhold_custom_layout_allowed_html())
    weinhold_custom_layout_get_button_visibility_class($link)Übersetzt die Sichtbarkeitseinstellung eines Buttons in die CSS-Klasse weinhold-show-on-login bzw. weinhold-show-on-logout
    weinhold_custom_header_render_social_preview()Gibt die Open-Graph- und Twitter-Card-Angaben an wp_head (Priorität 5) aus
    weinhold_custom_header_social_get_meta($settings)Ermittelt Titel, Beschreibung, URL und Typ der aktuellen Seite
    weinhold_custom_header_social_get_image($settings)Wählt Beitragsbild, Standardbild oder Website-Icon samt Größe

    Die Sichtbarkeitsklassen greifen auf dieselbe CSS-Logik zurück, die auch die Shortcodes weinhold_show_on_login/weinhold_show_on_logout des Benutzerverwaltung-Moduls nutzen (weinhold_user_management_render_visibility_css()).

    Besonderheiten

    Wird auf Auth-Seiten (Login, Registrierung, Profil, Passwort-vergessen) automatisch unterdrückt – weinhold_user_management_is_auth_page() prüft das vor jeder Ausgabe, damit der eigene Header/Footer die dortigen Formulare nicht stört.

    Rückwärtskompatibel gespeicherte Buttons: ältere Buttons ohne das neue visibility-Feld werden über das frühere boolesche Feld login_only interpretiert, statt beim Update verloren zu gehen.

    Freies HTML ohne Whitelisting von Grund auf – erlaubt sind bewusst mehr Tags/Attribute als WordPress‘ Standard-Editor zulässt (eigene erweiterte Erlaubnisliste), damit auch komplexere Layout-Strukturen im Header/Footer möglich sind.

    Die Social-Vorschau hat einen eigenen Schalter (standardmäßig aus) und wirkt unabhängig davon, ob der Header angezeigt wird, auch auf Auth-Seiten. Ist ein SEO-Plugin aktiv (Yoast, Rank Math, AIOSEO, SEOPress, The SEO Framework), gibt sie nichts aus, damit keine doppelten Angaben entstehen. Die Beschreibung von Unterseiten stammt nur aus einem gesetzten Auszug, nie aus dem gekürzten Inhalt, weil der Shortcodes oder geschützte Texte enthalten kann.

    Versionshistorie

    VersionDatumÄnderung
    1.0.128.10.2026Social-Vorschau (Open Graph, Twitter Card) mit Bild aus der Mediathek, Titel und Beschreibung.
    1.0.022.09.2026Einführung der Versionierung.


  • email-versand


    E-Mail Versand


    Das E-Mail-Versand-Modul konfiguriert den SMTP-Versand für das gesamte Netzwerk. Alle ausgehenden E-Mails des Weinhold Frameworks – von Kalender-Erinnerungen bis zu Passwort-Reset-Mails – laufen über diese eine zentrale Konfiguration.

    Allgemein

    Konfiguration


    SMTP-Server, Port, Verschlüsselung (TLS/SSL/keine), Benutzername und Passwort werden einmalig unter Weinhold → E-Mail Versand für das gesamte Netzwerk eingetragen. Einzelne Subsites können optional einen abweichenden Absendernamen und eine eigene Absenderadresse festlegen, sofern das netzwerkweit erlaubt ist. Ist kein SMTP konfiguriert, greift automatisch der lokale Mailserver über WordPress‘ Standard-wp_mail().

    E-Mail-Templates


    Andere Module können eigene E-Mail-Templates registrieren, die im Dashboard unter Weinhold → E-Mail Versand → Templates mit individuellem Betreff und Nachrichtentext angepasst werden können – netzwerkweit und zusätzlich pro Subsite überschreibbar. Aktuell nutzen u. a. Gerätesicherheit, Security Manager und Bastard des Monats dieses System für ihre Benachrichtigungs-Mails.

    In der Praxis


    Auf weinify.de läuft der gesamte transaktionale E-Mail-Versand – Passwort zurücksetzen, Kalender-Erinnerungen, Modul-Benachrichtigungen – über dieses Modul. Kein Plugin-Wirrwarr, eine zentrale Stelle.

    Dateien

    modules/email_delivery.php – einzige Datei des Moduls: SMTP-Konfiguration, Passwort-Verschlüsselung, Absender-Filter, komplettes E-Mail-Template-System, Admin-Oberflächen (Netzwerk + Site), Cleanup.

    Für Entwickler

    Ein eigenes Template registrieren


    Beim eigenen Modul-Init über den Filter weinhold_email_templates einen Eintrag mit label, module, description, default_subject, default_body und variables registrieren. Immer verfügbare Platzhalter in jedem Template: {site}, {datetime}, {manage_url} – zusätzlich die selbst in variables gelisteten. Versand dann über weinhold_send_module_mail($template_id, $to, $context, $site_id) statt direktem wp_mail().

    Auflösungsreihenfolge


    Sowohl Absender als auch Betreff/Text eines Templates werden in der Reihenfolge Site-Override → Netzwerk-Anpassung → Modul-Default aufgelöst (weinhold_email_get_resolved_template()). Templates lassen sich netzwerkweit deaktivieren, dann sendet weinhold_send_module_mail() gar nicht erst.

    SMTP-Erkennung & Passwortschutz


    weinhold_email_delivery_should_use_smtp() nutzt SMTP nicht nur, wenn die Checkbox aktiv ist, sondern auch dann, wenn ein SMTP-Host UND Zugangsdaten/Auth gesetzt sind – schützt gegen ein versehentlich deaktiviertes SMTP bei sonst vollständig ausgefüllter Konfiguration. Das SMTP-Passwort wird nie im Klartext gespeichert, sondern mit AES-256-CBC verschlüsselt (Schlüssel aus dem WordPress-AUTH_KEY bzw. -Salt abgeleitet); alte Klartext-Werte werden beim Lesen automatisch erkannt und weiterhin akzeptiert (Migrationsfall).

    Wichtige Funktionen


    FunktionBeschreibung
    weinhold_send_module_mail($template_id,$to,$context,$site_id)Zentraler Versand für Modul-E-Mails über das Template-System
    weinhold_email_get_resolved_template($template_id,$site_id)Löst Betreff/Text/Absender eines Templates auf
    weinhold_email_delivery_get_effective_settings()Liefert die tatsächlich wirksamen SMTP-/Absender-Einstellungen (inkl. Subsite-Override)
    weinhold_email_delivery_send_test_mail($to,$scope)Versendet eine Test-Mail und fängt Fehler zur Anzeige im Dashboard ab

    Besonderheiten

    Absender-Override gilt nur temporär pro Mail: weinhold_send_module_mail() hängt bei abweichendem Template-Absender kurzzeitig eigene wp_mail_from/wp_mail_from_name-Filter ein und entfernt sie sofort nach dem Versand wieder – andere, zeitgleich versendete E-Mails bleiben unberührt.

    Test-Ergebnisse werden als Transient gespeichert (24 Stunden), nicht dauerhaft in Optionen – nach dem Testen im Dashboard bleibt das Ergebnis eine Weile sichtbar, verschwindet danach automatisch von selbst.

    Fällt die Verschlüsselung aus irgendeinem Grund aus (z. B. openssl-Erweiterung fehlt), wird das Passwort unverschlüsselt gespeichert statt den Vorgang abzubrechen – bewusste Entscheidung gegen Datenverlust, auf Kosten geringerer Sicherheit in diesem Randfall.

    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.


  • kalender


    Kalender


    Das Kalender-Modul bringt einen netzwerkweiten Terminplaner ins Weinhold Framework. Termine werden zentral gespeichert und können von eingeloggten Nutzern erstellt, bearbeitet und geteilt werden – optional auch öffentlich für alle Besucher. Auf weinify.de/kalender ist das Modul live im Einsatz.

    Allgemein

    Sichtbarkeit von Terminen


    Beim Erstellen wählt man zwischen drei Stufen: Netzwerk (alle eingeloggten Nutzer können den Termin sehen), Privat (nur Ersteller und eingeladene Nutzer haben Zugriff) und Öffentlich (jeder kann den Termin sehen, auch ohne Login – erfordert eine eigene, separat vergebene Berechtigung). Jeder Termin kann außerdem einen optionalen externen Link tragen.

    E-Mail-Erinnerungen


    Pro Termin kann eine E-Mail-Erinnerung aktiviert werden. In den persönlichen Einstellungen legt jeder Nutzer fest, wie viele Tage vorher die Erinnerung gesendet werden soll (0 = am selben Tag, -1 = deaktiviert). Der Versand läuft täglich automatisch per Cronjob, wahlweise über WP-Cron oder einen externen Server-Cron (Einstellung pro Modul, wie im gesamten Framework üblich).

    Farbkodierung & Herkunft


    Jeder Nutzer kann pro Webseite eine eigene Farbe für die Terminanzeige konfigurieren. Bei der Termin-Erstellung wird außerdem die Herkunft (welche Subsite) zugeordnet – so behalten Mitglieder mehrerer Sites den Überblick.

    Navigation


    Ein Kalender-Link wird automatisch in die Navigation des Benutzerverwaltung-Moduls (weinhold_auth_nav) eingehängt.

    Shortcodes

    ShortcodeBeschreibung
    weinhold_calendarPersönlicher Kalender (nur eingeloggte Nutzer): zeigt alle Termine netzwerkweit, die der Nutzer sehen darf. Beim Aktivieren des Moduls wird automatisch eine Seite unter /kalender mit diesem Shortcode erstellt
    weinhold_public_calendarÖffentlicher Kalender der aktuellen Webseite: nicht eingeloggte Besucher sehen nur öffentliche Termine, eingeloggte Nutzer alle Termine dieser Webseite

    Dateien

    modules/calendar.php – einzige Datei des Moduls: Datenbank inkl. versionierter Migrationen, Termin-/Farbverwaltung, Erinnerungs-Cronjob, Frontend-Formularverarbeitung, beide Shortcodes, Admin-Seite, Cleanup.

    Für Entwickler

    Datenbank


    TabelleSpalten(Auswahl)
    weinhold_calendar_eventssite_id, creator_user_id, caption, description, event_link, visibility(0 Netzwerk/1 Privat/2 Öffentlich), event_dt_gmt
    weinhold_calendar_event_usersevent_id, user_id, wants_reminder, reminder_sent_at_gmt
    weinhold_calendar_user_settingsuser_id, reminder_days
    weinhold_calendar_site_colorsuser_id, site_id, color

    Versionierte Migration bis DB-Version 3: v2 auf v3 benennt is_private in visibility um (aus bool wird dreiwertig), fügt event_link hinzu und wants_reminder in der Teilnehmer-Tabelle.

    Eigene Berechtigung für öffentliche Termine


    Über den Filter weinhold_registered_capabilities registriert das Modul die zusätzliche Capability weinhold_calendar_create_public_event – eine eigene, feinere Berechtigung oberhalb der normalen Modul-Edit-Rechte, weil ein öffentlicher Termin auch ohne Login sichtbar ist und damit sensibler ist als ein normaler Netzwerk-Termin.

    E-Mail-Template & Cron


    Registriert das Template calendar_reminder beim E-Mail-Versand-Modul (Platzhalter display_name, count, when, events) und nutzt es über weinhold_send_module_mail() für den täglichen Erinnerungsversand. Der tägliche Cron-Job wird ausschließlich auf der Hauptsite eingerichtet (Modul-Scope: network) und respektiert den zentralen Cron-Modus-Schalter (weinhold_cron_mode_is_extern(‚calendar‘)) – bei externem Cron übernimmt WP-Cron das Scheduling nicht selbst.

    Besonderheiten

    Trotz Modul-Scope network sind Termine site_id-getaggt und Farben pro Nutzer UND Site konfigurierbar – „netzwerkweit“ bedeutet hier, dass ein Nutzer die Termine ALLER Sites in einem gemeinsamen persönlichen Kalender sieht, nicht dass es nur einen einzigen, undifferenzierten Termin-Pool ohne Site-Bezug gibt.

    Die Migration von is_private (boolesch) zu visibility (dreiwertig) zeigt, dass „Öffentlich“ nachträglich als dritte Sichtbarkeitsstufe hinzugefügt wurde – ältere, per Datenbank-Upgrade migrierte Installationen haben dieselbe Spalte nur unter neuem Namen und mit erweitertem Wertebereich.

    Die Berechtigung für öffentliche Termine läuft über eine eigene Capability statt über das generische Modul-Edit-Recht – wer Termine bearbeiten darf, darf noch lange keine öffentlichen, nicht-login-pflichtigen Termine erstellen.

    Versionshistorie

    VersionDatumÄnderung
    1.0.022.09.2026Einführung der Versionierung.