📖 Spamfaktor: Erklärung, Anwendung und Bedeutung

Der Spamfaktor ist eine Kennzahl zwischen 0,0 und 1,0, mit der erkannt wird, wie wahrscheinlich ein Beitrag Spam oder schädliche Inhalte enthält. Das System basiert auf der OpenAI‑Moderations‑API, die Texte und Bilder auf problematische Kategorien wie sexuelle Inhalte, Belästigung, Hass, illegale Inhalte, Selbstverletzung und Gewalt untersuchtcookbook.openai.com. Solche Kategorien werden automatisch erkannt, um Spam und irreführende Inhalte zu filterncookbook.openai.com.

Zur Einordnung nutzt das Projekt folgende Skala:

Spamfaktor Bedeutung
0,00 – 0,20 Sehr wahrscheinlich legitimer Beitrag (kein Spam).
0,21 – 0,50 Leicht auffällig – vermutlich harmlose Werbung.
0,51 – 0,80 Deutlicher Verdacht auf Spam oder irreführende Inhalte.
0,81 – 1,00 Offensichtlicher Spam oder schädlicher Inhalt – Beitrag wird geblockt.

Die Wahl eines Schwellenwerts (z. B. 0,80) ist ein Abwägungsprozess zwischen Falsch‑Positiven (legitime Inhalte werden fälschlich blockiert) und Falsch‑Negativen (problematische Inhalte rutschen durch). Die OpenAI‑Dokumentation weist darauf hin, dass solche Schwellenwerte an die gewünschte Toleranz angepasst werden solltencookbook.openai.com. In diesem Projekt gilt: Liegt der Spamfaktor über 0,50, wird der Beitrag automatisch in den Entwurfsstatus versetzt, um Missbrauch zu verhindern.

✨ Anwendung des Shortcodes

Der Shortcode prüft einen oder mehrere Beiträge und speichert den ermittelten Spamfaktor im Metafeld spam. Je nach Parameter verändert sich das Verhalten:

  • Letzter Beitrag des aktuellen Nutzers (Standard):

    [sdg_spam_check use_openai="1"]

     

    • PrĂĽft den zuletzt erstellten commitment-Beitrag des eingeloggten Nutzers.

    • Wird der Spamfaktor ≤ 0,50, zeigt der Shortcode nach der PrĂĽfung die positive Meldung
      „Deine Celebration wurde überprüft und ist jetzt auf der Celebration Map sichtbar“.

    • Ist der Spamfaktor > 0,50, wird der Beitrag als Entwurf gespeichert und die negative Meldung
      „Vielen Dank für deinen Beitrag. Wir werden ihn prüfen und dann freischalten.“ ausgegeben.

  • Bestimmten Beitrag prĂĽfen (z. B. Post‑ID 445):

    [sdg_spam_check post_id="445" use_openai="1"]

     

    • PrĂĽft nur diesen Beitrag und aktualisiert sein Metafeld spam.

    • Liegt der Spamfaktor ĂĽber dem Schwellenwert, wird der Beitrag automatisch auf draft gesetzt.

  • Alle Beiträge prĂĽfen (nur Beiträge, die der Nutzer bearbeiten darf):

    [sdg_spam_check post_id="all" use_openai="1"]

     

    • PrĂĽft alle commitment‑Beiträge, aktualisiert die Spamfaktoren und setzt Beiträge mit zu hohem Wert auf draft.

    • Gibt eine zusammenfassende RĂĽckmeldung aus („Spam check completed on N post(s).“).

Nach der Prüfung wird der Spamfaktor in der Administrationsliste in einer eigenen Spalte angezeigt. Somit können Administratoren auf einen Blick erkennen, welche Beiträge unbedenklich sind und welche in den Entwurfsmodus versetzt wurden.

Zweck des Codes

Der Shortcode sdg_spam_check prüft einen oder mehrere „Feiern“-Beiträge (Post-Typ commitment) automatisiert auf Spam oder problematische Inhalte.
Je nach Ergebnis:

  • wird ein Spam-Score im Beitrag gespeichert,
  • der Beitrag ggf. auf Entwurf (draft) gesetzt,
  • und dem Nutzer eine RĂĽckmeldung in seiner Sprache angezeigt.

Optional kann dafĂĽr die OpenAI-API genutzt werden.


1. Wie der Shortcode aufgerufen wird

Grundform:

sdg_spam_check post_id="" use_openai="1"]

Attribute:

  • post_id
    • "" (leer oder ungĂĽltig) → der letzte Beitrag des eingeloggten Nutzers wird geprĂĽft (nur wenn URL ?a=create oder ?a=update enthält).
    • "all" → alle commitment-Beiträge, die der eingeloggte Nutzer bearbeiten darf, werden geprĂĽft.
    • eine Zahl (z.B. "123") → genau dieser Beitrag wird geprĂĽft (wenn Typ commitment und der Nutzer Bearbeitungsrechte hat).
  • use_openai
    • "1" → OpenAI-Moderation wird benutzt (falls API-Key vorhanden).
    • "0" → es wird nur ein Spam-Score 0.0 gesetzt (kein API-Call).

2. Steuerung ĂĽber URL-Parameter a

Für den Standardfall „neuer oder geänderter Beitrag des aktuellen Users“ (leerer post_id) wird zusätzlich der URL-Parameter a ausgewertet, z.B.:

  • ?a=create → neu angelegter Beitrag
  • ?a=update → aktualisierter Beitrag

Nur wenn a genau "create" oder "update" ist, wird:

  • ĂĽberhaupt eine SpamprĂĽfung fĂĽr den letzten Beitrag des Nutzers durchgefĂĽhrt,
  • und eine RĂĽckmeldung (positiv/negativ) ausgegeben.

Fehlt der Parameter oder hat er einen anderen Wert, gibt der Shortcode gar nichts aus.


3. Spracherkennung und Ăśbersetzungen

Die RĂĽckmeldungen an den Nutzer werden mehrsprachig ausgegeben.

  1. Es wird die Sprache des Besuchers ermittelt:
    • bevorzugt mit determine_locale(),
    • sonst mit get_locale().
  2. Aus dem Locale werden die ersten zwei Buchstaben verwendet, z.B.:
    • de_DE → de
    • en_US → en
  3. FĂĽr diese SprachkĂĽrzel sind Texte hinterlegt:
    aktuell en, de, sq, es, fr, pt, zh, ko, hi, ru, ar.

Zwei Nachrichtentypen:

  • positive_msg (wenn kein Spam):
    „Deine Feier wurde geprüft und ist jetzt auf der Feier-Karte sichtbar.“ (bzw. Übersetzung)
  • negative_msg (wenn Spam):
    „Vielen Dank für deine Einreichung. Wir werden sie prüfen und anschließend veröffentlichen.“ (bzw. Übersetzung)

Kann die gewählte Sprache nicht gefunden werden, fällt der Code auf Englisch zurück.


4. Welche Beiträge werden tatsächlich geprüft?

Je nach post_id:

  1. post_id="all"
    • Es werden alle Beiträge vom Typ commitment geladen (alle Status: publish, pending, draft, future, private).
    • Nur Beiträge, die der eingeloggte Nutzer bearbeiten darf, kommen in die PrĂĽfliste.
  2. post_id="" oder nicht numerisch
    • Es wird der aktuell eingeloggte User geprĂĽft:
      • Falls keiner eingeloggt ist → Ausgabe: Please log in.
    • Es wird der neueste commitment-Beitrag dieses Nutzers gesucht (alle Status).
    • Nur wenn die URL ?a=create oder ?a=update enthält:
      • wird dieser letzte Beitrag geprĂĽft
      • und eine nutzerfreundliche Meldung ausgegeben.
    • Gibt es keinen Beitrag → Ausgabe: No post found for current user.
  3. post_id="123" (numerisch)
    • Wenn der Beitrag vom Typ commitment ist und der Nutzer Bearbeitungsrechte hat:
      • wird genau dieser Beitrag geprĂĽft.
    • Sonst Ausgabe: Invalid post ID or insufficient permissions.

Wenn am Ende keine Beiträge in der Prüfliste sind, kommt: No posts to check.


5. Wie die Spam-Prüfung technisch abläuft

FĂĽr jeden zu prĂĽfenden Beitrag ($pid) wird:

  1. Ein Spam-Faktor initial auf 0.0 gesetzt.
  2. Nur wenn:
    • use_openai="1" gesetzt ist
    • und die Konstante OPENAI_API_KEY definiert ist,

    wird eine Anfrage an die OpenAI Chat Completions API gesendet.

5.1 Welche Daten an OpenAI gesendet werden?

  • Alle Post-Meta-Felder des Beitrags werden durchlaufen.
  • Nicht gesendet werden:
    • Meta-Keys, die mit _ beginnen (technische Felder),
    • first_name,
    • last_name,
    • spam.
  • Leere Werte werden ĂĽbersprungen.
  • Arrays werden JSON-kodiert, sonst werden Strings verwendet.
  • Der Key image_for_the_event wird speziell behandelt:
    • Falls numerisch → wird die URL des Anhangs ermittelt.
    • Falls schon URL → wird diese ĂĽbernommen.
    • Diese Bild-URL wird dem Text an OpenAI hinzugefĂĽgt.

Alle Daten werden als Textliste im User-Prompt an OpenAI gesendet:
Feldname: Wert

5.2 OpenAI-Prompt und Antwort

  • Systemrolle: „content safety analyst“, der auf Basis der Daten einen Spam-Faktor von 0.0 bis 1.0 zurĂĽckgibt.
  • Antwortformat: reines JSON mit einem Feld spam_factor, z.B.:
    { "spam_factor": 0.27 }
    
  • Die Antwort wird geparst; der Wert wird auf den Bereich 0.0–1.0 begrenzt.

Wenn die API nicht erreichbar ist oder kein gĂĽltiges JSON zurĂĽckkommt, bleibt der Spam-Faktor bei 0.0.

5.3 Speicherung & Schwellenwert

  • Der berechnete spam_factor wird als Post-Meta spam gespeichert.
  • Es gibt einen Schwellenwert $threshold = 0.5.
  • Wenn spam_factor >= 0.5:
    • wird der Beitrag automatisch auf Status draft gesetzt
      (wp_update_post).

6. Was der Shortcode im Frontend ausgibt

Am Ende hängt die Ausgabe davon ab, wie viele Beiträge geprüft wurden und in welchem Modus:

  1. Standardfall „letzter Beitrag des Nutzers“ (ein Beitrag, a=create|update)
    • Wenn spam_factor >= 0.5 → „negative“ Meldung in Sprache des Nutzers
      (z.B. „Vielen Dank für deine Einreichung. Wir werden sie prüfen und anschließend veröffentlichen.“)
    • Wenn spam_factor < 0.5 → „positive“ Meldung
      (z.B. „Deine Feier wurde geprüft und ist jetzt auf der Feier-Karte sichtbar.“)
  2. Mehrere Beiträge (z.B. post_id="all") oder gezielte ID
    • Es wird keine Einzelmeldung pro Beitrag ausgegeben.
    • Stattdessen: eine neutrale Zusammenfassung:
      <p>Spam check completed on X post(s).</p>
      
  3. Kein passender Post / keine Rechte / nicht eingeloggt
    • Entsprechende Fehlermeldung im Klartext:
      • Please log in.
      • No post found for current user.
      • Invalid post ID or insufficient permissions.
      • No posts to check.

7. Typische Anwendungsfälle (Beispiele)

  • Nach dem Absenden eines Formulars (neuer Eintrag):
    sdg_spam_check use_openai="1"]
    

    Wird auf einer Seite verwendet, die mit ?a=create oder ?a=update aufgerufen wird.
    → Prüft den zuletzt erstellten/aktualisierten Beitrag des eingeloggten Nutzers und zeigt eine passende Rückmeldung.

  • Admin- / Moderator-Check fĂĽr alle eigenen Feiern:
    sdg_spam_check post_id="all" use_openai="1"]
    

    → Prüft alle eigenen commitment-Beiträge und setzt ggf. Spam-Beiträge auf draft. Ausgabe: „Spam check completed on X post(s).“

  • Gezielter Check eines einzelnen Beitrags (z.B. im Backend-Dashboard):
    sdg_spam_check post_id="123" use_openai="1"]
    

 

 

Leere Arrays bereinigen

Der Code behebt einen konkreten technischen Fehler in Beiträgen (Post-Typ z.B. commitment):

  • In vier bestimmten Feldern (date_of_our_event, time_of_the_event, website_of_the_event, details_about_the_events) landet manchmal der Wert a:0:{} bzw. ein leeres Array.

  • Das ist ein technischer Sonderfall (leeres, serialisiertes Array), mit dem andere Funktionen (z.B. Datumsverarbeitung) nicht klarkommen und Fehler werfen können.

  • Der Code sucht diese „kaputten“ Werte und ersetzt sie durch leere Strings ('').
    Praktisch bedeutet das: „kein Wert gesetzt“ statt „defekter Wert“.

Es gibt dafĂĽr:

  1. eine Hilfsfunktion: sdg_fix_empty_array_metas()

  2. einen Shortcode, um nur den letzten Beitrag zu reparieren:
    [sdg_fix_latest_meta ...]

  3. einen Shortcode, um alle passenden Beiträge in einem Rutsch zu reparieren:
    [sdg_fix_all_meta ...]


1. Hilfsfunktion: sdg_fix_empty_array_metas($post_id, $keys)

Was sie tut:

  • Nimmt eine Beitrags-ID ($post_id) und eine Liste von Feldnamen ($keys).

  • FĂĽr jedes dieser Felder:

    1. Liest den Rohwert aus der Datenbank.

    2. Wenn es gar keinen Wert gibt (leer oder null), passiert nichts.

    3. PrĂĽft, ob der Wert

      • genau a:0:{} ist (klassische WordPress-Serialisierung eines leeren Arrays)
        oder

      • sich nach dem Entserialisieren (maybe_unserialize) als leeres Array herausstellt.

    4. Falls ja, wird der Wert im Beitrag auf '' (leerer String) gesetzt – technisch das „Null-Äquivalent“ für ein Meta-Feld in WordPress.

    5. Der Name des Feldes wird in eine Liste der „reparierten“ Felder aufgenommen.

  • Am Ende gibt die Funktion ein Array der bereinigten Feldnamen zurĂĽck.
    (z.B. ['date_of_our_event', 'time_of_the_event'])

FĂĽr Externe:
Diese Funktion ist die eigentliche „Reparatur-Logik“. Die Shortcodes rufen sie nur mit unterschiedlichen Beitragslisten auf.


2. Shortcode 1: Letzten Beitrag prĂĽfen/fixen

Shortcode:

[sdg_fix_latest_meta post_type="commitment" scope="user|global"]

Parameter:

  • post_type

    • z.B. "commitment" oder "any"

    • Steuert, welcher Beitragstyp betrachtet wird.

  • scope

    • "user" (Standard): Es wird der letzte Beitrag des aktuell eingeloggten Nutzers gesucht.

    • "global": Es wird der letzte Beitrag insgesamt (unabhängig vom Autor) gesucht.

Ablauf:

  1. Der Shortcode definiert zunächst die vier betroffenen Meta-Felder:

    • date_of_our_event

    • time_of_the_event

    • website_of_the_event

    • details_about_the_events

  2. Er baut eine Abfrage, um genau einen Beitrag zu finden:

    • neuester Beitrag (orderby=date, DESC)

    • Status: publish, pending, draft, future, private

    • Post-Typ: wie in post_type angegeben (any oder spezifisch)

  3. Bei scope="user":

    • Wird zusätzlich der aktuell eingeloggte Benutzer ermittelt.

    • Falls niemand eingeloggt ist → Ausgabe:
      „Bitte einloggen.“

    • Sonst werden nur Beiträge dieses Nutzers berĂĽcksichtigt.

  4. Wird kein passender Beitrag gefunden → Ausgabe:
    „Kein passender Beitrag gefunden.“

  5. Wird ein Beitrag gefunden:

    • sdg_fix_empty_array_metas() wird fĂĽr genau diesen Beitrag mit den vier SchlĂĽsseln aufgerufen.

    • Gibt es nichts zu reparieren → Ausgabe:
      „Letzter Beitrag (#ID): keine a:0:{}-Felder gefunden.“

    • Gibt es reparierte Felder → Ausgabe:
      „Beitrag #ID bereinigt: feld1, feld2, …“

Typischer Einsatz:

  • Wenn man vermutet, dass beim zuletzt angelegten/aktualisierten Beitrag des eigenen Accounts ein Fehler in den vier Feldern steckt.

  • Man ruft den Shortcode auf einer Admin-/Service-Seite auf und sieht direkt, ob und was korrigiert wurde.


3. Shortcode 2: Alle passenden Beiträge prüfen/fixen

Shortcode:

[sdg_fix_all_meta post_type="commitment" author=""]

Wichtiger Hinweis:
Dieser Shortcode ist nur fĂĽr Nutzer mit ausreichenden Rechten gedacht, z.B. Redakteure oder Administratoren.
Technisch wird geprĂĽft:

  • Nutzer muss eingeloggt sein und

  • current_user_can('delete_posts') muss true sein.

Sonst gibt der Shortcode aus:
„Keine Berechtigung.“

Parameter:

  • post_type

    • "commitment" oder "any"

    • Steuert, welche Beitragstypen durchsucht werden.

  • author

    • "" (leer): alle Autoren werden berĂĽcksichtigt.

    • "current": Nur Beiträge des aktuell eingeloggten Nutzers.

    • numerische ID (z.B. "7"): Nur Beiträge dieses Autors.

Ablauf:

  1. Wieder dieselben vier Meta-Felder wie beim ersten Shortcode:

    • date_of_our_event

    • time_of_the_event

    • website_of_the_event

    • details_about_the_events

  2. Es wird eine Abfrage gebaut, die alle passenden Beiträge lädt:

    • posts_per_page = -1 (also alle)

    • nach Datum sortiert (neueste zuerst)

    • Status: publish, pending, draft, future, private

    • Post-Typ und Autor gemäß den Parametern

  3. Wenn keine passenden Beiträge gefunden werden → Ausgabe:
    „Keine passenden Beiträge gefunden.“

  4. FĂĽr jeden gefundenen Beitrag:

    • sdg_fix_empty_array_metas() wird aufgerufen.

    • Es werden Zähler mitgefĂĽhrt:

      • total: Anzahl der geprĂĽften Beiträge

      • changed: Anzahl der Beiträge, bei denen mindestens ein Feld korrigiert wurde

    • In einem Bericht wird gespeichert, welcher Beitrag welche Felder korrigiert bekam, z.B.:

      • #123 (date_of_our_event, time_of_the_event)

  5. Am Ende wird eine Zusammenfassung ausgegeben, z.B.:

    • „GeprĂĽft: 25 Beitrag/Beiträge. Bereinigt: 7.“

    • Wenn Details vorhanden sind, angehängt:
      „Details: #123 (date_of_our_event) | #456 (time_of_the_event, website_of_the_event) | …“


4. Typische Anwendungsfälle

  • Punktuelle Reparatur eines einzelnen Problems:

    • Mit [sdg_fix_latest_meta post_type="commitment" scope="user"] kann ein Nutzer schnell seinen letzten eigenen Beitrag reparieren (z.B. nach einem Fehler im Formular).

  • Admin-Wartung nach Bugfix:

    • Nachdem klar ist, dass ältere Beiträge durch ein Formular oder Plugin-Fehlverhalten falsche Werte (a:0:{}) enthalten:

      • Ein Administrator nutzt
        [sdg_fix_all_meta post_type="commitment" author=""],
        um alle betroffenen Beiträge einmalig zu prüfen und aufzuräumen.

  • Gezielte Reparatur nach Autor:

    • Z.B. fĂĽr bestimmte Regionen oder Verantwortliche:

      • [sdg_fix_all_meta post_type="commitment" author="current"]
        → nur eigene Beiträge

      • [sdg_fix_all_meta post_type="commitment" author="17"]
        → alle Beiträge von Autor mit ID 17

 

 

Weiterleitung

Dieser Code regelt vier Dinge für die spezielle Nutzerrolle „sdg2033_user“:

  1. Bei Registrierung:

    • Sprache des Nutzers speichern

    • Nutzer automatisch auf die passende „Feier-anlegen“-Seite weiterleiten

    • zusätzlich Schreibrechte (Rolle „author“) geben

  2. Nach Registrierung / erstem Login:

    • Nutzer beim ersten Besuch im Frontend automatisch auf die richtige Eingabeseite in seiner Sprache weiterleiten

  3. Backend-Schutz:

    • „sdg2033_user“-Accounts vom WordPress-Backend fernhalten

    • aber Uploads und AJAX (fĂĽr Formulare etc.) weiterhin erlauben

  4. Admin-Leiste ausblenden:

    • Die schwarze WordPress-Admin-Leiste im Frontend fĂĽr diese Nutzer ausblenden

Damit entsteht fĂĽr Teilnehmende eine klare, gefĂĽhrte Frontend-Erfahrung, ohne dass sie mit dem WordPress-Backend in BerĂĽhrung kommen.


1. Registrierung: Sprache speichern & Redirect-Flag setzen

Hook: user_register

Wenn ein neuer Benutzer angelegt wird:

  1. Es wird geprĂĽft, ob der User die Rolle sdg2033_user hat.
    Nur dann greift diese Logik.

  2. Der Nutzer bekommt zusätzlich die Rolle „author“ zugewiesen, falls:

    • er noch nicht „author“ ist oder

    • noch keine Upload-Rechte hat.
      âžś Damit kann er Medien (z.B. Bilder fĂĽr seine Feier) hochladen, ohne ein volles Backend zu sehen.

  3. Sprache des Nutzers ermitteln:

    • Wenn WPML aktiv ist, wird zuerst die aktuelle WPML-Sprache abgefragt.

    • Falls das leer ist, wird die Sprache aus dem System-Locale ermittelt (z.B. de_DE → de).

    • Es werden immer nur die ersten zwei Buchstaben verwendet (z.B. de, en, sq).

  4. Diese Sprache wird in einem User-Meta-Feld gespeichert:

    • sdg2033_lang = Sprachcode (z.B. de, en)

  5. Zusätzlich wird ein Flag gesetzt:

    • sdg2033_needs_redirect = '1'
      âžś Kennzeichnet, dass der Nutzer nach der Registrierung / beim ersten Login automatisch weitergeleitet werden soll.


2. Ziel-URL je nach Sprache bestimmen

Funktion: sdg2033_get_redirect_url_for_user(WP_User $user)

Diese Funktion berechnet, wohin ein Nutzer weitergeleitet werden soll.

  1. Zuerst wird die gespeicherte Sprache sdg2033_lang geladen.

  2. Wenn sie fehlt:

    • wird erneut eine sinnvolle Sprache aus WPML oder den Locale-Einstellungen ermittelt,

    • gespeichert,

    • und auf zwei Zeichen gekĂĽrzt.

  3. Standard-Ziel ist die englische Seite:

    • https://sdg2033.world/commit/

  4. FĂĽr Deutsch gibt es eine feste Zielseite:

    • https://sdg2033.world/de/feier-hinzufuegen/

  5. FĂĽr andere Sprachen mit WPML:

    • Wird die englische Basis-URL https://sdg2033.world/commit/ ĂĽber WPML (wpml_permalink) in die passende Sprach-URL umgewandelt.
      Beispiel: …/es/commit/, …/sq/commit/ etc., je nach Konfiguration.

  6. Falls WPML nicht verfĂĽgbar ist:

    • wird einfach die englische Basis-URL verwendet.

Kurz:
Die Funktion sorgt dafür, dass jede*r sdg2033_user beim ersten Aufruf auf die richtige „Feier hinzufügen“- bzw. „Commit“-Seite in der eigenen Sprache kommt.


3. Redirect nach Registrierung / erstem Login (Frontend)

Hook: template_redirect

Bei jedem Frontend-Aufruf wird geprĂĽft:

  1. Ist der User eingeloggt?
    Wenn nein → nichts tun.

  2. Ist es Backend?
    FĂĽr Backend (is_admin() == true) wird in diesem Hook nichts gemacht.

  3. Der eingeloggte Nutzer wird geladen.
    Wenn:

    • er nicht die Rolle sdg2033_user hat
      oder

    • er Admin-Rechte hat (manage_options)

    âžś keine Umleitung.

  4. Es wird geprĂĽft, ob das Redirect-Flag gesetzt ist:

    • sdg2033_needs_redirect == '1'
      Nur dann erfolgt eine Weiterleitung.

  5. Ist das Flag gesetzt:

    • Ziel-URL wird ĂĽber sdg2033_get_redirect_url_for_user() ermittelt.

    • Flag wird auf 0 gesetzt, damit der Redirect nur einmalig passiert.

    • Der Nutzer wird mit wp_safe_redirect() auf die Zielseite umgeleitet.

Ergebnis:
Direkt nach Registrierung / erstem Login landet ein SDG2033-Nutzer automatisch auf der passenden Feier-Anlegen-Seite in seiner Sprache – aber eben nur einmal, nicht bei jedem Seitenaufruf.


4. Backend-Zugriff blockieren (ohne Uploads zu stören)

Hook: admin_init

Ziel: sdg2033_user sollen nicht ins WordPress-Backend, aber ihre Formulare und Datei-Uploads sollen trotzdem funktionieren.

Die Logik:

  1. Nur bei eingeloggten Usern aktiv.

  2. AJAX-Aufrufe (wp_doing_ajax()) werden durchgelassen
    âžś wichtig fĂĽr Formularfunktionen und technische Prozesse.

  3. Der Spezialfall async-upload.php (Media-Upload) wird ebenfalls nicht blockiert, damit Nutzer Bilder über Frontend-Formulare hochladen können.

  4. Nur wenn is_admin() (also im Backend) wird weiter geprĂĽft.

  5. Der aktuelle User wird geladen.

  6. Wenn:

    • er keine sdg2033_user-Rolle hat
      oder

    • er Admin-Rechte (manage_options) hat

    âžś keine Umleitung (z.B. fĂĽr normale Admins).

  7. FĂĽr SDG-User ohne Admin-Rechte:

    • Ziel-URL wird ĂĽber sdg2033_get_redirect_url_for_user() ermittelt.

    • Der Nutzer wird mit wp_safe_redirect() ins Frontend umgeleitet.

Praxis-Effekt:
Teilnehmende mit sdg2033_user-Accounts können Inhalte einreichen, aber das klassische WordPress-Dashboard bleibt ihnen verborgen. Sie bleiben immer im Frontend-Workflow.


5. Admin-Bar im Frontend ausblenden

Hook: after_setup_theme

Im letzten Schritt wird fĂĽr SDG-User die WordPress-Adminbar im Frontend deaktiviert:

  • Wenn current_user_can('sdg2033_user') erfĂĽllt ist, wird show_admin_bar(false) aufgerufen.

Ziel ist hier vor allem:

  • die Benutzeroberfläche klar und „nicht-technisch“ zu halten,

  • keine verwirrenden Backend-Elemente anzuzeigen.


Zusammenfassung fĂĽr Externe

  • Zielgruppe: Nutzerrolle sdg2033_user (Teilnehmende, die Feiern / Commitments eintragen).

  • Nutzen:

    • Automatische Spracherkennung und Weiterleitung auf die passende Eingabeseite.

    • Klare Trennung:

      • Frontend fĂĽr Teilnehmende

      • Backend nur fĂĽr Admins und Redakteure

    • Keine unnötige Komplexität fĂĽr Endnutzer (kein Dashboard, keine Admin-Leiste).