{"id":4827,"date":"2025-10-22T08:39:43","date_gmt":"2025-10-22T06:39:43","guid":{"rendered":"https:\/\/sdg2033.world\/documentation\/"},"modified":"2025-10-22T08:39:43","modified_gmt":"2025-10-22T06:39:43","slug":"documentation","status":"publish","type":"page","link":"https:\/\/sdg2033.world\/sq\/documentation\/","title":{"rendered":"Documentation"},"content":{"rendered":"<div class=\"et_d4_element et_pb_section et_pb_section_0  et_pb_css_mix_blend_mode et_section_regular et_block_section\" >\n\t\t\t\t\n\t\t\t\t\n\t\t\t\t\n\t\t\t\t\n\t\t\t\t\n\t\t\t\t\n\t\t\t\t<div class=\"et_d4_element et_pb_row et_pb_row_0  et_pb_css_mix_blend_mode et_block_row\">\n\t\t\t\t<div class=\"et_d4_element et_pb_column_4_4 et_pb_column et_pb_column_0  et_pb_css_mix_blend_mode et-last-child et_block_column\">\n\t\t\t\t\n\t\t\t\t\n\t\t\t\t\n\t\t\t\t\n\t\t\t\t<div id=\"spamfaktor\" class=\"et_pb_module et_d4_element et_pb_text et_pb_text_0  et_pb_text_align_left et_pb_bg_layout_light\">\n\t\t\t\t\n\t\t\t\t\n\t\t\t\t\n\t\t\t\t\n\t\t\t\t<div class=\"et_pb_text_inner\"><h2 data-start=\"344\" data-end=\"396\">\ud83d\udcd6 Spamfaktor: Erkl\u00e4rung, Anwendung und Bedeutung<\/h2>\n<p data-start=\"398\" data-end=\"945\">Der <strong data-start=\"402\" data-end=\"416\">Spamfaktor<\/strong> ist eine Kennzahl zwischen <strong data-start=\"444\" data-end=\"451\">0,0<\/strong> und <strong data-start=\"456\" data-end=\"463\">1,0<\/strong>, mit der erkannt wird, wie wahrscheinlich ein Beitrag Spam oder sch\u00e4dliche Inhalte enth\u00e4lt. Das System basiert auf der OpenAI\u2011Moderations\u2011API, die Texte und Bilder auf problematische Kategorien wie <strong data-start=\"662\" data-end=\"682\">sexuelle Inhalte<\/strong>, <strong data-start=\"684\" data-end=\"699\">Bel\u00e4stigung<\/strong>, <strong data-start=\"701\" data-end=\"709\">Hass<\/strong>, <strong data-start=\"711\" data-end=\"731\">illegale Inhalte<\/strong>, <strong data-start=\"733\" data-end=\"753\">Selbstverletzung<\/strong> und <strong data-start=\"758\" data-end=\"768\">Gewalt<\/strong> untersucht<span class=\"\" data-state=\"closed\"><span class=\"ms-1 inline-flex max-w-full items-center relative top-&#091;-0.094rem&#093; animate-&#091;show_150ms_ease-in&#093;\" data-testid=\"webpage-citation-pill\"><a href=\"https:\/\/cookbook.openai.com\/examples\/how_to_use_moderation#:~:text=The%20function%20above%20can%20be,to%20a%20specific%20use%20case\" target=\"_blank\" rel=\"noopener\" alt=\"https:\/\/cookbook.openai.com\/examples\/how_to_use_moderation#:~:text=The%20function%20above%20can%20be,to%20a%20specific%20use%20case\" class=\"flex h-4.5 overflow-hidden rounded-xl px-2 text-&#091;9px&#093; font-medium transition-colors duration-150 ease-in-out text-token-text-secondary! bg-&#091;#F4F4F4&#093;! dark:bg-&#091;#303030&#093;!\"><span class=\"relative start-0 bottom-0 flex h-full w-full items-center\"><span class=\"flex h-4 w-full items-center justify-between overflow-hidden\"><span class=\"max-w-&#091;15ch&#093; grow truncate overflow-hidden text-center\">cookbook.openai.com<\/span><\/span><\/span><\/a><\/span><\/span>. Solche Kategorien werden automatisch erkannt, um Spam und irref\u00fchrende Inhalte zu filtern<span class=\"\" data-state=\"closed\"><span class=\"ms-1 inline-flex max-w-full items-center relative top-&#091;-0.094rem&#093; animate-&#091;show_150ms_ease-in&#093;\" data-testid=\"webpage-citation-pill\"><a href=\"https:\/\/cookbook.openai.com\/examples\/how_to_use_moderation#:~:text=,commerce%20platforms%2C%20and%20customer%20reviews\" target=\"_blank\" rel=\"noopener\" alt=\"https:\/\/cookbook.openai.com\/examples\/how_to_use_moderation#:~:text=,commerce%20platforms%2C%20and%20customer%20reviews\" class=\"flex h-4.5 overflow-hidden rounded-xl px-2 text-&#091;9px&#093; font-medium transition-colors duration-150 ease-in-out text-token-text-secondary! bg-&#091;#F4F4F4&#093;! dark:bg-&#091;#303030&#093;!\"><span class=\"relative start-0 bottom-0 flex h-full w-full items-center\"><span class=\"flex h-4 w-full items-center justify-between overflow-hidden\"><span class=\"max-w-&#091;15ch&#093; grow truncate overflow-hidden text-center\">cookbook.openai.com<\/span><\/span><\/span><\/a><\/span><\/span>.<\/p>\n<p data-start=\"947\" data-end=\"995\">Zur Einordnung nutzt das Projekt folgende Skala:<\/p>\n<div class=\"_tableContainer_1rjym_1\">\n<div class=\"group _tableWrapper_1rjym_13 flex w-fit flex-col-reverse\" tabindex=\"-1\">\n<table data-start=\"997\" data-end=\"1581\" class=\"w-fit min-w-(--thread-content-width)\">\n<thead data-start=\"997\" data-end=\"1093\">\n<tr data-start=\"997\" data-end=\"1093\">\n<th data-start=\"997\" data-end=\"1017\" data-col-size=\"sm\">Spamfaktor<\/th>\n<th data-start=\"1017\" data-end=\"1093\" data-col-size=\"md\">Bedeutung<\/th>\n<\/tr>\n<\/thead>\n<tbody data-start=\"1192\" data-end=\"1581\">\n<tr data-start=\"1192\" data-end=\"1288\">\n<td data-start=\"1192\" data-end=\"1212\" data-col-size=\"sm\"><strong data-start=\"1194\" data-end=\"1209\">0,00\u00a0\u2013\u00a00,20<\/strong><\/td>\n<td data-start=\"1212\" data-end=\"1288\" data-col-size=\"md\">Sehr wahrscheinlich legitimer Beitrag (kein Spam).<\/td>\n<\/tr>\n<tr data-start=\"1289\" data-end=\"1385\">\n<td data-start=\"1289\" data-end=\"1309\" data-col-size=\"sm\"><strong data-start=\"1291\" data-end=\"1306\">0,21\u00a0\u2013\u00a00,50<\/strong><\/td>\n<td data-start=\"1309\" data-end=\"1385\" data-col-size=\"md\">Leicht auff\u00e4llig \u2013 vermutlich harmlose Werbung.<\/td>\n<\/tr>\n<tr data-start=\"1386\" data-end=\"1482\">\n<td data-start=\"1386\" data-end=\"1406\" data-col-size=\"sm\"><strong data-start=\"1388\" data-end=\"1403\">0,51\u00a0\u2013\u00a00,80<\/strong><\/td>\n<td data-start=\"1406\" data-end=\"1482\" data-col-size=\"md\">Deutlicher Verdacht auf Spam oder irref\u00fchrende Inhalte.<\/td>\n<\/tr>\n<tr data-start=\"1483\" data-end=\"1581\">\n<td data-start=\"1483\" data-end=\"1503\" data-col-size=\"sm\"><strong data-start=\"1485\" data-end=\"1500\">0,81\u00a0\u2013\u00a01,00<\/strong><\/td>\n<td data-start=\"1503\" data-end=\"1581\" data-col-size=\"md\"><strong data-start=\"1505\" data-end=\"1554\">Offensichtlicher Spam oder sch\u00e4dlicher Inhalt<\/strong> \u2013 Beitrag wird geblockt.<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<\/div>\n<p data-start=\"1583\" data-end=\"2099\">Die Wahl eines Schwellenwerts (z.\u202fB. <strong data-start=\"1620\" data-end=\"1628\">0,80<\/strong>) ist ein Abw\u00e4gungsprozess zwischen Falsch\u2011Positiven (legitime Inhalte werden f\u00e4lschlich blockiert) und Falsch\u2011Negativen (problematische Inhalte rutschen durch). Die OpenAI\u2011Dokumentation weist darauf hin, dass solche Schwellenwerte an die gew\u00fcnschte Toleranz angepasst werden sollten<span class=\"\" data-state=\"closed\"><span class=\"ms-1 inline-flex max-w-full items-center relative top-&#091;-0.094rem&#093; animate-&#091;show_150ms_ease-in&#093;\" data-testid=\"webpage-citation-pill\"><a href=\"https:\/\/cookbook.openai.com\/examples\/how_to_use_moderation#:~:text=OpenAI%20has%20selected%20thresholds%20for,off%20here%20is%20generally\" target=\"_blank\" rel=\"noopener\" alt=\"https:\/\/cookbook.openai.com\/examples\/how_to_use_moderation#:~:text=OpenAI%20has%20selected%20thresholds%20for,off%20here%20is%20generally\" class=\"flex h-4.5 overflow-hidden rounded-xl px-2 text-&#091;9px&#093; font-medium transition-colors duration-150 ease-in-out text-token-text-secondary! bg-&#091;#F4F4F4&#093;! dark:bg-&#091;#303030&#093;!\"><span class=\"relative start-0 bottom-0 flex h-full w-full items-center\"><span class=\"flex h-4 w-full items-center justify-between overflow-hidden\"><span class=\"max-w-&#091;15ch&#093; grow truncate overflow-hidden text-center\">cookbook.openai.com<\/span><\/span><\/span><\/a><\/span><\/span>. In diesem Projekt gilt: <strong data-start=\"1974\" data-end=\"2069\">Liegt der Spamfaktor \u00fcber 0,50, wird der Beitrag automatisch in den Entwurfsstatus versetzt<\/strong>, um Missbrauch zu verhindern.<\/p>\n<h3 data-start=\"2101\" data-end=\"2131\">\u2728 Anwendung des Shortcodes<\/h3>\n<p data-start=\"2133\" data-end=\"2308\">Der Shortcode <code data-start=\"2147\" data-end=\"2165\"><\/code> pr\u00fcft einen oder mehrere Beitr\u00e4ge und speichert den ermittelten Spamfaktor im Metafeld <code data-start=\"2253\" data-end=\"2259\">spam<\/code>. Je nach Parameter ver\u00e4ndert sich das Verhalten:<\/p>\n<ul data-start=\"2310\" data-end=\"3513\">\n<li data-start=\"2310\" data-end=\"2883\">\n<p data-start=\"2312\" data-end=\"2367\"><strong data-start=\"2312\" data-end=\"2353\">Letzter Beitrag des aktuellen Nutzers<\/strong> (Standard):<\/p>\n<div class=\"contain-inline-size rounded-2xl relative bg-token-sidebar-surface-primary\">\n<div class=\"sticky top-9\">\n<div class=\"absolute end-0 bottom-0 flex h-9 items-center pe-2\">\n<div class=\"bg-token-bg-elevated-secondary text-token-text-secondary flex items-center gap-4 rounded-sm px-2 font-sans text-xs\"><\/div>\n<\/div>\n<\/div>\n<div class=\"overflow-y-auto p-4\" dir=\"ltr\">\n<p><code class=\"whitespace-pre!\"><span>[<span class=\"hljs-meta\">sdg_spam_check use_openai=<span class=\"hljs-string\">\"1\"<\/span><\/span>]<\/span><\/code><\/p>\n<p>&nbsp;<\/p>\n<\/div>\n<\/div>\n<ul data-start=\"2416\" data-end=\"2883\">\n<li data-start=\"2416\" data-end=\"2495\">\n<p data-start=\"2418\" data-end=\"2495\">Pr\u00fcft den zuletzt erstellten <code data-start=\"2447\" data-end=\"2459\">commitment<\/code>-Beitrag des eingeloggten Nutzers.<\/p>\n<\/li>\n<li data-start=\"2498\" data-end=\"2683\">\n<p data-start=\"2500\" data-end=\"2683\">Wird der Spamfaktor <strong data-start=\"2520\" data-end=\"2530\">\u2264 0,50<\/strong>, zeigt der Shortcode nach der Pr\u00fcfung die positive Meldung<br data-start=\"2589\" data-end=\"2592\" \/><em data-start=\"2596\" data-end=\"2681\">\u201eDeine Celebration wurde \u00fcberpr\u00fcft und ist jetzt auf der Celebration Map sichtbar\u201c.<\/em><\/p>\n<\/li>\n<li data-start=\"2686\" data-end=\"2883\">\n<p data-start=\"2688\" data-end=\"2883\">Ist der Spamfaktor <strong data-start=\"2707\" data-end=\"2717\">&gt; 0,50<\/strong>, wird der Beitrag als Entwurf gespeichert und die negative Meldung<br data-start=\"2784\" data-end=\"2787\" \/><em data-start=\"2791\" data-end=\"2871\">\u201eVielen Dank f\u00fcr deinen Beitrag. Wir werden ihn pr\u00fcfen und dann freischalten.\u201c<\/em> ausgegeben.<\/p>\n<\/li>\n<\/ul>\n<\/li>\n<li data-start=\"2885\" data-end=\"3168\">\n<p data-start=\"2887\" data-end=\"2939\"><strong data-start=\"2887\" data-end=\"2916\">Bestimmten Beitrag pr\u00fcfen<\/strong> (z.\u202fB. Post\u2011ID\u00a0445):<\/p>\n<div class=\"contain-inline-size rounded-2xl relative bg-token-sidebar-surface-primary\">\n<div class=\"sticky top-9\">\n<div class=\"absolute end-0 bottom-0 flex h-9 items-center pe-2\">\n<div class=\"bg-token-bg-elevated-secondary text-token-text-secondary flex items-center gap-4 rounded-sm px-2 font-sans text-xs\"><\/div>\n<\/div>\n<\/div>\n<div class=\"overflow-y-auto p-4\" dir=\"ltr\">\n<p><code class=\"whitespace-pre!\"><span>[<span class=\"hljs-meta\">sdg_spam_check post_id=<span class=\"hljs-string\">\"445\"<\/span><\/span> use_openai=<span class=\"hljs-string\">\"1\"<\/span>]<\/span><\/code><\/p>\n<p>&nbsp;<\/p>\n<\/div>\n<\/div>\n<ul data-start=\"3002\" data-end=\"3168\">\n<li data-start=\"3002\" data-end=\"3069\">\n<p data-start=\"3004\" data-end=\"3069\">Pr\u00fcft nur diesen Beitrag und aktualisiert sein Metafeld <code data-start=\"3060\" data-end=\"3066\">spam<\/code>.<\/p>\n<\/li>\n<li data-start=\"3072\" data-end=\"3168\">\n<p data-start=\"3074\" data-end=\"3168\">Liegt der Spamfaktor \u00fcber dem Schwellenwert, wird der Beitrag automatisch auf <code data-start=\"3152\" data-end=\"3159\">draft<\/code> gesetzt.<\/p>\n<\/li>\n<\/ul>\n<\/li>\n<li data-start=\"3170\" data-end=\"3513\">\n<p data-start=\"3172\" data-end=\"3246\"><strong data-start=\"3172\" data-end=\"3196\">Alle Beitr\u00e4ge pr\u00fcfen<\/strong> (nur Beitr\u00e4ge, die der Nutzer bearbeiten darf):<\/p>\n<div class=\"contain-inline-size rounded-2xl relative bg-token-sidebar-surface-primary\">\n<div class=\"sticky top-9\">\n<div class=\"absolute end-0 bottom-0 flex h-9 items-center pe-2\">\n<div class=\"bg-token-bg-elevated-secondary text-token-text-secondary flex items-center gap-4 rounded-sm px-2 font-sans text-xs\"><\/div>\n<\/div>\n<\/div>\n<div class=\"overflow-y-auto p-4\" dir=\"ltr\">\n<p><code class=\"whitespace-pre!\"><span>[<span class=\"hljs-meta\">sdg_spam_check post_id=<span class=\"hljs-string\">\"all\"<\/span><\/span> use_openai=<span class=\"hljs-string\">\"1\"<\/span>]<\/span><\/code><\/p>\n<p>&nbsp;<\/p>\n<\/div>\n<\/div>\n<ul data-start=\"3309\" data-end=\"3513\">\n<li data-start=\"3309\" data-end=\"3426\">\n<p data-start=\"3311\" data-end=\"3426\">Pr\u00fcft alle <code data-start=\"3322\" data-end=\"3334\">commitment<\/code>\u2011Beitr\u00e4ge, aktualisiert die Spamfaktoren und setzt Beitr\u00e4ge mit zu hohem Wert auf <code data-start=\"3416\" data-end=\"3423\">draft<\/code>.<\/p>\n<\/li>\n<li data-start=\"3429\" data-end=\"3513\">\n<p data-start=\"3431\" data-end=\"3513\">Gibt eine zusammenfassende R\u00fcckmeldung aus (\u201eSpam check completed on N post(s).\u201c).<\/p>\n<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p data-start=\"3515\" data-end=\"3756\">Nach der Pr\u00fcfung wird der Spamfaktor in der <strong data-start=\"3559\" data-end=\"3583\">Administrationsliste<\/strong> in einer eigenen Spalte angezeigt. Somit k\u00f6nnen Administratoren auf einen Blick erkennen, welche Beitr\u00e4ge unbedenklich sind und welche in den Entwurfsmodus versetzt wurden.<\/p><\/div>\n\t\t\t<\/div><div class=\"et_pb_module et_d4_element et_pb_text et_pb_text_1  et_pb_text_align_left et_pb_bg_layout_light\">\n\t\t\t\t\n\t\t\t\t\n\t\t\t\t\n\t\t\t\t\n\t\t\t\t<div class=\"et_pb_text_inner\"><h2>Zweck des Codes<\/h2>\n<p>Der Shortcode <code>sdg_spam_check<\/code>\u00a0pr\u00fcft einen oder mehrere \u201eFeiern\u201c-Beitr\u00e4ge (Post-Typ <code>commitment<\/code>) automatisiert auf Spam oder problematische Inhalte.<br \/>Je nach Ergebnis:<\/p>\n<ul>\n<li>wird ein <strong>Spam-Score<\/strong> im Beitrag gespeichert,<\/li>\n<li>der Beitrag ggf. auf <strong>Entwurf (draft)<\/strong> gesetzt,<\/li>\n<li>und dem Nutzer eine <strong>R\u00fcckmeldung in seiner Sprache<\/strong> angezeigt.<\/li>\n<\/ul>\n<p>Optional kann daf\u00fcr die <strong>OpenAI-API<\/strong> genutzt werden.<\/p>\n<hr \/>\n<h2>1. Wie der Shortcode aufgerufen wird<\/h2>\n<p>Grundform:<\/p>\n<pre><code class=\"language-text\">sdg_spam_check post_id=\"\" use_openai=\"1\"]\n<\/code><\/pre>\n<p><strong>Attribute:<\/strong><\/p>\n<ul>\n<li><code>post_id<\/code>\n<ul>\n<li><code>\"\"<\/code> (leer oder ung\u00fcltig) \u2192 der <strong>letzte Beitrag des eingeloggten Nutzers<\/strong> wird gepr\u00fcft (nur wenn URL <code>?a=create<\/code> oder <code>?a=update<\/code> enth\u00e4lt).<\/li>\n<li><code>\"all\"<\/code> \u2192 <strong>alle<\/strong> <code>commitment<\/code>-Beitr\u00e4ge, die der eingeloggte Nutzer bearbeiten darf, werden gepr\u00fcft.<\/li>\n<li>eine Zahl (z.B. <code>\"123\"<\/code>) \u2192 genau dieser Beitrag wird gepr\u00fcft (wenn Typ <code>commitment<\/code> und der Nutzer Bearbeitungsrechte hat).<\/li>\n<\/ul>\n<\/li>\n<li><code>use_openai<\/code>\n<ul>\n<li><code>\"1\"<\/code> \u2192 OpenAI-Moderation wird benutzt (falls API-Key vorhanden).<\/li>\n<li><code>\"0\"<\/code> \u2192 es wird nur ein Spam-Score <code>0.0<\/code> gesetzt (kein API-Call).<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<hr \/>\n<h2>2. Steuerung \u00fcber URL-Parameter <code>a<\/code><\/h2>\n<p>F\u00fcr den Standardfall \u201eneuer oder ge\u00e4nderter Beitrag des aktuellen Users\u201c (leerer <code>post_id<\/code>) wird zus\u00e4tzlich der URL-Parameter <code>a<\/code> ausgewertet, z.B.:<\/p>\n<ul>\n<li><code>?a=create<\/code> \u2192 <strong>neu angelegter<\/strong> Beitrag<\/li>\n<li><code>?a=update<\/code> \u2192 <strong>aktualisierter<\/strong> Beitrag<\/li>\n<\/ul>\n<p>Nur wenn <code>a<\/code> genau <code>\"create\"<\/code> oder <code>\"update\"<\/code> ist, wird:<\/p>\n<ul>\n<li>\u00fcberhaupt eine Spampr\u00fcfung f\u00fcr den <strong>letzten Beitrag des Nutzers<\/strong> durchgef\u00fchrt,<\/li>\n<li>und eine R\u00fcckmeldung (positiv\/negativ) ausgegeben.<\/li>\n<\/ul>\n<p>Fehlt der Parameter oder hat er einen anderen Wert, gibt der Shortcode <strong>gar nichts<\/strong> aus.<\/p>\n<hr \/>\n<h2>3. Spracherkennung und \u00dcbersetzungen<\/h2>\n<p>Die R\u00fcckmeldungen an den Nutzer werden <strong>mehrsprachig<\/strong> ausgegeben.<\/p>\n<ol>\n<li>Es wird die Sprache des Besuchers ermittelt:\n<ul>\n<li>bevorzugt mit <code>determine_locale()<\/code>,<\/li>\n<li>sonst mit <code>get_locale()<\/code>.<\/li>\n<\/ul>\n<\/li>\n<li>Aus dem Locale werden die ersten zwei Buchstaben verwendet, z.B.:\n<ul>\n<li><code>de_DE<\/code> \u2192 <code>de<\/code><\/li>\n<li><code>en_US<\/code> \u2192 <code>en<\/code><\/li>\n<\/ul>\n<\/li>\n<li>F\u00fcr diese Sprachk\u00fcrzel sind Texte hinterlegt:<br \/>aktuell <code>en, de, sq, es, fr, pt, zh, ko, hi, ru, ar<\/code>.<\/li>\n<\/ol>\n<p><strong>Zwei Nachrichtentypen:<\/strong><\/p>\n<ul>\n<li><strong>positive_msg<\/strong> (wenn kein Spam):<br \/>\u201eDeine Feier wurde gepr\u00fcft und ist jetzt auf der Feier-Karte sichtbar.\u201c (bzw. \u00dcbersetzung)<\/li>\n<li><strong>negative_msg<\/strong> (wenn Spam):<br \/>\u201eVielen Dank f\u00fcr deine Einreichung. Wir werden sie pr\u00fcfen und anschlie\u00dfend ver\u00f6ffentlichen.\u201c (bzw. \u00dcbersetzung)<\/li>\n<\/ul>\n<p>Kann die gew\u00e4hlte Sprache nicht gefunden werden, f\u00e4llt der Code auf <strong>Englisch<\/strong> zur\u00fcck.<\/p>\n<hr \/>\n<h2>4. Welche Beitr\u00e4ge werden tats\u00e4chlich gepr\u00fcft?<\/h2>\n<p>Je nach <code>post_id<\/code>:<\/p>\n<ol>\n<li><code>post_id=\"all\"<\/code>\n<ul>\n<li>Es werden alle Beitr\u00e4ge vom Typ <code>commitment<\/code> geladen (alle Status: publish, pending, draft, future, private).<\/li>\n<li>Nur Beitr\u00e4ge, die der eingeloggte Nutzer <strong>bearbeiten darf<\/strong>, kommen in die Pr\u00fcfliste.<\/li>\n<\/ul>\n<\/li>\n<li><code>post_id=\"\"<\/code> oder nicht numerisch\n<ul>\n<li>Es wird der <strong>aktuell eingeloggte User<\/strong> gepr\u00fcft:\n<ul>\n<li>Falls keiner eingeloggt ist \u2192 Ausgabe: <code>Please log in.<\/code><\/li>\n<\/ul>\n<\/li>\n<li>Es wird der <strong>neueste <code>commitment<\/code>-Beitrag<\/strong> dieses Nutzers gesucht (alle Status).<\/li>\n<li>Nur wenn die URL <code>?a=create<\/code> oder <code>?a=update<\/code> enth\u00e4lt:\n<ul>\n<li>wird dieser letzte Beitrag gepr\u00fcft<\/li>\n<li>und eine nutzerfreundliche Meldung ausgegeben.<\/li>\n<\/ul>\n<\/li>\n<li>Gibt es keinen Beitrag \u2192 Ausgabe: <code>No post found for current user.<\/code><\/li>\n<\/ul>\n<\/li>\n<li><code>post_id=\"123\"<\/code> (numerisch)\n<ul>\n<li>Wenn der Beitrag vom Typ <code>commitment<\/code> ist und der Nutzer Bearbeitungsrechte hat:\n<ul>\n<li>wird genau dieser Beitrag gepr\u00fcft.<\/li>\n<\/ul>\n<\/li>\n<li>Sonst Ausgabe: <code>Invalid post ID or insufficient permissions.<\/code><\/li>\n<\/ul>\n<\/li>\n<\/ol>\n<p>Wenn am Ende <strong>keine Beitr\u00e4ge<\/strong> in der Pr\u00fcfliste sind, kommt: <code>No posts to check.<\/code><\/p>\n<hr \/>\n<h2>5. Wie die Spam-Pr\u00fcfung technisch abl\u00e4uft<\/h2>\n<p>F\u00fcr jeden zu pr\u00fcfenden Beitrag (<code>$pid<\/code>) wird:<\/p>\n<ol>\n<li>Ein <strong>Spam-Faktor<\/strong> initial auf <code>0.0<\/code> gesetzt.<\/li>\n<li>Nur wenn:\n<ul>\n<li><code>use_openai=\"1\"<\/code> gesetzt ist<\/li>\n<li>und die Konstante <code>OPENAI_API_KEY<\/code> definiert ist,<\/li>\n<\/ul>\n<p>wird eine Anfrage an die <strong>OpenAI Chat Completions API<\/strong> gesendet.<\/p>\n<\/li>\n<\/ol>\n<h3>5.1 Welche Daten an OpenAI gesendet werden?<\/h3>\n<ul>\n<li>Alle <strong>Post-Meta-Felder<\/strong> des Beitrags werden durchlaufen.<\/li>\n<li>Nicht gesendet werden:\n<ul>\n<li>Meta-Keys, die mit <code>_<\/code> beginnen (technische Felder),<\/li>\n<li><code>first_name<\/code>,<\/li>\n<li><code>last_name<\/code>,<\/li>\n<li><code>spam<\/code>.<\/li>\n<\/ul>\n<\/li>\n<li>Leere Werte werden \u00fcbersprungen.<\/li>\n<li>Arrays werden JSON-kodiert, sonst werden Strings verwendet.<\/li>\n<li>Der Key <code>image_for_the_event<\/code> wird speziell behandelt:\n<ul>\n<li>Falls numerisch \u2192 wird die URL des Anhangs ermittelt.<\/li>\n<li>Falls schon URL \u2192 wird diese \u00fcbernommen.<\/li>\n<li>Diese Bild-URL wird dem Text an OpenAI hinzugef\u00fcgt.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p>Alle Daten werden als <strong>Textliste<\/strong> im User-Prompt an OpenAI gesendet:<br \/><code>Feldname: Wert<\/code><\/p>\n<h3>5.2 OpenAI-Prompt und Antwort<\/h3>\n<ul>\n<li>Systemrolle: \u201econtent safety analyst\u201c, der auf Basis der Daten einen <strong>Spam-Faktor<\/strong> von <code>0.0<\/code> bis <code>1.0<\/code> zur\u00fcckgibt.<\/li>\n<li>Antwortformat: <strong>reines JSON<\/strong> mit einem Feld <code>spam_factor<\/code>, z.B.:\n<pre><code class=\"language-json\">{ \"spam_factor\": 0.27 }\n<\/code><\/pre>\n<\/li>\n<li>Die Antwort wird geparst; der Wert wird auf den Bereich <code>0.0\u20131.0<\/code> begrenzt.<\/li>\n<\/ul>\n<p>Wenn die API nicht erreichbar ist oder kein g\u00fcltiges JSON zur\u00fcckkommt, bleibt der Spam-Faktor bei <code>0.0<\/code>.<\/p>\n<h3>5.3 Speicherung &amp; Schwellenwert<\/h3>\n<ul>\n<li>Der berechnete <code>spam_factor<\/code> wird als Post-Meta <code>spam<\/code> gespeichert.<\/li>\n<li>Es gibt einen <strong>Schwellenwert<\/strong> <code>$threshold = 0.5<\/code>.<\/li>\n<li>Wenn <code>spam_factor &gt;= 0.5<\/code>:\n<ul>\n<li>wird der Beitrag automatisch auf <strong>Status <code>draft<\/code><\/strong> gesetzt<br \/>(<code>wp_update_post<\/code>).<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<hr \/>\n<h2>6. Was der Shortcode im Frontend ausgibt<\/h2>\n<p>Am Ende h\u00e4ngt die Ausgabe davon ab, <strong>wie viele Beitr\u00e4ge<\/strong> gepr\u00fcft wurden und in welchem Modus:<\/p>\n<ol>\n<li><strong>Standardfall \u201eletzter Beitrag des Nutzers\u201c (ein Beitrag, <code>a=create|update<\/code>)<\/strong>\n<ul>\n<li>Wenn <code>spam_factor &gt;= 0.5<\/code> \u2192 \u201enegative\u201c Meldung in Sprache des Nutzers<br \/>(z.B. <em>\u201eVielen Dank f\u00fcr deine Einreichung. Wir werden sie pr\u00fcfen und anschlie\u00dfend ver\u00f6ffentlichen.\u201c<\/em>)<\/li>\n<li>Wenn <code>spam_factor &lt; 0.5<\/code> \u2192 \u201epositive\u201c Meldung<br \/>(z.B. <em>\u201eDeine Feier wurde gepr\u00fcft und ist jetzt auf der Feier-Karte sichtbar.\u201c<\/em>)<\/li>\n<\/ul>\n<\/li>\n<li><strong>Mehrere Beitr\u00e4ge (z.B. <code>post_id=\"all\"<\/code>) oder gezielte ID<\/strong>\n<ul>\n<li>Es wird <strong>keine Einzelmeldung pro Beitrag<\/strong> ausgegeben.<\/li>\n<li>Stattdessen: eine neutrale Zusammenfassung:\n<pre><code class=\"language-html\">&lt;p&gt;Spam check completed on X post(s).&lt;\/p&gt;\n<\/code><\/pre>\n<\/li>\n<\/ul>\n<\/li>\n<li><strong>Kein passender Post \/ keine Rechte \/ nicht eingeloggt<\/strong>\n<ul>\n<li>Entsprechende Fehlermeldung im Klartext:\n<ul>\n<li><code>Please log in.<\/code><\/li>\n<li><code>No post found for current user.<\/code><\/li>\n<li><code>Invalid post ID or insufficient permissions.<\/code><\/li>\n<li><code>No posts to check.<\/code><\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n<hr \/>\n<h2>7. Typische Anwendungsf\u00e4lle (Beispiele)<\/h2>\n<ul>\n<li><strong>Nach dem Absenden eines Formulars (neuer Eintrag):<\/strong>\n<pre><code class=\"language-text\">sdg_spam_check use_openai=\"1\"]\n<\/code><\/pre>\n<p>Wird auf einer Seite verwendet, die mit <code>?a=create<\/code> oder <code>?a=update<\/code> aufgerufen wird.<br \/>\u2192 Pr\u00fcft den zuletzt erstellten\/aktualisierten Beitrag des eingeloggten Nutzers und zeigt eine passende R\u00fcckmeldung.<\/p>\n<\/li>\n<li><strong>Admin- \/ Moderator-Check f\u00fcr alle eigenen Feiern:<\/strong>\n<pre><code class=\"language-text\">sdg_spam_check post_id=\"all\" use_openai=\"1\"]\n<\/code><\/pre>\n<p>\u2192 Pr\u00fcft alle eigenen <code>commitment<\/code>-Beitr\u00e4ge und setzt ggf. Spam-Beitr\u00e4ge auf <code>draft<\/code>. Ausgabe: \u201eSpam check completed on X post(s).\u201c<\/p>\n<\/li>\n<li><strong>Gezielter Check eines einzelnen Beitrags (z.B. im Backend-Dashboard):<\/strong>\n<pre><code class=\"language-text\">sdg_spam_check post_id=\"123\" use_openai=\"1\"]\n<\/code><\/pre>\n<\/li>\n<\/ul>\n<hr \/>\n<p>&nbsp;<\/p><\/div>\n\t\t\t<\/div><div id=\"LeereArrays\" class=\"et_pb_module et_d4_element et_pb_text et_pb_text_2  et_pb_text_align_left et_pb_bg_layout_light\">\n\t\t\t\t\n\t\t\t\t\n\t\t\t\t\n\t\t\t\t\n\t\t\t\t<div class=\"et_pb_text_inner\"><p>&nbsp;<\/p>\n<h2>Leere Arrays bereinigen<\/h2>\n<p>Der Code behebt einen konkreten technischen Fehler in Beitr\u00e4gen (Post-Typ z.B. <code>commitment<\/code>):<\/p>\n<ul>\n<li>\n<p>In vier bestimmten Feldern (<code>date_of_our_event<\/code>, <code>time_of_the_event<\/code>, <code>website_of_the_event<\/code>, <code>details_about_the_events<\/code>) landet manchmal der Wert <code>a:0:{}<\/code> bzw. ein leeres Array.<\/p>\n<\/li>\n<li>\n<p>Das ist ein <strong>technischer Sonderfall<\/strong> (leeres, serialisiertes Array), mit dem andere Funktionen (z.B. Datumsverarbeitung) nicht klarkommen und Fehler werfen k\u00f6nnen.<\/p>\n<\/li>\n<li>\n<p>Der Code sucht diese \u201ekaputten\u201c Werte und ersetzt sie durch <strong>leere Strings<\/strong> (<code>''<\/code>).<br \/>Praktisch bedeutet das: \u201ekein Wert gesetzt\u201c statt \u201edefekter Wert\u201c.<\/p>\n<\/li>\n<\/ul>\n<p>Es gibt daf\u00fcr:<\/p>\n<ol>\n<li>\n<p>eine <strong>Hilfsfunktion<\/strong>: <code>sdg_fix_empty_array_metas()<\/code><\/p>\n<\/li>\n<li>\n<p>einen Shortcode, um <strong>nur den letzten Beitrag<\/strong> zu reparieren:<br \/><code>[sdg_fix_latest_meta ...]<\/code><\/p>\n<\/li>\n<li>\n<p>einen Shortcode, um <strong>alle passenden Beitr\u00e4ge<\/strong> in einem Rutsch zu reparieren:<br \/><code>[sdg_fix_all_meta ...]<\/code><\/p>\n<\/li>\n<\/ol>\n<hr \/>\n<h2>1. Hilfsfunktion: <code>sdg_fix_empty_array_metas($post_id, $keys)<\/code><\/h2>\n<p><strong>Was sie tut:<\/strong><\/p>\n<ul>\n<li>\n<p>Nimmt eine Beitrags-ID (<code>$post_id<\/code>) und eine Liste von Feldnamen (<code>$keys<\/code>).<\/p>\n<\/li>\n<li>\n<p>F\u00fcr jedes dieser Felder:<\/p>\n<ol>\n<li>\n<p>Liest den Rohwert aus der Datenbank.<\/p>\n<\/li>\n<li>\n<p>Wenn es gar keinen Wert gibt (leer oder <code>null<\/code>), passiert nichts.<\/p>\n<\/li>\n<li>\n<p>Pr\u00fcft, ob der Wert<\/p>\n<ul>\n<li>\n<p><strong>genau<\/strong> <code>a:0:{}<\/code> ist (klassische WordPress-Serialisierung eines leeren Arrays)<br \/><strong>oder<\/strong><\/p>\n<\/li>\n<li>\n<p>sich nach dem Entserialisieren (<code>maybe_unserialize<\/code>) als <strong>leeres Array<\/strong> herausstellt.<\/p>\n<\/li>\n<\/ul>\n<\/li>\n<li>\n<p>Falls ja, wird der Wert im Beitrag auf <code>''<\/code> (leerer String) gesetzt \u2013 technisch das \u201eNull-\u00c4quivalent\u201c f\u00fcr ein Meta-Feld in WordPress.<\/p>\n<\/li>\n<li>\n<p>Der Name des Feldes wird in eine Liste der \u201ereparierten\u201c Felder aufgenommen.<\/p>\n<\/li>\n<\/ol>\n<\/li>\n<li>\n<p>Am Ende gibt die Funktion ein <strong>Array der bereinigten Feldnamen<\/strong> zur\u00fcck.<br \/>(z.B. <code>['date_of_our_event', 'time_of_the_event']<\/code>)<\/p>\n<\/li>\n<\/ul>\n<p><strong>F\u00fcr Externe:<\/strong><br \/>Diese Funktion ist die eigentliche \u201eReparatur-Logik\u201c. Die Shortcodes rufen sie nur mit unterschiedlichen Beitragslisten auf.<\/p>\n<hr \/>\n<h2>2. Shortcode 1: Letzten Beitrag pr\u00fcfen\/fixen<\/h2>\n<p><strong>Shortcode:<\/strong><\/p>\n<pre><code class=\"language-text\">[sdg_fix_latest_meta post_type=\"commitment\" scope=\"user|global\"]\n<\/code><\/pre>\n<p><strong>Parameter:<\/strong><\/p>\n<ul>\n<li>\n<p><code>post_type<\/code><\/p>\n<ul>\n<li>\n<p>z.B. <code>\"commitment\"<\/code> oder <code>\"any\"<\/code><\/p>\n<\/li>\n<li>\n<p>Steuert, welcher Beitragstyp betrachtet wird.<\/p>\n<\/li>\n<\/ul>\n<\/li>\n<li>\n<p><code>scope<\/code><\/p>\n<ul>\n<li>\n<p><code>\"user\"<\/code> (Standard): Es wird der <strong>letzte Beitrag des aktuell eingeloggten Nutzers<\/strong> gesucht.<\/p>\n<\/li>\n<li>\n<p><code>\"global\"<\/code>: Es wird der <strong>letzte Beitrag insgesamt<\/strong> (unabh\u00e4ngig vom Autor) gesucht.<\/p>\n<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p><strong>Ablauf:<\/strong><\/p>\n<ol>\n<li>\n<p>Der Shortcode definiert zun\u00e4chst die vier betroffenen Meta-Felder:<\/p>\n<ul>\n<li>\n<p><code>date_of_our_event<\/code><\/p>\n<\/li>\n<li>\n<p><code>time_of_the_event<\/code><\/p>\n<\/li>\n<li>\n<p><code>website_of_the_event<\/code><\/p>\n<\/li>\n<li>\n<p><code>details_about_the_events<\/code><\/p>\n<\/li>\n<\/ul>\n<\/li>\n<li>\n<p>Er baut eine Abfrage, um genau <strong>einen Beitrag<\/strong> zu finden:<\/p>\n<ul>\n<li>\n<p>neuester Beitrag (<code>orderby=date<\/code>, <code>DESC<\/code>)<\/p>\n<\/li>\n<li>\n<p>Status: <code>publish<\/code>, <code>pending<\/code>, <code>draft<\/code>, <code>future<\/code>, <code>private<\/code><\/p>\n<\/li>\n<li>\n<p>Post-Typ: wie in <code>post_type<\/code> angegeben (<code>any<\/code> oder spezifisch)<\/p>\n<\/li>\n<\/ul>\n<\/li>\n<li>\n<p>Bei <code>scope=\"user\"<\/code>:<\/p>\n<ul>\n<li>\n<p>Wird zus\u00e4tzlich der aktuell eingeloggte Benutzer ermittelt.<\/p>\n<\/li>\n<li>\n<p>Falls niemand eingeloggt ist \u2192 Ausgabe:<br \/><strong>\u201eBitte einloggen.\u201c<\/strong><\/p>\n<\/li>\n<li>\n<p>Sonst werden nur Beitr\u00e4ge dieses Nutzers ber\u00fccksichtigt.<\/p>\n<\/li>\n<\/ul>\n<\/li>\n<li>\n<p>Wird <strong>kein passender Beitrag<\/strong> gefunden \u2192 Ausgabe:<br \/><strong>\u201eKein passender Beitrag gefunden.\u201c<\/strong><\/p>\n<\/li>\n<li>\n<p>Wird ein Beitrag gefunden:<\/p>\n<ul>\n<li>\n<p><code>sdg_fix_empty_array_metas()<\/code> wird f\u00fcr genau diesen Beitrag mit den vier Schl\u00fcsseln aufgerufen.<\/p>\n<\/li>\n<li>\n<p>Gibt es nichts zu reparieren \u2192 Ausgabe:<br \/><strong>\u201eLetzter Beitrag (#ID): keine a:0:{}-Felder gefunden.\u201c<\/strong><\/p>\n<\/li>\n<li>\n<p>Gibt es reparierte Felder \u2192 Ausgabe:<br \/><strong>\u201eBeitrag #ID bereinigt: feld1, feld2, \u2026\u201c<\/strong><\/p>\n<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n<p><strong>Typischer Einsatz:<\/strong><\/p>\n<ul>\n<li>\n<p>Wenn man vermutet, dass beim <strong>zuletzt angelegten\/aktualisierten Beitrag<\/strong> des eigenen Accounts ein Fehler in den vier Feldern steckt.<\/p>\n<\/li>\n<li>\n<p>Man ruft den Shortcode auf einer Admin-\/Service-Seite auf und sieht direkt, ob und was korrigiert wurde.<\/p>\n<\/li>\n<\/ul>\n<hr \/>\n<h2>3. Shortcode 2: Alle passenden Beitr\u00e4ge pr\u00fcfen\/fixen<\/h2>\n<p><strong>Shortcode:<\/strong><\/p>\n<pre><code class=\"language-text\">[sdg_fix_all_meta post_type=\"commitment\" author=\"\"]\n<\/code><\/pre>\n<p><strong>Wichtiger Hinweis:<\/strong><br \/>Dieser Shortcode ist nur f\u00fcr Nutzer mit ausreichenden Rechten gedacht, z.B. <strong>Redakteure oder Administratoren<\/strong>.<br \/>Technisch wird gepr\u00fcft:<\/p>\n<ul>\n<li>\n<p>Nutzer muss eingeloggt sein <strong>und<\/strong><\/p>\n<\/li>\n<li>\n<p><code>current_user_can('delete_posts')<\/code> muss true sein.<\/p>\n<\/li>\n<\/ul>\n<p>Sonst gibt der Shortcode aus:<br \/><strong>\u201eKeine Berechtigung.\u201c<\/strong><\/p>\n<p><strong>Parameter:<\/strong><\/p>\n<ul>\n<li>\n<p><code>post_type<\/code><\/p>\n<ul>\n<li>\n<p><code>\"commitment\"<\/code> oder <code>\"any\"<\/code><\/p>\n<\/li>\n<li>\n<p>Steuert, welche Beitragstypen durchsucht werden.<\/p>\n<\/li>\n<\/ul>\n<\/li>\n<li>\n<p><code>author<\/code><\/p>\n<ul>\n<li>\n<p><code>\"\"<\/code> (leer): <strong>alle Autoren<\/strong> werden ber\u00fccksichtigt.<\/p>\n<\/li>\n<li>\n<p><code>\"current\"<\/code>: Nur Beitr\u00e4ge des <strong>aktuell eingeloggten<\/strong> Nutzers.<\/p>\n<\/li>\n<li>\n<p>numerische ID (z.B. <code>\"7\"<\/code>): Nur Beitr\u00e4ge <strong>dieses Autors<\/strong>.<\/p>\n<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p><strong>Ablauf:<\/strong><\/p>\n<ol>\n<li>\n<p>Wieder dieselben vier Meta-Felder wie beim ersten Shortcode:<\/p>\n<ul>\n<li>\n<p><code>date_of_our_event<\/code><\/p>\n<\/li>\n<li>\n<p><code>time_of_the_event<\/code><\/p>\n<\/li>\n<li>\n<p><code>website_of_the_event<\/code><\/p>\n<\/li>\n<li>\n<p><code>details_about_the_events<\/code><\/p>\n<\/li>\n<\/ul>\n<\/li>\n<li>\n<p>Es wird eine Abfrage gebaut, die <strong>alle passenden Beitr\u00e4ge<\/strong> l\u00e4dt:<\/p>\n<ul>\n<li>\n<p><code>posts_per_page = -1<\/code> (also alle)<\/p>\n<\/li>\n<li>\n<p>nach Datum sortiert (neueste zuerst)<\/p>\n<\/li>\n<li>\n<p>Status: <code>publish<\/code>, <code>pending<\/code>, <code>draft<\/code>, <code>future<\/code>, <code>private<\/code><\/p>\n<\/li>\n<li>\n<p>Post-Typ und Autor gem\u00e4\u00df den Parametern<\/p>\n<\/li>\n<\/ul>\n<\/li>\n<li>\n<p>Wenn <strong>keine passenden Beitr\u00e4ge<\/strong> gefunden werden \u2192 Ausgabe:<br \/><strong>\u201eKeine passenden Beitr\u00e4ge gefunden.\u201c<\/strong><\/p>\n<\/li>\n<li>\n<p>F\u00fcr <strong>jeden gefundenen Beitrag<\/strong>:<\/p>\n<ul>\n<li>\n<p><code>sdg_fix_empty_array_metas()<\/code> wird aufgerufen.<\/p>\n<\/li>\n<li>\n<p>Es werden Z\u00e4hler mitgef\u00fchrt:<\/p>\n<ul>\n<li>\n<p><code>total<\/code>: Anzahl der gepr\u00fcften Beitr\u00e4ge<\/p>\n<\/li>\n<li>\n<p><code>changed<\/code>: Anzahl der Beitr\u00e4ge, bei denen mindestens ein Feld korrigiert wurde<\/p>\n<\/li>\n<\/ul>\n<\/li>\n<li>\n<p>In einem Bericht wird gespeichert, <strong>welcher Beitrag welche Felder<\/strong> korrigiert bekam, z.B.:<\/p>\n<ul>\n<li>\n<p><code>#123 (date_of_our_event, time_of_the_event)<\/code><\/p>\n<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<\/li>\n<li>\n<p>Am Ende wird eine Zusammenfassung ausgegeben, z.B.:<\/p>\n<ul>\n<li>\n<p><strong>\u201eGepr\u00fcft: 25 Beitrag\/Beitr\u00e4ge. Bereinigt: 7.\u201c<\/strong><\/p>\n<\/li>\n<li>\n<p>Wenn Details vorhanden sind, angeh\u00e4ngt:<br \/><strong>\u201eDetails: #123 (date_of_our_event) | #456 (time_of_the_event, website_of_the_event) | \u2026\u201c<\/strong><\/p>\n<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n<hr \/>\n<h2>4. Typische Anwendungsf\u00e4lle<\/h2>\n<ul>\n<li>\n<p><strong>Punktuelle Reparatur<\/strong> eines einzelnen Problems:<\/p>\n<ul>\n<li>\n<p>Mit <code>[sdg_fix_latest_meta post_type=\"commitment\" scope=\"user\"]<\/code> kann ein Nutzer schnell seinen letzten eigenen Beitrag reparieren (z.B. nach einem Fehler im Formular).<\/p>\n<\/li>\n<\/ul>\n<\/li>\n<li>\n<p><strong>Admin-Wartung nach Bugfix:<\/strong><\/p>\n<ul>\n<li>\n<p>Nachdem klar ist, dass \u00e4ltere Beitr\u00e4ge durch ein Formular oder Plugin-Fehlverhalten falsche Werte (<code>a:0:{}<\/code>) enthalten:<\/p>\n<ul>\n<li>\n<p>Ein Administrator nutzt<br \/><code>[sdg_fix_all_meta post_type=\"commitment\" author=\"\"]<\/code>,<br \/>um <strong>alle betroffenen Beitr\u00e4ge<\/strong> einmalig zu pr\u00fcfen und aufzur\u00e4umen.<\/p>\n<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<\/li>\n<li>\n<p><strong>Gezielte Reparatur nach Autor:<\/strong><\/p>\n<ul>\n<li>\n<p>Z.B. f\u00fcr bestimmte Regionen oder Verantwortliche:<\/p>\n<ul>\n<li>\n<p><code>[sdg_fix_all_meta post_type=\"commitment\" author=\"current\"]<\/code><br \/>\u2192 nur eigene Beitr\u00e4ge<\/p>\n<\/li>\n<li>\n<p><code>[sdg_fix_all_meta post_type=\"commitment\" author=\"17\"]<\/code><br \/>\u2192 alle Beitr\u00e4ge von Autor mit ID 17<\/p>\n<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p>&nbsp;<\/p><\/div>\n\t\t\t<\/div><div id=\"Weiterleitung\" class=\"et_pb_module et_d4_element et_pb_text et_pb_text_3  et_pb_text_align_left et_pb_bg_layout_light\">\n\t\t\t\t\n\t\t\t\t\n\t\t\t\t\n\t\t\t\t\n\t\t\t\t<div class=\"et_pb_text_inner\"><p>&nbsp;<\/p>\n<h2>Weiterleitung<\/h2>\n<p>Dieser Code regelt vier Dinge f\u00fcr die spezielle Nutzerrolle <strong>\u201esdg2033_user\u201c<\/strong>:<\/p>\n<ol>\n<li>\n<p><strong>Bei Registrierung:<\/strong><\/p>\n<ul>\n<li>\n<p>Sprache des Nutzers speichern<\/p>\n<\/li>\n<li>\n<p>Nutzer automatisch auf die passende \u201eFeier-anlegen\u201c-Seite weiterleiten<\/p>\n<\/li>\n<li>\n<p>zus\u00e4tzlich Schreibrechte (Rolle \u201eauthor\u201c) geben<\/p>\n<\/li>\n<\/ul>\n<\/li>\n<li>\n<p><strong>Nach Registrierung \/ erstem Login:<\/strong><\/p>\n<ul>\n<li>\n<p>Nutzer beim ersten Besuch im Frontend automatisch auf die richtige Eingabeseite in seiner Sprache weiterleiten<\/p>\n<\/li>\n<\/ul>\n<\/li>\n<li>\n<p><strong>Backend-Schutz:<\/strong><\/p>\n<ul>\n<li>\n<p>\u201esdg2033_user\u201c-Accounts vom WordPress-Backend fernhalten<\/p>\n<\/li>\n<li>\n<p>aber <strong>Uploads und AJAX<\/strong> (f\u00fcr Formulare etc.) weiterhin erlauben<\/p>\n<\/li>\n<\/ul>\n<\/li>\n<li>\n<p><strong>Admin-Leiste ausblenden:<\/strong><\/p>\n<ul>\n<li>\n<p>Die schwarze WordPress-Admin-Leiste im Frontend f\u00fcr diese Nutzer ausblenden<\/p>\n<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n<p>Damit entsteht f\u00fcr Teilnehmende eine <strong>klare, gef\u00fchrte Frontend-Erfahrung<\/strong>, ohne dass sie mit dem WordPress-Backend in Ber\u00fchrung kommen.<\/p>\n<hr \/>\n<h2>1. Registrierung: Sprache speichern &amp; Redirect-Flag setzen<\/h2>\n<p><strong>Hook:<\/strong> <code>user_register<\/code><\/p>\n<p>Wenn ein neuer Benutzer angelegt wird:<\/p>\n<ol>\n<li>\n<p>Es wird gepr\u00fcft, ob der User die Rolle <strong><code>sdg2033_user<\/code><\/strong> hat.<br \/>Nur dann greift diese Logik.<\/p>\n<\/li>\n<li>\n<p>Der Nutzer bekommt zus\u00e4tzlich die Rolle <strong>\u201eauthor\u201c<\/strong> zugewiesen, falls:<\/p>\n<ul>\n<li>\n<p>er noch nicht \u201eauthor\u201c ist oder<\/p>\n<\/li>\n<li>\n<p>noch keine Upload-Rechte hat.<br \/>\u279c Damit kann er Medien (z.B. Bilder f\u00fcr seine Feier) hochladen, ohne ein volles Backend zu sehen.<\/p>\n<\/li>\n<\/ul>\n<\/li>\n<li>\n<p><strong>Sprache des Nutzers ermitteln:<\/strong><\/p>\n<ul>\n<li>\n<p>Wenn <strong>WPML<\/strong> aktiv ist, wird zuerst die aktuelle WPML-Sprache abgefragt.<\/p>\n<\/li>\n<li>\n<p>Falls das leer ist, wird die Sprache aus dem System-Locale ermittelt (z.B. <code>de_DE<\/code> \u2192 <code>de<\/code>).<\/p>\n<\/li>\n<li>\n<p>Es werden immer nur die ersten zwei Buchstaben verwendet (z.B. <code>de<\/code>, <code>en<\/code>, <code>sq<\/code>).<\/p>\n<\/li>\n<\/ul>\n<\/li>\n<li>\n<p>Diese Sprache wird in einem User-Meta-Feld gespeichert:<\/p>\n<ul>\n<li>\n<p><code>sdg2033_lang<\/code> = Sprachcode (z.B. <code>de<\/code>, <code>en<\/code>)<\/p>\n<\/li>\n<\/ul>\n<\/li>\n<li>\n<p>Zus\u00e4tzlich wird ein Flag gesetzt:<\/p>\n<ul>\n<li>\n<p><code>sdg2033_needs_redirect = '1'<\/code><br \/>\u279c Kennzeichnet, dass der Nutzer nach der Registrierung \/ beim ersten Login <strong>automatisch weitergeleitet<\/strong> werden soll.<\/p>\n<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n<hr \/>\n<h2>2. Ziel-URL je nach Sprache bestimmen<\/h2>\n<p><strong>Funktion:<\/strong> <code>sdg2033_get_redirect_url_for_user(WP_User $user)<\/code><\/p>\n<p>Diese Funktion berechnet, wohin ein Nutzer weitergeleitet werden soll.<\/p>\n<ol>\n<li>\n<p>Zuerst wird die gespeicherte Sprache <code>sdg2033_lang<\/code> geladen.<\/p>\n<\/li>\n<li>\n<p>Wenn sie fehlt:<\/p>\n<ul>\n<li>\n<p>wird erneut eine sinnvolle Sprache aus WPML oder den Locale-Einstellungen ermittelt,<\/p>\n<\/li>\n<li>\n<p>gespeichert,<\/p>\n<\/li>\n<li>\n<p>und auf zwei Zeichen gek\u00fcrzt.<\/p>\n<\/li>\n<\/ul>\n<\/li>\n<li>\n<p>Standard-Ziel ist die <strong>englische Seite<\/strong>:<\/p>\n<ul>\n<li>\n<p><code>https:\/\/sdg2033.world\/commit\/<\/code><\/p>\n<\/li>\n<\/ul>\n<\/li>\n<li>\n<p>F\u00fcr <strong>Deutsch<\/strong> gibt es eine feste Zielseite:<\/p>\n<ul>\n<li>\n<p><code>https:\/\/sdg2033.world\/de\/feier-hinzufuegen\/<\/code><\/p>\n<\/li>\n<\/ul>\n<\/li>\n<li>\n<p>F\u00fcr andere Sprachen mit WPML:<\/p>\n<ul>\n<li>\n<p>Wird die englische Basis-URL <code>https:\/\/sdg2033.world\/commit\/<\/code> \u00fcber WPML (<code>wpml_permalink<\/code>) in die passende Sprach-URL umgewandelt.<br \/>Beispiel: <code>\u2026\/es\/commit\/<\/code>, <code>\u2026\/sq\/commit\/<\/code> etc., je nach Konfiguration.<\/p>\n<\/li>\n<\/ul>\n<\/li>\n<li>\n<p>Falls WPML nicht verf\u00fcgbar ist:<\/p>\n<ul>\n<li>\n<p>wird einfach die englische Basis-URL verwendet.<\/p>\n<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n<p><strong>Kurz:<\/strong><br \/>Die Funktion sorgt daf\u00fcr, dass jede*r <code>sdg2033_user<\/code> beim ersten Aufruf auf die <strong>richtige \u201eFeier hinzuf\u00fcgen\u201c- bzw. \u201eCommit\u201c-Seite<\/strong> in der eigenen Sprache kommt.<\/p>\n<hr \/>\n<h2>3. Redirect nach Registrierung \/ erstem Login (Frontend)<\/h2>\n<p><strong>Hook:<\/strong> <code>template_redirect<\/code><\/p>\n<p>Bei jedem Frontend-Aufruf wird gepr\u00fcft:<\/p>\n<ol>\n<li>\n<p><strong>Ist der User eingeloggt?<\/strong><br \/>Wenn nein \u2192 nichts tun.<\/p>\n<\/li>\n<li>\n<p><strong>Ist es Backend?<\/strong><br \/>F\u00fcr Backend (<code>is_admin() == true<\/code>) wird in diesem Hook nichts gemacht.<\/p>\n<\/li>\n<li>\n<p>Der eingeloggte Nutzer wird geladen.<br \/>Wenn:<\/p>\n<ul>\n<li>\n<p>er <strong>nicht<\/strong> die Rolle <code>sdg2033_user<\/code> hat<br \/><strong>oder<\/strong><\/p>\n<\/li>\n<li>\n<p>er <strong>Admin-Rechte<\/strong> hat (<code>manage_options<\/code>)<\/p>\n<\/li>\n<\/ul>\n<p>\u279c keine Umleitung.<\/p>\n<\/li>\n<li>\n<p>Es wird gepr\u00fcft, ob das Redirect-Flag gesetzt ist:<\/p>\n<ul>\n<li>\n<p><code>sdg2033_needs_redirect == '1'<\/code><br \/>Nur dann erfolgt eine Weiterleitung.<\/p>\n<\/li>\n<\/ul>\n<\/li>\n<li>\n<p>Ist das Flag gesetzt:<\/p>\n<ul>\n<li>\n<p>Ziel-URL wird \u00fcber <code>sdg2033_get_redirect_url_for_user()<\/code> ermittelt.<\/p>\n<\/li>\n<li>\n<p>Flag wird auf <code>0<\/code> gesetzt, damit der Redirect <strong>nur einmalig<\/strong> passiert.<\/p>\n<\/li>\n<li>\n<p>Der Nutzer wird mit <code>wp_safe_redirect()<\/code> auf die Zielseite umgeleitet.<\/p>\n<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n<p><strong>Ergebnis:<\/strong><br \/>Direkt nach Registrierung \/ erstem Login landet ein SDG2033-Nutzer automatisch auf der passenden <strong>Feier-Anlegen-Seite<\/strong> in seiner Sprache \u2013 aber eben nur <strong>einmal<\/strong>, nicht bei jedem Seitenaufruf.<\/p>\n<hr \/>\n<h2>4. Backend-Zugriff blockieren (ohne Uploads zu st\u00f6ren)<\/h2>\n<p><strong>Hook:<\/strong> <code>admin_init<\/code><\/p>\n<p>Ziel: <code>sdg2033_user<\/code> <strong>sollen nicht ins WordPress-Backend<\/strong>, aber ihre Formulare und Datei-Uploads sollen trotzdem funktionieren.<\/p>\n<p>Die Logik:<\/p>\n<ol>\n<li>\n<p>Nur bei eingeloggten Usern aktiv.<\/p>\n<\/li>\n<li>\n<p><strong>AJAX-Aufrufe<\/strong> (<code>wp_doing_ajax()<\/code>) werden <strong>durchgelassen<\/strong><br \/>\u279c wichtig f\u00fcr Formularfunktionen und technische Prozesse.<\/p>\n<\/li>\n<li>\n<p>Der Spezialfall <code>async-upload.php<\/code> (Media-Upload) wird ebenfalls <strong>nicht blockiert<\/strong>, damit Nutzer Bilder \u00fcber Frontend-Formulare hochladen k\u00f6nnen.<\/p>\n<\/li>\n<li>\n<p>Nur wenn <code>is_admin()<\/code> (also im Backend) wird weiter gepr\u00fcft.<\/p>\n<\/li>\n<li>\n<p>Der aktuelle User wird geladen.<\/p>\n<\/li>\n<li>\n<p>Wenn:<\/p>\n<ul>\n<li>\n<p>er keine <code>sdg2033_user<\/code>-Rolle hat<br \/><strong>oder<\/strong><\/p>\n<\/li>\n<li>\n<p>er Admin-Rechte (<code>manage_options<\/code>) hat<\/p>\n<\/li>\n<\/ul>\n<p>\u279c keine Umleitung (z.B. f\u00fcr normale Admins).<\/p>\n<\/li>\n<li>\n<p>F\u00fcr SDG-User ohne Admin-Rechte:<\/p>\n<ul>\n<li>\n<p>Ziel-URL wird \u00fcber <code>sdg2033_get_redirect_url_for_user()<\/code> ermittelt.<\/p>\n<\/li>\n<li>\n<p>Der Nutzer wird mit <code>wp_safe_redirect()<\/code> ins Frontend umgeleitet.<\/p>\n<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n<p><strong>Praxis-Effekt:<\/strong><br \/>Teilnehmende mit <code>sdg2033_user<\/code>-Accounts k\u00f6nnen Inhalte einreichen, aber das klassische WordPress-Dashboard bleibt ihnen verborgen. Sie bleiben immer im <strong>Frontend-Workflow<\/strong>.<\/p>\n<hr \/>\n<h2>5. Admin-Bar im Frontend ausblenden<\/h2>\n<p><strong>Hook:<\/strong> <code>after_setup_theme<\/code><\/p>\n<p>Im letzten Schritt wird f\u00fcr SDG-User die <strong>WordPress-Adminbar<\/strong> im Frontend deaktiviert:<\/p>\n<ul>\n<li>\n<p>Wenn <code>current_user_can('sdg2033_user')<\/code> erf\u00fcllt ist, wird <code>show_admin_bar(false)<\/code> aufgerufen.<\/p>\n<\/li>\n<\/ul>\n<p>Ziel ist hier vor allem:<\/p>\n<ul>\n<li>\n<p>die Benutzeroberfl\u00e4che <strong>klar und \u201enicht-technisch\u201c<\/strong> zu halten,<\/p>\n<\/li>\n<li>\n<p>keine verwirrenden Backend-Elemente anzuzeigen.<\/p>\n<\/li>\n<\/ul>\n<hr \/>\n<h2>Zusammenfassung f\u00fcr Externe<\/h2>\n<ul>\n<li>\n<p><strong>Zielgruppe:<\/strong> Nutzerrolle <code>sdg2033_user<\/code> (Teilnehmende, die Feiern \/ Commitments eintragen).<\/p>\n<\/li>\n<li>\n<p><strong>Nutzen:<\/strong><\/p>\n<ul>\n<li>\n<p>Automatische <strong>Spracherkennung und Weiterleitung<\/strong> auf die passende Eingabeseite.<\/p>\n<\/li>\n<li>\n<p>Klare Trennung:<\/p>\n<ul>\n<li>\n<p><strong>Frontend<\/strong> f\u00fcr Teilnehmende<\/p>\n<\/li>\n<li>\n<p><strong>Backend<\/strong> nur f\u00fcr Admins und Redakteure<\/p>\n<\/li>\n<\/ul>\n<\/li>\n<li>\n<p>Keine unn\u00f6tige Komplexit\u00e4t f\u00fcr Endnutzer (kein Dashboard, keine Admin-Leiste).<\/p>\n<\/li>\n<\/ul>\n<\/li>\n<\/ul><\/div>\n\t\t\t<\/div>\n\t\t\t<\/div>\n\t\t\t\t\n\t\t\t\t\n\t\t\t\t\n\t\t\t\t\n\t\t\t<\/div>\n\t\t\t\t\n\t\t\t\t\n\t\t\t<\/div>\n","protected":false},"excerpt":{"rendered":"","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"_acf_changed":false,"_et_pb_use_builder":"on","_et_pb_old_content":"","_et_gb_content_width":"","footnotes":""},"class_list":["post-4827","page","type-page","status-publish","hentry"],"acf":[],"_links":{"self":[{"href":"https:\/\/sdg2033.world\/sq\/wp-json\/wp\/v2\/pages\/4827","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/sdg2033.world\/sq\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/sdg2033.world\/sq\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/sdg2033.world\/sq\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/sdg2033.world\/sq\/wp-json\/wp\/v2\/comments?post=4827"}],"version-history":[{"count":0,"href":"https:\/\/sdg2033.world\/sq\/wp-json\/wp\/v2\/pages\/4827\/revisions"}],"wp:attachment":[{"href":"https:\/\/sdg2033.world\/sq\/wp-json\/wp\/v2\/media?parent=4827"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}