OW Consent — Dokumentation
Vollständiges Einwilligungsmanagement in WordPress: Banner für mehrere Rechtsräume, Tracker-Blockade, Scanner, Rechtstexte, Nachweisprotokoll und Portal für Betroffenenrechte. Autor: OptionWeb — Julien Daniel Plugin-Startseite: https://optionweb.dev/de/addons/ow-consent/ Lizenz: GPL-2.0-or-later Dieses Dokument deckt Version 1.4.3 ab.
Inhaltsverzeichnis
- Überblick
- Installation
- Schnellstart
- Die elf Compliance-Profile
- Die Cookie-Kategorien
- Das Banner
- Die automatische Blockade
- Der Tracker-Scanner
- Der Generator für Rechtstexte
- Das Einwilligungsprotokoll
- Das Portal für Betroffenenrechte (DSAR)
- Das CCPA-Opt-out „Do Not Sell or Share“
- Google Consent Mode v2
- IAB TCF v2.2
- Global Privacy Control
- Die regionale Erkennung
- Die OW Forms-Integration
- Der schwebende Button
- Shortcodes
- REST API
- Einstellungsreferenz
- Fehlerbehebung
- FAQ
Überblick
OW Consent ist eine Suite für das Einwilligungsmanagement in WordPress. Sie deckt die ganze Kette ab: eine Wahl anzeigen, sie auf die Tracker tatsächlich anwenden, sie nachweisbar festhalten, die erklärenden Dokumente veröffentlichen und Anfragen betroffener Personen entgegennehmen.
Elf Compliance-Profile werden mitgeliefert — von der DSGVO über das kalifornische CCPA und die Loi 25 aus Québec bis zum brasilianischen LGPD oder zum indischen DPDP. Das aktive Profil entscheidet über das Einwilligungsmodell (Opt-in oder Opt-out), über die Standardwerte von Google Consent Mode, über den Text der erzeugten Dokumente, über die veröffentlichten Betroffenenrechte und über die genannte Aufsichtsbehörde.
Alles bleibt auf Ihrer Website. Das Plugin kontaktiert genau einen externen Dienst, die Global Vendor List von IAB Europe, und auch nur dann, wenn Sie das TCF-Modul aktivieren, das standardmäßig ausgeschaltet ist. Keine Telemetrie, kein Konto, kein Abo.
Verträglich mit einem vollständigen Page-Cache, von Grund auf
Das ist die architektonische Entscheidung, aus der alles andere folgt. Nichts von dem, was der Server rendert, hängt vom Einwilligungs-Cookie ab. Das HTML ist für alle Besucher identisch: Tracker werden für jeden zu inerten Tags umgeschrieben, und erst ein JavaScript-Runtime gibt sie im Browser frei, Kategorie für Kategorie, indem es das Cookie vor dem ersten Rendern liest.
Praktische Folge: LiteSpeed Cache, WP Rocket, Varnish oder ein CDN können die Wahl des einen
Besuchers nicht an einen anderen ausliefern. Nur wirklich personenbezogene Antworten — die
Seite zur Identitätsbestätigung einer Betroffenenanfrage, REST-Antworten mit Daten des
Besuchers — werden ausdrücklich als nicht cachebar markiert. Auch kein Nonce wird in
cachebares HTML gedruckt: Das Banner holt sich vor jedem Schreibvorgang ein frisches über
einen no-store-Endpunkt.
Was mitgeliefert wird
- Consent-Banner: vier Positionen, Theme hell / dunkel / automatisch, „Alle ablehnen“ genauso sichtbar wie „Alle akzeptieren“, tastaturbedienbares Präferenz-Panel, vollständig übersetzbar.
- Automatische Tracker-Blockade: Skripte, Inline-Snippets, iframes, Pixel,
Ressourcen-Hints (
preconnect,dns-prefetch,preload), Analytics- und Marketing-Stylesheets sowie Drittanbieter-Medien, auf Basis von 175 Signaturen, die mitgeliefert und editierbar sind. - Tracker-Scanner: Durchlauf durch Ihre eigenen Seiten per WP-Cron, Auswertung der
Set-Cookie-Header, Browser-Sonde nur für Administratoren, und ein Panel, das immer sagt, was der Durchlauf tatsächlich abgedeckt hat. - Generator für Rechtstexte: Datenschutzerklärung und Cookie-Richtlinie für alle elf Profile, in der Sprache der Jurisdiktion; Impressum und AGB auf Französisch.
- Einwilligungsprotokoll: jede Aktion an eine per HMAC verkettete Tabelle angehängt, mit dem geltenden Profil, dem Fingerabdruck der veröffentlichten Dokumente und dem Fingerabdruck des tatsächlich angezeigten Banners.
- Portal für Betroffenenrechte (DSAR): Formular per Shortcode, E-Mail-Verifizierung, Frist nach Artikel 12 Abs. 3 ab der Identitätsbestätigung, Anbindung an den nativen Exporter und Eraser von WordPress.
- Google Consent Mode v2, IAB TCF v2.2, Global Privacy Control, regionale Erkennung, OW Forms-Integration: jedes einzeln aktivierbar.
- Vollständige REST API unter dem Namespace
owc/v1.
Was es nicht tut — bitte vorher lesen
Bei einem Rechtsthema schadet ein zu großes Versprechen Ihnen genauso wie dem Hersteller. Hier sind die Grenzen, so wie sie im Code stehen.
- Die erzeugten Dokumente sind Vorlagen, keine Rechtsberatung. Jedes Dokument endet mit einem Hinweis, der genau das sagt, und dieser Hinweis ist standardmäßig aktiv. Lassen Sie Ihre Dokumente prüfen, bevor Sie sie veröffentlichen.
- Das TCF-Modul ist keine bei IAB Europe registrierte CMP. Es verlangt eine CMP-ID, die Sie selbst beschaffen müssen, es bietet keine Auswahl auf Anbieterebene, und Anbieter dürfen sein Signal zurückweisen. Wenn Werbeerlöse unter TCF für Sie zählen, nutzen Sie eine zertifizierte CMP.
- Das Protokoll ist nur unter einer Bedingung fälschungssicher. Die Kette ist nur dann ein Nachweis, wenn ihr Signaturschlüssel außerhalb der Datenbank liegt. Das Plugin erkennt den gegenteiligen Fall, meldet ihn selbst und sagt es Ihnen im Backend, statt das Gegenteil zu behaupten.
- Der Scanner führt kein JavaScript aus. Er sieht, was Ihr HTML enthält und was Ihre
Set-Cookie-Header setzen; was ein Tag-Manager zur Laufzeit einschleust, sieht nur eine Sonde, die angemeldeten Administratoren vorbehalten ist. - Die Standardblockade ist nicht „alles, was von Dritten kommt“. Ein unbekanntes Drittanbieter-Skript ist standardmäßig erlaubt; unbekannte iframes werden dagegen standardmäßig blockiert. Die Blockade stützt sich auf den Signaturkatalog, den Sie erweitern können.
- Ohne JavaScript kann keine Wahl erfasst werden. Der Besucher sieht einen
<noscript>-Block, und nichts Nicht-Notwendiges wird geladen — aber es wird auch nichts erfasst. - Keine Granularität nach US-Bundesstaat und keine nach kanadischer Provinz in der
regionalen Erkennung: Das gesamte US-Gebiet bekommt das Profil
ccpa, ganz Kanada bekommtquebec. - Impressum und AGB gibt es nur auf Französisch. Für jede Jurisdiktion, deren Zielsprache nicht Französisch ist, verweigert der Generator diese beiden Dokumente, statt einen unpassenden Text zu veröffentlichen.
- Keine eigene Rolle: Das gesamte Backend verlangt die Berechtigung
manage_options.
Diese Liste ist eine bewusste Entscheidung, keine versteckte Roadmap. Bei Compliance ist ein Werkzeug, das seine Lücken benennt, mehr wert als eines, das sie verbirgt.
Installation
Aus der ZIP-Datei
- Laden Sie
ow-consent-1.4.3.zipvon https://optionweb.dev/de/addons/ow-consent/ - Plugins → Installieren → Plugin hochladen
- Datei wählen, auf Jetzt installieren klicken, dann auf Aktivieren
Per FTP
Entpacken Sie das Archiv und legen Sie den Ordner ow-consent in /wp-content/plugins/,
dann aktivieren Sie das Plugin unter Plugins.
Voraussetzungen
- WordPress 6.2 oder neuer — das ist eine Startverweigerung, keine Empfehlung (siehe unten)
- PHP 7.4 oder neuer
- MySQL 5.7+ / MariaDB 10.2+
- Funktionierendes WP-Cron, wenn Sie den Scanner, die Protokollaufbewahrung, die DSAR-Fristerinnerungen oder das TCF-Modul nutzen
Die WordPress-6.2-Sicherung. Seit 1.3.0 wird jeder Tabellenbezeichner über den Platzhalter
%ivonwpdb::prepare()gebunden, den WordPress erst ab 6.2 versteht. Auf einem älteren Core würdeprepare()einen leeren String zurückgeben, der Tracker-Katalog würde sich stillschweigend zu einer leeren Menge auflösen, und das Banner würde dem Besucher weiterhin eine Blockade versprechen, die nicht stattfindet. Das Plugin verweigert deshalb den Start und zeigt eine Fehlermeldung, die ausdrücklich sagt, dass nichts blockiert und keine Einwilligung erfasst wird. Der HeaderRequires at leastverhindert die Aktivierung unterhalb von 6.2 bereits, deckt aber weder ein Downgrade des Cores unter einer laufenden Installation noch eine per FTP abgelegte Kopie ab.
Was installiert wird
Bei der Aktivierung legt OW Consent vier Tabellen an:
| Tabelle | Inhalt |
|---|---|
{prefix}owc_ledger | Das Einwilligungsprotokoll, per Hash verkettet |
{prefix}owc_dsar | Die Betroffenenanfragen |
{prefix}owc_scanner | Die Funde des Tracker-Scanners |
{prefix}owc_scripts | Der Signaturkatalog, den die Blockade nutzt |
Eine fünfte Tabelle, {prefix}owc_form_links, wird separat von der OW Forms-Integration
angelegt, wenn das Schwester-Plugin aktiv ist (siehe Die OW Forms-Integration).
Die Aktivierung ergänzt außerdem:
- die Option
owc_settings, absichtlich leer angelegt: Solange Sie nichts gespeichert haben, stammen alle Texte aus den englischen Standardwerten, die zur Laufzeit in die Sprache der Website übersetzt werden — statt die Locale derjenigen Person in der Datenbank festzuschreiben, die das Plugin aktiviert hat; - die Option
owc_version; - den mitgelieferten Tracker-Katalog (
data/tracker-catalog.json), in Paketen zu 100 perINSERT IGNOREeingefügt, mit einem Seed-Flag pro Version (owc_catalog_seeded_1.4.3); - die tägliche Aufgabe
owc_daily_maintenance, geplant für eine Stunde nach der Aktivierung.
Fünf weitere Cron-Ereignisse werden von den Modulen scharf geschaltet, die sie nutzen. Die
sechs Cron-Hooks des Plugins sind: owc_scanner_run, owc_scanner_run_batch,
owc_ledger_retention, owc_tcf_refresh_gvl, owc_run_upgrade und
owc_daily_maintenance.
Im Multisite-Betrieb werden die Tabellen pro Website angelegt, niemals geteilt
(wp_2_owc_ledger usw.). Eine netzwerkweite Aktivierung geht alle Websites durch, aber nur
wenn das Netzwerk höchstens 200 Websites umfasst; darüber wird jede Website beim ersten
Aufruf verzögert bereitgestellt. Eine Unterwebsite, die nach einer Netzwerkaktivierung
entsteht, wird über den Hook wp_initialize_site bereitgestellt.
Was in wp-config.php gehört
Keine dieser Konstanten ist Pflicht, aber zwei davon verändern den Beweiswert dessen, was das Plugin produziert.
// Empfohlen: holt den Signaturschlüssel des Protokolls aus der Datenbank heraus.
define( 'OWC_LEDGER_KEY', 'eine lange Zufallszeichenkette, nur für diese Website' );
// Empfohlen: die üblichen WordPress-Salts. Ohne sie speichert WordPress sie in der
// Datenbank, und das Protokoll meldet sich selbst als nicht fälschungssicher.
define( 'AUTH_KEY', '…' );
define( 'AUTH_SALT', '…' );
// Falls die Website hinter einem CDN, einem Load Balancer oder einem Reverse Proxy läuft.
// Ohne diese Konstante werden CF-Connecting-IP, X-Forwarded-For und X-Real-IP IGNORIERT
// und nur REMOTE_ADDR verwendet — womit alle Ihre Besucher für die Rate-Limitierung
// dieselbe Identität bekommen.
define( 'OWC_TRUSTED_PROXY', '198.51.100.0/24, 2001:db8::/32' );
// `OWC_TRUSTED_PROXIES` wird als Alias akzeptiert; ein String oder ein Array geht beides.
// Nur für die regionale Erkennung: legt fest, welchen Länder-Headern zu trauen ist.
define( 'OWC_GEO_TRUSTED_HEADERS', 'cloudflare' ); // 'cloudflare'|'cloudfront'|'proxy'|'all'
define( 'OWC_BEHIND_CLOUDFLARE', true );
define( 'OWC_BEHIND_CLOUDFRONT', true );
OWC_LEDGER_KEY dient auch dazu, den Schlüssel des Cookies für die regionale Erkennung
abzuleiten. Ist die Konstante nicht definiert, fällt der Protokollschlüssel auf
wp_salt('auth') zurück.
Wer Zugriff hat
Das gesamte Backend des Plugins und alle administrativen REST-Routen verlangen die
Berechtigung manage_options. Es gibt weder eine eigene Rolle noch eine feinere
Berechtigung: Wem Sie den Plugin-Bildschirm öffnen, dem geben Sie die Einstellungen der
gesamten Website.
Der Update-Pfad
Das Plugin migriert sein Schema niemals im laufenden Betrieb auf einem anonymen Seitenaufruf.
Wenn sich die Version ändert, werden owc_version und ein Flag owc_pending_upgrade sofort
geschrieben, dann gilt:
- Die Migration läuft inline, wenn die Anfrage eine Backend-Anfrage außerhalb von AJAX, ein Cron-Lauf oder ein WP-CLI-Befehl ist;
- andernfalls wird ein Ereignis
owc_run_upgradefünf Sekunden später eingeplant.
admin-ajax.php gilt als anonyme Anfrage: Das ist ein öffentlicher Einstiegspunkt. Die
Migration läuft unter einer Sperre (owc_upgrade_lock, nach 300 Sekunden übernehmbar), und
ein Auffangnetz auf admin_init fängt Websites ab, auf denen WP-Cron deaktiviert ist. Bei
unveränderter Version kostet das Ganze genau ein get_option().
Deaktivieren und Löschen
Deaktivieren bewahrt alle Daten und löscht nur die sechs Cron-Ereignisse. Bei einer netzwerkweiten Deaktivierung werden alle Websites in Paketen zu 200 durchlaufen — anders als bei der Aktivierung —, weil ein scharf gebliebener Cron sonst nie wieder verschwinden würde.
Löschen des Plugins löst uninstall.php aus, das in zwei Schritten vorgeht:
- Immer, unabhängig von Ihrer Einstellung: Die sechs Crons werden gelöscht und die
Tabelle
{prefix}owc_dsarwird entfernt, samt ihrer Rate-Limit-Transients. Sie ist die einzige Tabelle, die direkt identifizierende personenbezogene Daten Dritter enthält (E-Mail-Adresse, Name, Freitext); sobald das Plugin weg ist, begrenzt nichts mehr ihre Aufbewahrung, und kein Bildschirm erlaubt es noch, darauf zu antworten, sie zu exportieren oder zu löschen. Exportieren Sie die Anfragen, die Sie behalten müssen, bevor Sie das Plugin löschen. - Nur wenn
delete_data_on_uninstallausdrücklich aktiviert ist: Löschung der Tabellenowc_ledger,owc_dsar,owc_scanner,owc_scriptsundowc_form_links, der benannten Optionen, aller Optionen mit dem Präfixowc_(inklusive Transients) und derusermetamit dem Präfixowc_. Im Multisite-Betrieb folgen die Netzwerkoptionen der Entscheidung der Hauptwebsite.
Diese Einstellung ist standardmäßig deaktiviert: Der Einwilligungsnachweis, den Artikel 7 Abs. 1 DSGVO verlangt, überlebt die Löschung des Plugins.
Schnellstart
Öffnen Sie nach der Aktivierung den Eintrag OW Consent in der Seitenleiste des Backends. Das gesamte Plugin liegt auf diesem einen Bildschirm, in zehn Tabs: Dashboard, Banner, Compliance, Legal identity, Categories, Policies, Scanner, Tracker catalogue, Audit ledger, DSAR requests.
Ein Speichervorgang betrifft nur den geöffneten Tab. Das ist Absicht: Jeder Boolean hat ein verstecktes Zwillingsfeld, und ein im Formular fehlender Schlüssel bedeutet „dieses Feld liegt auf einem anderen Tab“, niemals „abgewählt“. Ohne das würde das Speichern eines Tabs die Einstellungen aller anderen überschreiben.
1. Wählen Sie Ihr Compliance-Profil
Tab Compliance. Das Profil entscheidet über das Einwilligungsmodell, über die
Standardwerte von Consent Mode, über die erzeugten Dokumente und über die veröffentlichten
Betroffenenrechte. Standard: gdpr.
compliance_strict ist standardmäßig aktiv: Das ist es, was die Blockade über die von
WordPress registrierten Skripte hinaus ausdehnt. Lassen Sie es an, wenn iframes, Pixel und
fest in Ihrem Theme stehende Skripte behandelt werden sollen.
2. Füllen Sie die rechtliche Identität aus
Tab Legal identity. Diese Felder sind der Rohstoff der erzeugten Dokumente, und die Erzeugung wird verweigert, solange ein Pflichtfeld leer ist — mit der Liste der fehlenden Schlüssel, nicht als stiller Fehlschlag.
Minimum für alle Dokumente: legal_company_name und legal_company_email. Für alles außer
der Cookie-Richtlinie kommen Anschrift und Land dazu. Für das Impressum zusätzlich Telefon,
verantwortliche Person für die Veröffentlichung und die vollständigen Kontaktdaten des
Hosters; in Frankreich, Belgien und Luxemburg werden außerdem Rechtsform und
Registernummer zur Pflicht.
Lassen Sie legal_dpa_authority leer: Die Aufsichtsbehörde wird aus Ihrem Land und Ihrem
Profil abgeleitet. Sie auf einer Website mit mehreren Jurisdiktionen von Hand einzutragen,
läuft darauf hinaus, die falsche Behörde zu nennen.
3. Prüfen Sie Ihre Kategorien
Tab Categories. Die sechs Kategorien sind standardmäßig verfügbar. Schalten Sie die
ab, die Ihre Website nicht nutzt: Eine Kategorie, die in der Oberfläche fehlt, ist kein
Compliance-Gewinn, sondern eine für immer blockierte Ressource ohne Schalter, um sie
freizugeben — die Blockade schiebt sie dann auf marketing.
Lassen Sie die Bezeichnungen leer, solange sie Ihnen passen: Sie folgen dann der Sprache der Website. Sobald Sie einen Text anpassen, folgt dieser Text der Sprache nicht mehr.
4. Stellen Sie das Banner ein
Tab Banner. Position, Theme, Buttons, Beschriftungen, Erneuerungsdauer.
Zwei Punkte, die Sie nicht übersehen sollten: Lassen Sie banner_reject_all aktiv
(„Ablehnen“ muss genauso einfach und sichtbar sein wie „Akzeptieren“), und lassen Sie das
Schließkreuz deaktiviert — es fehlt standardmäßig, weil ein Schließen ohne Wahl einer
stillschweigenden Ablehnung gleichkommt. Wenn Sie es aktivieren, führt ein Klick auf das
Kreuz den vollständigen Pfad „Alle ablehnen“ aus, niemals ein stilles Schließen.
5. Erzeugen Sie Ihre Dokumente
Tab Policies. Vier Dokumente: Cookie-Richtlinie, Datenschutzerklärung, Impressum, AGB. Jedes wird zu einer versionierten WordPress-Seite, deren Link in die Einstellungen zurückgeschrieben wird.
Erzeugen Sie zuerst als Vorschau, lesen Sie gegen, veröffentlichen Sie dann. Und lassen Sie fachlich prüfen: Der Hinweisblock am Ende jedes Dokuments ist keine Dekoration.
6. Öffnen Sie das Portal für Betroffenenrechte
Legen Sie eine Seite an und setzen Sie [owc_dsar_form] hinein. Tragen Sie dsar_email im
Tab DSAR requests ein: Das ist die unter dem Formular veröffentlichte Kontaktadresse und
der Empfänger der Benachrichtigungen. Ohne sie fällt das Plugin auf legal_dpo_email zurück,
dann auf admin_email — aber admin_email wird nie auf einer öffentlichen Seite
veröffentlicht.
7. Prüfen Sie, bevor Sie öffentlich gehen
Das Dashboard führt fünfzehn Compliance-Prüfungen aus und unterscheidet Fehler von Warnungen: Banner deaktiviert, „Alle ablehnen“ fehlt, Schließkreuz aktiviert, rechtliche Identität unvollständig, Portal für Betroffenenrechte geschlossen, Protokoll deaktiviert, keine Rechtstexte verlinkt, Aufsichtsbehörde im Widerspruch zum aktiven Profil (mit einem Button „Fix this“, der sie zurücksetzt), Website nicht auf HTTPS, nicht kategorisierte Tracker, überfällige DSAR-Anfragen, Katalogregeln, die nicht greifen können.
Bringen Sie diese fünfzehn Zeilen auf Grün, bevor Sie erklären, Ihre Website sei konform.
Die elf Compliance-Profile
Das Compliance-Profil ist nicht kosmetisch. Es steuert das Rechtsmodell, die Oberfläche, die technischen Signale und den Inhalt der veröffentlichten Dokumente.
Die Liste
| Profil | Angesprochener Rechtsrahmen | Modell |
|---|---|---|
gdpr | DSGVO + ePrivacy (EU/EWR) | Opt-in |
uk_pecr | UK GDPR + PECR (Vereinigtes Königreich) | Opt-in |
ch_nfadp | Schweizer revDSG | Opt-in |
quebec | Loi 25 (Québec) | Opt-in |
lgpd | LGPD (Brasilien) | Opt-in |
popia | POPIA (Südafrika) | Opt-in |
pipl | PIPL (China) | Opt-in |
dpdp | DPDP Act 2023 (Indien) | Opt-in |
ccpa | CCPA / CPRA (Kalifornien) | Opt-out |
us_generic | Allgemeine US-Bundesstaatengesetze | Opt-out |
au | Privacy Act (Australien) | Opt-out |
Einstellung: compliance_profile, Standard gdpr.
Opt-in bedeutet, dass vor jeder Wahl nur die erzwungenen Kategorien freigegeben sind.
Opt-out bedeutet, dass alles freigegeben ist, bis widersprochen wird. Die drei
Opt-out-Profile sind ccpa, us_generic und au. Das JavaScript-Runtime wendet exakt
dieselbe Regel an wie PHP, sodass Server und Browser nicht zwei verschiedene Zustände melden
können.
Was das Profil wirklich verändert
| Was sich ändert | Detail |
|---|---|
| Einwilligungsmodell | Opt-in, außer bei ccpa, us_generic, au |
| Standardwerte von Consent Mode | Unter einem Opt-out-Profil stehen alle sieben Signale auf granted |
| „Do Not Sell or Share“-Link vorgeschrieben | Nur ccpa und us_generic |
| GPC rechtlich bindend | Nur ccpa und us_generic — Australien ist ausdrücklich ausgenommen: Opt-out-Rahmen, der GPC aber nicht anerkennt |
| Geltungsbereich „die DSGVO gilt“ für TCF | 27 EU-Länder + IS, LI, NO + GB + CH, also 31 Codes |
| Sprache des erzeugten Dokuments | quebec → Französisch; lgpd → Portugiesisch; gdpr mit Land FR, BE oder LU → Französisch; alles Übrige → Englisch |
| Genannte Aufsichtsbehörde | Tabelle je Profil, für die DSGVO nach Land verfeinert |
| Veröffentlichte Liste der Betroffenenrechte | Eine je Profil formulierte Liste, mit Artikelangabe |
| Abschnitt „Cookie-Regime“ des englischen Dokuments | Text, Übermittlungsumfang und Garantien je Profil unterschiedlich |
Die je Profil erzeugten Dokumente
Datenschutzerklärung und Cookie-Richtlinie existieren für alle elf Profile. Die Vorlagen
werden in dieser Reihenfolge aufgelöst, der erste Treffer gewinnt:
<typ>_<profil>_<sprache>, dann <typ>_<profil>, dann <typ>_<sprache>, dann <typ>.
Die englischen Textkörper der Cookie-Richtlinie sind profilbewusst: anwendbare Regel,
Übermittlungsumfang, Garantien und Panel-Beschriftung unterscheiden sich für gdpr,
uk_pecr, ch_nfadp, au, pipl, dpdp, ccpa und us_generic, jeweils mit den
passenden Fundstellen (Art. 5 Abs. 3 der Richtlinie 2002/58, PECR reg. 6, Art. 45c(b) FMG
und Art. 19/6 Abs. 7 lit. b revDSG, APP 8, Art. 24 PIPL, Sections 5/6/7/9(3)/16 des DPDP Act
2023, §1798.121 und Cal. Code Regs. tit. 11 §7025, VCDPA/CPA/CTDPA/UCPA/TDPSA).
Genannte Aufsichtsbehörde
| Profil | Genannte Behörde |
|---|---|
gdpr, Land FR | CNIL |
gdpr, Land BE | APD-GBA |
gdpr, Land LU | CNPD |
gdpr, Land DE | BfDI |
gdpr, anderes EWR-Land | Allgemeine Formulierung („die zuständige Aufsichtsbehörde“) |
uk_pecr | ICO |
ch_nfadp | EDÖB / FDPIC |
quebec | Commission d'accès à l'information |
lgpd | ANPD |
ccpa | California Privacy Protection Agency |
popia | Information Regulator (South Africa) |
pipl | Cyberspace Administration of China |
dpdp | Data Protection Board of India |
au | OAIC |
us_generic | Attorney General Ihres Bundesstaates |
Wenn Sie legal_dpa_authority geändert haben, hat Ihre Eingabe Vorrang vor dieser Ableitung.
Grenzen der Abdeckung nach Jurisdiktion
- Nur vier EWR-Länder haben eine namentlich genannte Behörde (FR, BE, LU, DE). Eine DSGVO-Website in Spanien, Italien oder den Niederlanden veröffentlicht eine allgemeine Formulierung.
- Keine Granularität nach US-Bundesstaat. Das Profil
us_genericexistiert und trägt seine eigenen VCDPA/CPA/CTDPA/UCPA/TDPSA-Texte, aber keine automatische Erkennung weist es zu: Es wird von Hand gewählt. - Keine Granularität nach kanadischer Provinz.
- Nur drei Dokumentsprachen: Französisch, Englisch, Portugiesisch. Die Textkörper laufen nicht durch den Übersetzungsmechanismus von WordPress — das ist Absicht: Ein Rechtstext muss einsprachig sein, und seine Sprache folgt der Jurisdiktion, niemals der Locale des Administrators.
- Impressum und AGB: nur französische Vorlagen. Der Generator verweigert für jede andere
Zielsprache rundheraus, es sei denn, Sie liefern über den Filter
owc_policy_templateIhren eigenen Textkörper.
Die Cookie-Kategorien
Die kanonische Liste
Sechs Kategorien, in dieser Anzeigereihenfolge, necessary immer zuerst:
| Slug | Mitgelieferte Bezeichnung | Mitgelieferte Beschreibung |
|---|---|---|
necessary | Necessary | Strictly required for the site to function (cart, login, language preferences). Cannot be disabled. |
functional | Functional | Enhance the experience (chat, embedded videos, maps). Without them some features may not work. |
analytics | Statistics | Help us understand how you use the site (anonymously). No personal data is shared for commercial purposes. |
marketing | Marketing | Enable us to show you ads and content tailored to your interests on other sites. |
preferences | Preferences | Remember your interface choices (layout, saved filters). |
social | Social & embeds | Allow embedded social content (YouTube, Instagram, X) to load. |
Die Werte oben sind die speicherbaren englischen Standardwerte. Auf einer deutschsprachigen Website sieht der Besucher die Übersetzung — siehe den Übersetzungsmechanismus weiter unten.
Verfügbarkeit
Einstellung cat_<slug>_available, eine je Kategorie. Alle sechs sind standardmäßig
verfügbar. Der alte Schlüssel cat_<slug>_enabled wird noch als Rückfall gelesen, ohne
Migration.
preferences und social werden verfügbar ausgeliefert, weil der Seed-Katalog YouTube,
Spotify, SoundCloud, Instagram, X und Facebook als social einstuft: Ohne die Kategorie in
der Oberfläche blieben diese Einbettungen für immer blockiert, ohne Möglichkeit zum Opt-in.
necessary ist erzwungen: Sie lässt sich nicht abschalten (Art. 5 Abs. 3 ePrivacy). Sie
hat deshalb keinen Verfügbarkeitsschalter im Backend, nur eine Bezeichnung und eine
Beschreibung.
Der Übersetzungsmechanismus
Einstellungen cat_<slug>_label und cat_<slug>_desc. Der gespeicherte Wert wird
wortwörtlich nur dann zurückgegeben, wenn er nicht leer und vom englischen Standard
verschieden ist; sonst kommt die Übersetzung heraus.
Folge, die Sie kennen sollten: Solange Sie nichts anpassen, ändert ein Wechsel der Website-Sprache auch die Sprache der Kategorien. Sobald Sie Ihren eigenen Text eintragen, ist dieser Text in der Sprache eingefroren, in der Sie ihn geschrieben haben. Dieselbe Regel gilt für die Texte des Banners.
Die übersetzte Beschreibung von necessary wird aus zwei Zeichenketten zusammengesetzt: Die
zweite benennt die Cookies des Plugins selbst, owc_consent (bis zu 13 Monate) und owc_geo
(24 Stunden, nur geschrieben, wenn die regionale Erkennung aktiviert ist).
Zuordnung zu Google Consent Mode v2 — verbindlich
Das ist die einzige Wahrheitsquelle des Plugins: Banner, Blockade und Bootstrap lesen alle diese Tabelle, sie können also nicht auseinanderlaufen.
| Kategorie | Consent-Mode-v2-Signale |
|---|---|
necessary | security_storage, functionality_storage |
functional | functionality_storage, personalization_storage |
analytics | analytics_storage |
marketing | ad_storage, ad_user_data, ad_personalization |
preferences | personalization_storage |
social | ad_storage, ad_user_data |
Wichtige Feinheit: Wenn Ihre Website die Kategorie functional anbietet, wird
functionality_storage aus der Liste von necessary entfernt. Sonst wäre es vor jeder
Einwilligung freigegeben, obwohl es zu einer optionalen Kategorie gehört.
Zuordnung zu TCF — nur beschreibend
functional → functional, analytics → measurement, marketing → advertising,
preferences → personalization, social → social_media.
Das sind Anzeigeetiketten. Die verbindliche Zuordnung auf TCF-Seite ist die Tabelle der numerischen IAB-Zweck-IDs, beschrieben im Abschnitt IAB TCF v2.2. Hängen Sie niemals ein TCF-Verhalten an diese fünf Etiketten.
Was passiert, wenn eine Kategorie verschwindet
Wenn eine Katalogregel auf eine Kategorie zeigt, die Ihre Website nicht mehr anbietet — Sie
haben zum Beispiel social abgeschaltet —, schiebt die Blockade die Ressource auf
marketing, hilfsweise auf die erste verfügbare optionale Kategorie. Ohne diese
Normalisierung wäre die Ressource für immer blockiert, ohne jeden Schalter, um sie
freizugeben.
Das Banner
Wann es erscheint
Das Banner wird auf wp_footer mit Priorität 5 gerendert, seine Assets werden auf
wp_enqueue_scripts eingereiht. Es steigt sofort aus, wenn eine dieser Bedingungen zutrifft:
Backend-Kontext, RSS-Feed, robots.txt oder banner_enabled deaktiviert. Es steigt ebenso
aus, wenn wp_head nie ausgelöst wurde — ein Theme, das wp_head() nicht aufruft, bekäme
sonst inertes, ungestyltes Markup.
Das HTML ist für alle Besucher identisch. Alle Schalter des Panels werden serverseitig
auf AUS gerendert und dann clientseitig aus dem Cookie hydriert. Es ist das JavaScript, das
<html data-owc="given|none"> synchron setzt, vor dem ersten Rendern; das CSS zeigt das
Banner nur bei data-owc="none".
Folgerung, die Sie kennen sollten: Ein Besucher ohne JavaScript sieht das Banner nie, er
sitzt also auch nie hinter einem Modal fest, das er nicht schließen kann. Er sieht
stattdessen einen <noscript>-Block, der erklärt, dass seine Präferenzen nicht erfasst
werden können und dass kein nicht notwendiges Cookie geladen wird, solange keine Wahl
getroffen wurde.
Positionen und Theme
| Einstellung | Werte | Standard |
|---|---|---|
banner_position | bottom-bar, bottom-card, center-modal, top-bar | bottom-bar |
banner_style | auto, light, dark | auto |
Nur center-modal bekommt role="dialog", aria-modal="true", einen abgedunkelten
Hintergrund, eine Fokusfalle und die Escape-Taste. Die drei anderen Positionen sind eine
role="region": Escape wird nicht abgefangen (das Theme behält seine eigene Behandlung),
und der Fokus wird beim ersten Rendern nicht gestohlen, was einen Tastaturnutzer sonst hinter
alle Sprunglinks werfen würde.
Die dunkle Palette greift unter prefers-color-scheme: dark, mit Absicherungen, um ein
Theme nicht zu überschreiben, das ausdrücklich light deklariert. Das Theme der Website kann
die Palette über CSS-Variablen steuern: --owc-paper-tint, --owc-ink, --owc-smoke,
--owc-fog, --owc-ui, --owc-accent, --owc-accent-strong, --owc-accent-darker.
Umsetzungsdetails: z-index 99998 für das Banner und 99997 für den Hintergrund,
Unterstützung von env(safe-area-inset-*) für iOS-Notches, automatischer Versatz unter der
WordPress-Adminleiste bei oberer Position.
Die Buttons
| Einstellung | Standard | Wirkung |
|---|---|---|
banner_accept_all | true | Zeigt „Alle akzeptieren“ |
banner_reject_all | true | Zeigt „Alle ablehnen“ |
banner_preferences | true | Zeigt „Anpassen“ |
banner_close_x | false | Zeigt das Schließkreuz |
banner_show_logo | true | Zeigt das Logo der Website |
„Alle akzeptieren“ und „Alle ablehnen“ teilen sich dieselbe Formatierungsklasse: gleicher Hintergrund, gleicher Rahmen, gleiche Schriftstärke, gleicher Innenabstand. Das ist die Antwort auf die Vorgabe von CNIL / EDSA (Leitlinien 03/2022): Ablehnen muss genauso einfach und genauso sichtbar sein wie Akzeptieren.
Das Schließkreuz
Es ist standardmäßig deaktiviert, weil ein Schließkreuz einer stillschweigenden Ablehnung gleichkommt. Drei Verhaltensweisen, die Sie kennen sollten:
- Wenn
banner_close_xaus ist, steckt das Kreuz zwar im Markup, trägt aber das Attributhidden, und das CSS entfernt es vollständig: weder sichtbar noch fokussierbar noch für Screenreader angekündigt. - Wenn es aktiviert ist, führt ein Klick auf das Kreuz den vollständigen Pfad „Alle ablehnen“ aus, niemals ein stilles Schließen.
- Es wird vom Runtime eingeblendet und neu beschriftet, und zwar in genau einem Fall: wenn eine Ablehnung überhaupt nicht erfasst werden konnte. Dann lehnt es nichts mehr ab, es räumt den Hinweis weg — und dieses Schließen zählt nicht als Wahl. Ein Besucher, dessen Entscheidung der Server verweigert, bleibt nicht vor einem Banner sitzen, das er nicht schließen kann.
Die erste Ebene
- Der Titel (
text_title) und die Nachricht (text_message). Die Nachricht ist das einzige Feld mit Rich-HTML im Plugin; sie wird mit einemwp_ksesgerendert, das auf<a href target rel>beschränkt ist. - Der Link zur Datenschutzerklärung:
link_privacy_policy, mit Rückfall auf die in WordPress hinterlegte Datenschutzseite, falls die Einstellung leer ist. - Der Link zur Cookie-Richtlinie:
link_cookie_policy, ohne Rückfall. - Der Name des Verantwortlichen:
legal_company_name, sonst der Name der Website, angezeigt als „Verantwortlicher: …“ (Art. 13 Abs. 1 lit. a). - Das Logo: das benutzerdefinierte Logo des Themes in der Größe
medium, sonst das Website-Icon.
Das Präferenz-Panel
Eine Zeile je verfügbarer Kategorie, in einer benannten role="group".
- Eine erzwungene Kategorie zeigt ein Textabzeichen „Always active“, ohne Schalter.
- Eine optionale Kategorie zeigt einen
<button role="switch">mitaria-checked,aria-labelledbyundaria-describedby. Der Zustand wird überaria-checked, die Position des Reglers und ein sichtbares On/Off-Wort getragen — nie über die Farbe allein. - Touch-Ziel auf kleinen Bildschirmen auf 44 px vergrößert (WCAG 2.2 AA, Kriterium 2.5.8).
- Die Aktionsleiste des Panels ist unten
sticky, damit „Meine Auswahl speichern“ erreichbar bleibt, während die Liste scrollt.
Wenn das TCF-Modul aktiv ist, kommen zwei weitere Blöcke hinzu: die erreichbaren TCF-Zwecke und die deklarierten Special Features. Siehe IAB TCF v2.2.
Erneuerung der Einwilligung
| Einstellung | Standard | Grenzen |
|---|---|---|
consent_renewal_months | 12 | 0 bis 13 |
consent_policy_hash_check | true | — |
0 heißt nicht „nie wieder fragen“. Der Wert 0 wird in 13 Monate umgewandelt, und 13
Monate sind die harte Obergrenze (CNIL-Beschluss 2020-091). Die tatsächliche Dauer liegt also
immer zwischen 1 und 13 Monaten, und derselbe Wert steuert die Cookie-Lebensdauer, die
serverseitige Ablaufprüfung und die in den erzeugten Dokumenten veröffentlichte Dauer. Die im
Quellcode sichtbare Konstante OWC_COOKIE_TTL ist nur ein Rückfall.
consent_policy_hash_check fragt die Einwilligung erneut ab, wenn sich Ihre Dokumente
ändern: Das Cookie trägt einen Fingerabdruck der verlinkten Rechtstextseiten, und eine
Abweichung öffnet das Banner erneut. Der Fingerabdruck ist der leere String, wenn keine
Seite verlinkt ist — genau das erlaubt es, „unbekannt“ von „geändert“ zu unterscheiden und
niemals eine ganze Website auf Basis eines leeren Vergleichs erneut zu behelligen.
Die Texte
Sieben Textstellen, alle standardmäßig leer und damit automatisch übersetzt: text_title,
text_message, text_accept_all, text_reject_all, text_preferences, text_save und
floating_button_label für den schwebenden Button.
Im Backend zeigt jedes Feld seinen übersetzten Standard als Platzhalter: Leer lassen behält den Standard, der der Sprache des Besuchers folgt.
Der Filter owc_banner_texts erlaubt es, diese Texte per Code zu ersetzen. Zusätzliche
Textstellen werden akzeptiert; nicht skalare oder leere Werte werden verworfen, damit ein
unbedachter Callback das Banner nicht leeren kann.
Wie die Wahl tatsächlich erfasst wird
Das JavaScript-Runtime ist striktes ES5 — keine Pfeilfunktionen, keine Template-Literale —, damit es in In-App-Browsern und alten WebViews läuft. Seine Schreibsequenz ist es wert, bekannt zu sein, denn sie erklärt die meisten Fehlermeldungen.
- Neuverankerung des Origins. Die REST-URLs stammen aus der WordPress-Konfiguration.
Wenn Ihre Besucher auf einem anderen Host unterwegs sind (www gegen Apex, Alias,
Vorschaudomain, Proxy, der
Hostumschreibt), ist diese URL Cross-Origin, und der Browser weigert sich, dasSet-Cookiezu speichern, während WordPress mit 200 antwortet. Das Runtime verankert den von PHP gelieferten Pfad deshalb neu auf dem tatsächlich besuchten Origin. - Nonce. Frisch über
GET /owc/v1/nonceunmittelbar vor dem Schreiben geholt, nie in cachebares HTML eingebettet, im HeaderX-OWC-Noncegesendet. Der Abruf ist auf 4 Sekunden gedeckelt, und ein fehlendes, leeres oder unerreichbares Nonce verhindert das Schreiben nie und wird dem Besucher auch nicht gemeldet. - Ausdrückliche
page_urlim Body der Anfrage, damit die Protokollzeile nicht vomReferer-Header abhängt, den eine Erweiterung, eine Meta-Referrer-Angabe oder ein Proxy entfernen kann. - Blockade-Schutz von 15 Sekunden mit
AbortController: Die Anfrage wird abgebrochen, nicht nur ignoriert, damit ein verspäteter POST keine zweite Zeile schreibt. - Definition von Erfolg. Der POST gilt genau dann als erfolgreich, wenn: die Antwort
okist, der Body auswertbares JSON ist,json.ok === truegilt und das Cookie im Browser wieder gelesen werden kann. Eine Cache-Seite, eine Edge-Challenge oder eine WAF, die mit 200 antwortet, zählen nicht. - Antwortet der Server mit
cookie_set: false, schreibt das Runtime das Cookie selbst mit den zurückgegebenen Parametern und liest es dann erneut. Ein Fehlschlag bleibt ein Fehlschlag: Es wird nichts veröffentlicht und nichts freigegeben. - Genau ein Wiederholungsversuch, und nur bei einem 403, dessen Code
owc_bad_nonce,rest_cookie_invalid_nonceoderrest_nonce_invalidlautet, und nur wenn das erhaltene Nonce tatsächlich ein anderes ist. - Was das Runtime veröffentlicht, ist das, was der Server gespeichert hat: Vom Server abgelehnte Kategorien werden vom lokalen Zustand abgezogen.
Solange der POST nicht erfolgreich war, wird nichts demaskiert, nichts freigegeben und kein Consent-Mode-Signal „granted“ gesendet.
Die Fehlertaxonomie
Das Runtime unterscheidet neun Ursachen, jede mit eigener sichtbarer Meldung: network,
refused, ratelimit, unexpected, timeout, browser, config, cookie,
owc_cookie_not_persisted. HTTP-Status und Server-Code werden auf das Element gesetzt
(data-owc-status, data-owc-code) und einmal per console.warn protokolliert — niemals
als sichtbarer Text gerendert. Ein Support-Screenshot benennt die Ursache also, ohne dass ein
Netzwerk-Trace nötig wäre.
Die JavaScript-API des Banners
window.OWCBanner.show(); // öffnet im Banner-Modus
window.OWCBanner.hide(); // schließt
window.OWCBanner.openPreferences(); // öffnet das Präferenz-Panel
window.OWCBanner.openDnsmpi(); // öffnet das Panel mit marketing, social
// und preferences bereits auf AUS (CCPA-Einstieg)
window.OWCBanner.reset(); // löscht das Cookie clientseitig, sendet einen Widerruf
// und lädt die Seite neu
window.OWCBanner.acceptCategory( 'social' ); // liefert ein Promise, das nur dann zu true
// auflöst, wenn der Server wirklich gespeichert hat
Ein leichteres Bootstrap wird in <head> mit Priorität 1 ausgegeben und stellt
window.OWConsent bereit: .config, .categories, .geo, .profile, .optOut, .state,
.has(cat), .refresh(), .paint(), .gcmSignals(state). Seine Konfiguration ist über
owc_bootstrap_config filterbar — aber alles, was darin steht, ist öffentlich und wird
vom Cache geteilt: Legen Sie dort niemals besucherspezifische Daten hinein.
Das Panel aus Ihren Seiten heraus öffnen
Drei Wege, alle gleichwertig:
- das URL-Fragment
#owc-preferences(oder#owc-dnsmpi), beim Laden und beihashchangeausgewertet; - jedes Element mit der Klasse
owc-open-preferencesoder dem Attributdata-owc-open; - das Attribut
data-owc-dnsmpi="1", um das „Do Not Sell“-Verhalten zu erzwingen.
Bei jeder Änderung wird ein Ereignis owc:consent-changed ausgelöst, mit der gesendeten
Nutzlast im Detail. Es wird vom Bootstrap, vom schwebenden Button, vom CCPA-Runtime und vom
TCF-Modul abgehört; Sie können es ebenfalls abhören.
Grenzen des Banners
- Alles hängt an
wp_head()undwp_footer(): Ein Theme, das sie nicht aufruft, bekommt nichts. - Ohne
window.fetchundwindow.Promiseist kein Schreiben möglich, und der Fehlerbrowserwird angezeigt. - Eine Einwilligung kann serverseitig erfasst werden, ohne im Browser erhalten zu bleiben (Website-Adresse weicht vom besuchten Host ab, Speicher blockiert, Cookie-Jar voll). Das Runtime erkennt diesen Fall, wertet ihn nicht als Erfolg, zeigt eine eigene Meldung und übermittelt den Umstand beim nächsten Schreibvorgang an den Server.
- Das Banner hat keinen Shortcode: Es erscheint überall oder nirgends.
Die automatische Blockade
Das ist das Modul, das aus einer Wahl eine echte Wirkung macht. Es schreibt die Tags, die Tracker tragen, vor jeder Einwilligung um, für alle, und überlässt es dem Runtime, sie im Browser freizugeben.
Zwei Modi, eine Einstellung
compliance_strict, standardmäßig aktiv.
- Aus (weicher Modus): Nur der Filter
script_loader_tagist eingehängt. Anders gesagt: Nur die überwp_enqueue_script()registrierten Skripte werden umgeschrieben. Ein<script>, das fest im Theme steht, ein Embed, ein iframe, ein<img>-Pixel: nichts davon wird angefasst. - An (Strict-Modus): Zusätzlich zum Filter fängt ein Output-Buffer das gesamte Dokument
ab, und auch das über die REST API gerenderte Markup wird behandelt. Im Backend deckt bei
einer
admin-ajax.php-Anfrage ein separater Buffer die Antworten ab, die auch das Frontend bedienen („mehr laden“, gefilterte Archive) — aber nur, wenn der Handler selbstContent-Type: text/htmldeklariert hat.
Was nie gepuffert wird
Der Strict-Buffer steigt sofort aus für: Backend, AJAX-Anfragen, Feeds, robots.txt,
Trackbacks, Cron, Favicons, REST-Anfragen, JSON-Anfragen, die Vorschau des Customizers,
Sitemaps und die Einstiegspunkte wp-login.php, wp-register.php, wp-signup.php,
xmlrpc.php, wp-cron.php, wp-trackback.php — geprüft anhand des exakten Skriptnamens,
niemals als Teilstring der URL. Er steigt außerdem für die Anfragen des Scanners aus, die das
rohe HTML brauchen.
Die fünf Durchläufe
Das Umschreiben erfolgt über kalibrierte reguläre Ausdrücke, niemals über einen DOM-Parser. Drei Sicherungen rahmen das Ganze ein: Ein Dokument über 8 MB wird unverändert zurückgegeben, ein Fehler der PCRE-Engine gibt das Dokument unverändert zurück, und wenn das Ergebnis weniger als die Hälfte der Ausgangsgröße hat, wird das Original zurückgegeben. Anders gesagt: Der Fehlermodus der Blockade ist „Seite ohne Blockade ausgeliefert“, niemals „Seite kaputt“.
Durchlauf 0 — Maskierung. HTML-Kommentare, <style> und <textarea> werden durch
Marker aus Steuerzeichen ersetzt, damit kein späteres Muster in ihrem Inneren greift.
Durchlauf 1 — <script>. Entscheidung, in dieser Reihenfolge:
- bereits behandelt → unverändert;
- Skript des Plugins selbst → unverändert;
type="text/plain"oder Nicht-JS-Typ (ld+json,importmap,x-template) → unverändert;- URL gesucht in
src,data-src,data-rocket-src,data-lazy-src,data-litespeed-src,data-cfsrc— die Attribute der Performance-Plugins sind also abgedeckt; - Host auf der Allowlist → unverändert; First-Party-Ressource, die nicht nach einem Tracker aussieht → unverändert;
- Abgleich mit dem Katalog über die Form
Host + Pfad; einedata:- oderjavascript:-URL wird dekodiert und wie ein Inline-Textkörper bewertet; - eine als
necessaryeingestufte Regel wird nie blockiert (Stripe.js, reCAPTCHA, Turnstile, cdnjs …): Sie zu blockieren bringt keinerlei Compliance und zerlegt das aufrufende Snippet; - keine Übereinstimmung →
blocker_unknown_script_policy, Standardallow; - sonst Umschreiben auf
type="text/plain"mitdata-owc-cat,data-owc-vendor,data-owc-srcund, falls der ursprüngliche Typ besonders war (moduleetwa),data-owc-type, um das wiederhergestellte Skript nicht zu verschlechtern.
Inline-Textkörper werden zuerst mit den Katalogregeln vom Typ inline_signature verglichen,
dann mit vierzehn fest verankerten Signaturen: fbq(, _fbq.push, gtag(,
dataLayer.push(, ga('…, _gaq.push, _paq.push, hjid, clarity(,
ttq.load|track|page, snaptr(, twq(, lintrk(, pintrk(. Ausdrückliche Ausnahme:
Ein alleinstehendes gtag('consent', …), also eine Consent-Mode-Standarddeklaration ohne
weitere Marker, bleibt ausführbar.
Durchlauf 2 — <iframe>. Dieselben URL-Attribute, dazu data-original und
data-srcset. First-Party oder Allowlist → unverändert. necessary → unverändert, sonst
wäre ein Formular mit Captcha nicht mehr absendbar. Ohne Übereinstimmung →
blocker_unknown_iframe_policy, Standard block. Das blockierte iframe wird zu
src="about:blank" und in einen sichtbaren Platzhalter eingepackt, der einen Button
„
Durchlauf 3 — <img>, nur Tracking-Pixel. Wichtige Regel: Eine Katalogzeile allein
reicht nie, um ein Bild zu entschärfen. Passt das Bild zum Katalog, ist seine Kategorie
aber weder analytics noch marketing — ein Bild-CDN, ein Gravatar-Dienst, ein Font-Hoster
—, bleibt es unverändert, sonst würde man die Medien der Website löschen statt eines
Trackers. Blockieren kann nur die Tag-Heuristik: elf bekannte Sammelpunkte
(facebook.com/tr, px.ads.linkedin.com, ct.pinterest.com, bat.bing.com,
analytics.twitter.com, t.co/i/adsct, tr.snapchat.com, analytics.tiktok.com,
google-analytics.com/collect, googleads.g.doubleclick.net, pixel.quantserve.com) oder
ein 1×1-Pixel-Bild von einem Dritten. Das src wird dann durch ein transparentes GIF
ersetzt, und alle Attribute, die eine URL tragen, werden entfernt, damit ein Lazy Loader
das Original nicht wiederherstellt.
Durchlauf 4 — <link>. Abhängig von blocker_block_resource_hints, Standard true.
Behandelt nur Hosts, die bereits im Katalog stehen, niemals einen unbekannten.
- Ressourcen-Hints (
preconnect,dns-prefetch,prefetch,prerender,preload,modulepreload) auf einen katalogisierten Dritten werden entfernt, nicht aufgeschoben: Ein Hint öffnet eine TCP+TLS-Verbindung und gibt IP und TLS-Fingerabdruck des Besuchers preis, und danach gibt es nichts wiederherzustellen. - Ein als
analyticsodermarketingeingestuftes Stylesheet wird entschärft. - Google Fonts und andere als
functionaleingestufte Schrift-Hosts werden nie angefasst: Sie zu entschärfen liefert website-weit Text in einer Fallback-Schrift, ohne jeden Compliance-Gewinn.
Durchlauf 5 — <object>, <embed>, <source>, <video>, <audio>. Nie eine
Blockade per Standard: Nur ein bereits katalogisierter Dritter wird behandelt. Die Attribute
autoplay und preload werden entfernt.
Was als „First Party“ zählt
Die Website-URL, die WordPress-URL, die Content-URL, die Includes-URL, ihre
Netzwerk-Entsprechungen im Multisite-Betrieb und der Uploads-Basispfad. Das www. wird beim
Vergleich entfernt. Jeder Pfad, der mit /wp-content/ oder /wp-includes/ beginnt, ist
First Party, egal auf welchem Host, um CDN-Umschreibungen abzudecken. Nicht-HTTP-Schemata
(data:, blob:, javascript:) sind nie First Party.
Gegenausnahme: Eine URL, die gtag, gtm.js, analytics, pixel, fbevents, hotjar,
matomo, piwik oder clarity enthält, wird auch auf dem Host der Website behandelt.
Genau das fängt ein selbst gehostetes GTM oder Matomo ab, und ebenso First-Party-Proxys.
Das Freigabe-Runtime
Ausgegeben in <head> mit Priorität 2. Seine JSON-Konfiguration enthält nur den Namen des
Cookies und die Liste der überwachten Hosts — nichts, was vom Besucher abhängt.
- Zustandslesen: Das Cookie
owc_consentwird bis zur Stabilität dekodiert, mit maximal drei Durchläufen, weil vor 1.4.3 geschriebene Cookies doppelt kodiert waren. - Absicherung dynamisch eingefügter Skripte: Der Setter
HTMLScriptElement.prototype.srcundsetAttributewerden umhüllt. Ein First-Party-Loader, ders.src = 'https://www.googletagmanager.com/gtm.js?id=…'zuweist, wird abgefangen, und das Element wird vor der Ausführung gekennzeichnet. Die überwachte Liste umfasst zwanzig Hosts:googletagmanager.com,google-analytics.com,googleadservices.com,googlesyndication.com,doubleclick.net,connect.facebook.net,static.hotjar.com,script.hotjar.com,clarity.ms,cdn.matomo.cloud,analytics.tiktok.com,snap.licdn.com,sc-static.net,static.ads-twitter.com,bat.bing.com,s.pinimg.com,cdn.segment.com,js.hs-scripts.com,cdn.amplitude.com,cdn.mxpnl.com. Alles, was nicht darin steht, läuft unbehelligt durch. Die Hosts Ihrer Allowlist werden vor der Ausgabe aus dieser Liste entfernt. - Wiedereinfügen in Dokumentreihenfolge. Ein wiederhergestelltes externes Skript
blockiert die Warteschlange bis zu seinem
onloadoderonerror, mit einer Obergrenze von 5 Sekunden, damit ein nicht erreichbarer Anbieter nicht den Rest aufhält. Das Attributasyncwird nur gesetzt, wenn es ursprünglich vorhanden war — sonst würde ein percreateElementerzeugtes Skript zwangsweise asynchron und das Konfigurations-Snippet liefe vor seiner Bibliothek. Bei einem wiederhergestellten Inline-Skript wirddocument.writevorübergehend umgeleitet, um das Dokument nicht zu löschen. - Widerruf der Einwilligung: Wenn eine bereits angewendete Kategorie ausdrücklich auf
falsewechselt, lädt das Runtime die Seite neu. Ein bereits ausgeführtes Skript lässt sich nicht entladen (Art. 7 Abs. 3 DSGVO). Eine Kategorie, die in der Nutzlast einfach fehlt, ist kein Widerruf. - Ein
MutationObserverscannt nachträglich eingefügtes Markup erneut (AJAX, lazy geladene Abschnitte). - Ein Klick auf den Button eines blockierten Embeds ruft
OWCBanner.acceptCategory()auf; fehlt die Banner-API, wird das Embed lokal freigegeben, ohne irgendetwas zu speichern.
Der Signaturkatalog
Tabelle {prefix}owc_scripts. Die mitgelieferte Datei data/tracker-catalog.json enthält
175 Zeilen für 71 verschiedene Anbieter:
| Aufteilung | Detail |
|---|---|
| Nach Ziel | 110 URL-Muster, 65 Cookie-Namen |
| Nach Typ | 172 Textfragmente, 3 reguläre Ausdrücke |
| Nach Kategorie | necessary 55, marketing 37, functional 37, analytics 36, social 10 |
Spalten: pattern, pattern_type (host, regex, inline_signature), match_target
(url oder cookie), name, vendor, category, privacy_policy_url, gcm_signal,
tcf_vendor_id, retention_days.
Zwei Verhaltensweisen, die Sie kennen sollten:
- Zeilen mit
match_target = 'cookie'werden von der Blockade nie verwendet. Sie dienen ausschließlich der Cookie-Tabelle in den erzeugten Dokumenten. Sie als Teilstring einer URL zu vergleichen, war genau das, was das JavaScript von Websites zerlegt hat. - Ein Muster vom Typ
host, das auf eine URL zielt, kürzer als sechs Zeichen ist und keinen Punkt enthält, wird abgelehnt: „fr“ oder „IDE“ würden auf „frame.js“ und „provider.js“ passen.
Der Katalog wird im Object Cache (1 Stunde) und in einem Transient (12 Stunden)
zwischengespeichert. Ein leeres Ergebnis wird nie gecacht. Jeder Schreibvorgang löst die
Aktion owc_catalog_updated aus, die diese Caches leert.
Der Tab Tracker catalogue erlaubt es, Regeln hinzuzufügen, zu ändern, zu löschen und zu durchsuchen, mit einem Filter „nur Regeln, die nicht greifen können“: leeres oder unsichtbares Muster, regulärer Ausdruck, der nicht kompiliert oder katastrophal zurückverfolgt, für eine URL zu kurzes Muster ohne Punkt, Kategorie, die es nicht mehr gibt. Diese Diagnose läuft in PHP, weil nur die PCRE-Engine sagen kann, ob ein Ausdruck kompiliert.
Einstellungen der Blockade
| Einstellung | Standard | Werte |
|---|---|---|
compliance_strict | true | boolesch |
blocker_unknown_script_policy | allow | allow, block |
blocker_unknown_iframe_policy | block | allow, block |
blocker_block_resource_hints | true | boolesch |
blocker_allowlist | '' | ein Host pro Zeile |
Erweiterungspunkte
// Hosts, die nie blockiert werden, zusätzlich zu blocker_allowlist.
add_filter( 'owc_blocker_allowlist', function ( array $hosts ) {
$hosts[] = 'cdn.mein-partner.example';
return $hosts;
} );
// Katalogzeilen vor der Validierung.
add_filter( 'owc_scripts_catalog', function ( array $rows ) {
$rows[] = array(
'pattern' => 'tracker.example.com',
'pattern_type' => 'host',
'match_target' => 'url',
'name' => 'Beispiel',
'vendor' => 'Beispiel GmbH',
'category' => 'analytics',
);
return $rows;
} );
Die öffentliche Methode OWC_Blocker::block_html_fragment( $html ) wendet die Blockade auf
ein Fragment an, das nicht durch den Output-Buffer gelaufen ist.
Grenzen der Blockade
- Ohne
compliance_strictwerden nur die von WordPress eingereihten Skripte behandelt. - Ein unbekanntes Drittanbieter-Skript ist standardmäßig erlaubt. Die tatsächliche Blockade stützt sich auf den Katalog und die Inline-Signaturen — erweitern Sie sie.
- Die Absicherung für per JavaScript eingefügte Skripte deckt nur zwanzig Hosts ab; ein Tracker außerhalb der Liste, den First-Party-Code einfügt, kommt durch.
- Als
functionaleingestufte Stylesheets (Webfonts) werden bewusst durchgelassen. - Ein im Katalog geführter Tracker in einem
<img>, der anders alsanalyticsodermarketingeingestuft ist, wird nicht entschärft. - Medien (
object,embed,source,video,audio) werden nie standardmäßig blockiert: Nur ein bereits katalogisierter Dritter wird behandelt. - Ein Dokument über 8 MB, ein PCRE-Fehler oder ein Verlust von mehr als 50 % des Inhalts führen zu einer Seite, die ganz ohne Blockade ausgeliefert wird, stillschweigend.
- Der Widerruf der Einwilligung löst ein vollständiges Neuladen der Seite aus.
Der Tracker-Scanner
Der Scanner inventarisiert, was Ihre Seiten wirklich laden. Er ist standardmäßig deaktiviert: Schalten Sie ihn im Tab Scanner ein.
Drei Erkennungsquellen
Jeder Fund behält seine Herkunft und die Information „kann die Blockade darauf wirken“.
1. Das ausgelieferte HTML. Der Scanner ruft eine Stichprobe der URLs Ihrer eigenen
Website ab und liest das Markup: <script src> und <script data-owc-src> — bereits
blockierte Skripte werden also trotzdem gesehen —, Inline-Signaturen, <iframe>, externe
Stylesheets und Bilder, deren URL 1x1, pixel, track, beacon oder impression
enthält. Es wird kein JavaScript ausgeführt: Was ein Tag-Manager zur Laufzeit einschleust,
ist für diesen Durchlauf unsichtbar.
2. Die Set-Cookie-Header. Das sind die einzigen Cookies, die ein Server-Durchlauf
beweisen kann, einschließlich der HttpOnly-Cookies, die eine Browser-Sonde nie sehen
wird. Sie werden als nicht blockierbar markiert: Nichts an der clientseitigen Blockade
kann ein vom Server gesetztes Cookie aufhalten. Die Cookies des Plugins selbst werden
ignoriert.
3. Die Browser-Sonde. Wird im Footer ausgegeben, nur für einen angemeldeten Nutzer mit
manage_options, und nur wenn der Scanner aktiviert ist. Sie fotografiert
document.cookie beim Laden, beobachtet die DOM-Mutationen — genau das fängt ab, was ein
Tag-Manager einschleust —, fragt document.cookie alle 5 Sekunden nach clientseitig
geschriebenen Cookies ab und übermittelt ihre Beobachtungen alle 2 Sekunden sowie bei
beforeunload. Die Antwort, die die Sonde trägt, wird als nicht cachebar markiert.
Im Code anerkannte Grenze: Ein Administrator hat in der Regel bereits alles akzeptiert. Die Sonde beschreibt also den Zustand nach der Einwilligung, nicht den davor.
Der Durchlauf
Die URL-Warteschlange ist so gebaut, dass sie Templates abdeckt, nicht Seiten: zuerst die Kern-URLs (Startseite, statische Startseite, Beitragsseite und die vier verlinkten Rechtstextseiten), dann eine Verschränkung im Rundlauf je Familie — bis zu 30 Seiten, 15 Beiträge, 5 je öffentlichem benutzerdefiniertem Inhaltstyp, 3 Kategorien und 3 Schlagwörter. Ohne diese Verschränkung fraßen dreißig nahezu identische Seiten das ganze Budget, und die WooCommerce-Templates wurden nie erreicht.
Der Filter owc_scanner_urls erlaubt es, URLs zu ergänzen, aber das Ergebnis wird erneut
auf den Host der Website eingeschränkt: Der Scanner verlässt Ihre Domain nie.
Jede Anfrage läuft mit von Hand verfolgten Weiterleitungen (höchstens zwei Sprünge, jeder
Sprung erneut gegen den Host der Website geprüft), einer auf 2 MB gedeckelten Antwort, einem
Header Cache-Control: no-cache, no-store und einem eindeutigen URL-Parameter, um keine
Cache-Seite zu lesen, sowie einem User-Agent OW-Consent-Scanner/<version>. Eine
Nicht-HTML-Antwort zählt als übersprungen, nicht als Fehlschlag.
Ein Umgehungsgeheimnis wird im Header X-OWC-Scanner mitgeschickt, damit sich die
Blockade zurückzieht und das rohe HTML sichtbar wird. Es wird in konstanter Zeit verglichen,
und der Header wird zuerst geprüft, damit ein gewöhnlicher Besucher nicht einmal das Lesen
der Option auslöst.
Budget, Sperre, Wiederaufnahme
| Randbedingung | Wert |
|---|---|
| URLs pro Lauf | scanner_max_urls, Standard 25, Grenzen 1 bis 500 |
| Timeout pro Anfrage | scanner_timeout, Standard 8 s, Grenzen 1 bis 60 |
| Zeitbudget pro Paket | max_execution_time − 10 s, sonst 45 s, begrenzt auf 5 bis 60 s |
| Ausführungssperre | 15 Minuten |
| Lebensdauer der Warteschlange | 6 Stunden |
Geht das Budget zur Neige, wird eine Minute später eine Wiederaufnahme geplant, und der Durchlauf macht dort weiter, wo er aufgehört hat. Ein zweiter Start während eines laufenden Durchlaufs antwortet „ein Scan läuft bereits“. Kurzschluss: Wenn drei Anfragen fehlschlagen, ohne dass eine einzige Seite gelesen wurde, bricht der Durchlauf ab, statt sein Timeout an zweiundzwanzig weiteren URLs zu verbrennen — der typische Fall einer Website, bei der HTTP-Loopback blockiert ist.
Die erkannten Inline-Signaturen
Dreiundzwanzig Suchmuster, gruppiert in einundzwanzig Bezeichnungen: gtag('config',
gtag('event', gtag('js', gtm.start, ga('create', ga('send', fbq('init',
fbq('track', _paq.push, (h.hj=h.hj, clarity('init', clarity.ms/tag,
mixpanel.init, amplitude.init, amplitude.getInstance, _linkedin_partner_id,
snaptr('init', ttq.load, pintrk("load", pintrk('load', rdt('init',
criteo_q.push, _etmc.push.
Der Schlüssel zur Entdopplung ist die Signatur, niemals ein Fingerabdruck des Textkörpers: Ein echtes gtag- oder Pixel-Snippet enthält seitenspezifische Werte, was eine Zeile pro Seite ergäbe.
Die Rückkopplungsschleife: Fund → Katalog → Blockade
Das ist der Punkt, der den Scanner nützlich macht. Einen Tracker einzuordnen schreibt eine Regel in den Blockade-Katalog. Ein Klick auf die Kategorie eines Fundes tut drei Dinge: Er schreibt die Kategorie in die Zeile, er merkt sich Ihre manuelle Entscheidung, und er legt die passende Regel an. Am Ende jedes vollständigen Durchlaufs wird dieselbe Operation als Massenvorgang für alles ausgeführt, was der Katalog noch nicht einordnen kann.
Umwandlungsregeln:
- ein Fund vom Typ
cookiewird zu einer Regelmatch_target = cookieauf dem Cookie-Namen; - ein Fund vom Typ
inline_scriptschreibt nur dann eine Regel, wenn das ursprüngliche Suchmuster wiedergefunden wird. Ohne es wird keine Regel geschrieben: Eine aus der Bezeichnung „Google gtag (config)“ gebaute Regel wäre für immer tot und würde auf den Namen des Fundes passen, wodurch dieser für immer als „abgedeckt“ gälte; - sonst eine
host-Regel auf der Domain, abgelehnt, wenn die Domain leer ist.
Ihre manuellen Entscheidungen werden getrennt gespeichert (höchstens 500) und bei jeder neuen Beobachtung erneut angewendet, weil das Flag „bestätigt“ auch bedeutet „eine Katalogregel hat gegriffen“ und deshalb nicht allein die Information „der Administrator hat entschieden“ tragen kann. Eine Rückstufung auf „nicht kategorisiert“ löscht den Eintrag: Das ist ein echter Rückwärtsschritt.
Der Katalog wird längstes Muster zuerst verglichen, damit eine breite Regel
(google-analytics.com) nicht die genauere Regel überschreibt, die Sie geschrieben haben
(www.google-analytics.com).
Planung, Benachrichtigungen, Aufbewahrung
scanner_frequency akzeptiert hourly, twicedaily, daily und weekly — im Backend
werden aber nur die Intervalle angeboten, die Ihre Installation tatsächlich kennt. Standard:
weekly. Den Scanner abzuschalten entplant beide Ereignisse.
Zwei getrennte E-Mails, nie beide gleichzeitig:
- Nicht kategorisierte Tracker — nur für wirklich neue Kennungen versandt, mit einem auf 500 Einträge gedeckelten Gedächtnis.
- „Der Durchlauf konnte diese Website nicht lesen“ — begrenzt auf eine Nachricht pro Woche und Fehlersignatur. Das ist der schwerwiegendste Fehlermodus, denn ein Durchlauf, der nichts liest, produziert keine Funde und damit auch keine Benachrichtigung der ersten Art.
Empfänger: scanner_alert_email, sonst die Administrationsadresse der Website.
Aufbewahrung: 90 Tage. Funde, die seit 90 Tagen nicht mehr gesehen wurden, werden gelöscht, sobald mindestens eine Seite gelesen wurde — nicht erst, wenn ein Durchlauf endet.
Das Abdeckungs-Panel
Das ist der wichtigste Teil des Scanner-Tabs, und er speist auch den Warnhinweis der erzeugten Dokumente. Er beantwortet immer diese Fragen:
- wurde überhaupt schon ein Durchlauf gestartet?
- ist der letzte fertig geworden, oder hat sein Zeitbudget ihn unterbrochen?
- wie viele Seiten wurden tatsächlich abgerufen (nicht: aus der Warteschlange genommen)?
- wie viele konnten es nicht, und was war der erste Fehler?
- hat ein Browser schon einmal etwas gemeldet, oder wurde nie JavaScript beobachtet?
- ab welchem Zeitfenster verschwindet ein nicht mehr gesehener Tracker?
Ein Durchlauf, der keine einzige Seite erreicht hat, wird als Fehlschlag dargestellt, nicht als sauberes Ergebnis. Dieses Panel sollten Sie lesen, bevor Sie eine Cookie-Richtlinie veröffentlichen, die auf diesen Funden beruht.
Der Scanner-Tab
Drei Karten (erkannte Tracker, nicht kategorisierte, letzter Durchlauf und nächster Lauf),
das Abdeckungs-Panel, ein Button „jetzt scannen“, das Planungsformular und dann die Liste der
Funde: Filter nach Kategorie, Textsuche, Filter nach Elementtyp (script, inline_script,
iframe, stylesheet, pixel, cookie, link, preconnect), Filter nach Zustand,
CSV-Export, Seiten zu 25. Einordnung einzeln oder als Massenvorgang — die Massenauswahl hat
ein deaktiviertes leeres erstes Element, damit ein versehentliches Absenden nicht zu einer
allgemeinen Rückstufung wird.
Einstellungen des Scanners
| Einstellung | Standard | Grenzen |
|---|---|---|
scanner_enabled | false | boolesch |
scanner_frequency | weekly | hourly, twicedaily, daily, weekly |
scanner_max_urls | 25 | 1 bis 500 |
scanner_timeout | 8 | 1 bis 60 |
scanner_probe_mode | admins | admins, off |
scanner_alert_email | '' | E-Mail-Adresse |
Wichtig:
scanner_probe_modewird in dieser Version nicht ausgewertet. Der Code sagt das ausdrücklich — die Bedingung für die Ausgabe der Sonde liest diese Einstellung nicht mehr und stützt sich allein aufscanner_enabled.offzu speichern legt den Wert ab, ohne die Sonde abzuschalten. Um die Sonde wirklich zu stoppen, deaktivieren Sie den Scanner.
Grenzen des Scanners
- Der Server-Durchlauf führt kein JavaScript aus. Ohne die Sonde fehlt im Inventar, was ein Tag-Manager einschleust.
- Die Sonde ist angemeldeten Administratoren vorbehalten, und es gibt keinen Modus, der sie für einen gewöhnlichen Besucher ausführt: Das würde eine eigene vorherige Information erfordern.
- Ein per
Set-Cookie-Header gesetztes Cookie wird erkannt, ist aber nicht blockierbar. - Der Durchlauf verlässt die Domain nie und ist standardmäßig auf 25 URLs gedeckelt: Eine große Website wird nie vollständig abgedeckt.
- Auf einem Host, bei dem HTTP-Loopback blockiert ist (HTTP-Authentifizierung auf einer Staging-Umgebung, Firewall), liest der Durchlauf gar nichts.
- Ein seit 90 Tagen nicht mehr gesehener Fund verschwindet — und damit auch aus der Cookie-Richtlinie.
- Der Scanner hängt an WP-Cron: Auf einer Website mit
DISABLE_WP_CRONund ohne System-Cron wird der geplante Durchlauf nicht ausgelöst.
Der Generator für Rechtstexte
Die vier Dokumente
| Typ | Inhalt | Verfügbare Sprachen |
|---|---|---|
cookie_policy | Cookie-Richtlinie | Französisch, Englisch, Portugiesisch |
privacy_policy | Datenschutzerklärung | Französisch, Englisch, Portugiesisch |
legal_notice | Impressum | nur Französisch |
terms | AGB | nur Französisch |
Jedes erzeugte Dokument ist eine WordPress-Seite, versioniert über Metadaten:
_owc_policy_type, _owc_policy_version (bei jeder Erzeugung hochgezählt),
_owc_policy_hash (SHA-256-Fingerabdruck des HTML), _owc_policy_generated_at,
_owc_policy_profile, _owc_policy_lang, _owc_policy_manual_edit.
Nach der Erzeugung wird der Link in die passenden Einstellungen zurückgeschrieben
(link_cookie_policy, link_privacy_policy, link_legal_notice, link_terms), und die
Veröffentlichung einer Datenschutzerklärung aktualisiert die in WordPress hinterlegte
Datenschutzseite.
Zwei Sperren vor der Veröffentlichung
Sperre 1 — die Pflichtfelder. Die Erzeugung wird verweigert, samt der Liste der leeren Schlüssel, statt lückenhafte Klauseln zu veröffentlichen.
| Dokument | Verlangte Felder |
|---|---|
| Alle | legal_company_name, legal_company_email |
| Außer der Cookie-Richtlinie | + legal_company_address, legal_country |
| Impressum | + legal_company_phone, legal_publication_director, legal_host_name, legal_host_address, legal_host_phone |
| Impressum, Land FR / BE / LU | + legal_company_legal_form, legal_company_reg_number |
Sperre 2 — die Sprache. Der Generator weigert sich, ein Dokument in einer Sprache zu veröffentlichen, die die Jurisdiktion nicht verwendet. In der Vorschau erscheint das Dokument mit einem roten Warnbanner; bei der Veröffentlichung ist es eine klare Verweigerung. Im Tab Policies wird der Erzeugungs-Button ausgeblendet, wenn für den aktiven Typ und das aktive Profil keine Vorlage existiert, statt sichtbar zu sein und regelmäßig zu scheitern.
Auflösung der Sprache
| Profil | Sprache des Dokuments |
|---|---|
quebec | Französisch |
lgpd | Portugiesisch |
gdpr mit legal_country ∈ {FR, BE, LU} | Französisch |
| Alles Übrige | Englisch |
Der obligatorische Hinweis
Solange policy_disclaimer aktiv ist — und das ist es standardmäßig —, endet jedes
Dokument mit einem Block, der sagt, dass es sich um eine automatisch erzeugte Vorlage
handelt, die vor der Veröffentlichung von einer qualifizierten Fachperson geprüft werden
muss, und der das Erzeugungsdatum sowie die Plugin-Version trägt. Schalten Sie ihn nur mit
vollem Bewusstsein ab.
Die Tracker-Tabelle — die Ehrlichkeitsregeln
Die in der Cookie-Richtlinie veröffentlichte Tabelle stammt aus Ihrer Scanner-Tabelle, nicht aus einer Fremddatenbank. Fünf Regeln bestimmen, was sie zeigt.
- Aktualitätsfenster: Veröffentlicht werden nur Funde, die in den letzten 90 Tagen gesehen wurden. Existiert die Spalte der letzten Beobachtung noch nicht, weil eine Migration nicht gelaufen ist, wird das Fenster ignoriert, statt auf einer Website mit Trackern „keine Tracker“ zu veröffentlichen — zu wenig offenzulegen ist die einzige Richtung, in die ein Rechtstext nie scheitern darf.
- Warnhinweis über der Tabelle, abgeleitet aus dem Abdeckungs-Panel des Scanners: nie ein Durchlauf gestartet, keine Seite gelesen, Durchlauf unterbrochen, N URLs fehlgeschlagen, keine Beobachtung mit aktivem JavaScript, Fenster von N Tagen. Ein unvollständiger Durchlauf wird offengelegt, nicht als fertiges Inventar veröffentlicht.
- Nicht eingeordnete Tracker werden nicht versteckt: Sie bekommen einen eigenen Abschnitt. Es sind die, die niemand geprüft hat.
- Ein in einem
Set-Cookie-Header beobachtetes Cookie wird eigens gekennzeichnet, mit einer Anmerkung, dass es vom Server gesetzt wird und keine clientseitige Blockade es aufhalten kann. Es darf also nicht als einwilligungsabhängig dargestellt werden, und die Klausel, die besagt, dass nicht eingeordnete Tracker erst nach der Einwilligung gesetzt werden, trägt die entsprechende Ausnahme. - Der Name des Verantwortlichen und der Link zu seiner Richtlinie stammen aus dem Katalog, nur für Regeln, die auf eine URL zielen. Muster für Cookie-Namen sind ausgeschlossen: In einem Rechtstext behauptet man ohne Beleg nicht, wer Daten verarbeitet.
Die Cookies der Website und die veröffentlichten Dauern
Der Abschnitt „von dieser Website gesetzte Cookies“ listet die Cookies des Plugins selbst
auf: owc_consent (Dauer aus der Erneuerungseinstellung abgeleitet), euconsent-v2, wenn
TCF aktiviert ist, owc_geo, wenn die regionale Erkennung aktiviert ist, owc_gpc
(Sitzungsdauer), owc_gpc_notice (5 Minuten), dazu die Anmelde- und
Einstellungs-Cookies von WordPress.
Die Tabelle der Aufbewahrungsfristen zieht ihre Zahlen aus den tatsächlichen
Einstellungen — ledger_retention_days, retention_form_data_days, retention_dsar_days
und der Erneuerungsdauer der Einwilligung. Kein dekorativer Wert wird veröffentlicht. Die
Dauer des Einwilligungs-Cookies wird aus derselben Rechnung abgeleitet wie das Cookie
selbst, was garantiert, dass eine Einstellung von 0 Monaten auch wirklich „13 Monate“
veröffentlicht und nicht „nie“.
Erkennung des Geschäftstyps (AGB)
Die AGB umfassen 21 Abschnitte, mit Umschaltung zwischen Verkäufer und Dienstleister, Produkten und Leistungen, Angebot und Bestellung sowie eigenen Klauseln je Geschäftstyp.
legal_business_type (auto, vitrine, rental, ecommerce, services, saas,
content) ist die Wahrheitsquelle. Steht der Wert auf auto, untersucht eine Heuristik
die Website — Vorhandensein von WooCommerce, offene Registrierung, Abo-Plugins, Preisseite,
Leistungsseiten, dann Stichwortdichte in den letzten fünfzig veröffentlichten Inhalten —,
aber ihr Urteil wird nie in ein veröffentlichtes Dokument gedruckt: Es dient nur der Wahl
der optionalen Klauseln.
Französische Artikelangaben werden nur eingesetzt, wenn legal_country den Wert FR hat.
Belgien hat seine eigenen Angaben (CDE Art. VI.45 §1, Art. VI.47, Verbraucherombudsdienst);
Luxemburg und Québec bekommen eine neutrale Formulierung. Eine ungeprüfte Fundstelle zu
zitieren wäre der Fehler, nicht das Heilmittel.
Weitere Verhaltensweisen
- Das Datum des Dokuments wird in der Locale des Dokuments formatiert. Ist das passende
Übersetzungspaket nicht installiert, wechselt das Format auf
TT/MM/JJJJ: Ein französisches Dokument kann nicht mit „4 September 2026“ beginnen. - Erkannte manuelle Bearbeitung: Wenn der gespeicherte Inhalt nicht mehr zu seinem Fingerabdruck passt, wird vor dem Überschreiben eine Revision angelegt, und der Bildschirm zeigt den Hinweis „manuelle Änderungen ersetzt“, mit einem Link zu den Revisionen.
- Der Generator stuft nie zurück: Eine veröffentlichte Seite bleibt veröffentlicht, auch wenn das Häkchen „veröffentlichen“ entfernt wird, und ein von Ihnen geänderter Titel oder Permalink überlebt eine Neuerzeugung.
- Einfügen ins Footer-Menü:
auto_footer_menu_inject, standardmäßig deaktiviert. Das Plugin verändert Ihre öffentliche Website nicht ohne ausdrückliche Aufforderung. Erkannte Menüpositionen, wenn Sie es einschalten:footer,footer-menu,footer_menu,footer-1,footer_1,secondary,legal.
Erweiterungspunkte
// Roher Vorlagentext, die {{Variablen}} noch an Ort und Stelle.
add_filter( 'owc_policy_template', function ( $html, $type, $profile ) {
return $html;
}, 10, 3 );
// Die Variablen, die in die Vorlage eingesetzt werden.
add_filter( 'owc_policy_vars', function ( array $vars, $type, $profile ) {
return $vars;
}, 10, 3 );
// Das fertige HTML, Variablen ersetzt.
add_filter( 'owc_policy_html', function ( $html, array $vars ) {
return $html;
}, 10, 2 );
Wer über owc_policy_template seinen eigenen Textkörper liefert, hebt die Sprachsperre
auf: Eine Website, die ihren Text selbst liefert, verantwortet dessen Sprache. Das ist der
offizielle Weg, ein nicht französisches Impressum zu veröffentlichen.
Vier vorgefertigte Blöcke stehen als reservierte Variablen bereit:
{{__trackers_table__}}, {{__categories_list__}}, {{__retention_table__}},
{{__jurisdictional_rights__}}. Alle Variablen sind im Kontext ihrer Verwendung bereits
escaped. Drei öffentliche Methoden lassen sich aus einer eigenen Vorlage wiederverwenden:
OWC_Policies::build_cookie_table(), build_data_retention_table() und
render_first_party_cookies().
REST-Routen
| Methode | Pfad | Parameter | Zugriff |
|---|---|---|---|
POST | /owc/v1/policies/generate | type (erforderlich), publish (boolesch, Standard false) | manage_options |
GET | /owc/v1/policies/preview | type (erforderlich) | manage_options |
Das HTML der Vorschau läuft vor der Rückgabe durch wp_kses_post().
Grenzen des Generators
- Das sind Vorlagen, keine Rechtsberatung. Lassen Sie sie prüfen.
- Impressum und AGB gibt es nur auf Französisch. Jede andere Jurisdiktion stößt auf die Sprachsperre, außer Sie liefern Ihren eigenen Textkörper.
- Nur drei Sprachen: Französisch, Englisch, Portugiesisch.
- Vier EWR-Länder haben eine namentlich genannte Behörde; anderswo eine allgemeine Formulierung.
- Die Tracker-Tabelle ist nur so viel wert wie Ihr Durchlauf — und das Dokument sagt es.
- Die Generator-Klasse enthält rund 440 KB an Rechtsvorlagen: Sie wird verzögert geladen, nur wenn einer der drei Einstiegspunkte wirklich angesprochen wird.
Das Einwilligungsprotokoll
Das Protokoll ist die Antwort auf Artikel 7 Abs. 1 DSGVO: nachweisen zu können, dass die Person eingewilligt hat. Es ist standardmäßig aktiviert.
Die Tabelle
{prefix}owc_ledger, alle Zeitangaben in UTC:
| Spalte | Typ | Inhalt |
|---|---|---|
id | bigint | Primärschlüssel |
created_at | datetime | Zeitstempel in UTC |
visitor_token | char(32) | Pseudonymes Browser-Token, 32 Hexadezimalzeichen |
event | varchar(20) | accept_all, reject_all, save_preferences, withdraw, auto, gpc_opt_out |
categories | varchar(255) | Liste der freigegebenen Kategorien |
profile | varchar(20) | Zum Zeitpunkt der Aktion geltendes Compliance-Profil |
source | varchar(60) | banner, preferences, footer_link, api, auto |
ip_pseudonymous | varchar(45) | Gekürzte IP |
ua_hash | char(64) | Gesalzener Fingerabdruck des User-Agents |
page_url | varchar(500) | Seite, auf der die Aktion stattfand |
prev_hash | varchar(128) | Fingerabdruck der vorherigen Zeile |
row_hash | varchar(128) | Fingerabdruck dieser Zeile |
policies_hash | char(64) | Fingerabdruck der geltenden Dokumente |
banner_revision | varchar(40) | Fingerabdruck des tatsächlich angezeigten Banners |
plugin_version | varchar(20) | Plugin-Version zum Zeitpunkt des Schreibens |
Die letzten drei Spalten erlauben es zu rekonstruieren, was der Besucher gesehen hat, nicht nur, was er angehakt hat.
Die Kette
Jede Zeile wird per HMAC über eine kanonische, längenpräfixierte Serialisierung ihres Inhalts und des Fingerabdrucks der vorherigen Zeile signiert. Der Genesis-Wert ist eine Folge von 64 Nullen. Das Schreiben läuft in einer Transaktion, mit einer Zeilensperre auf dem letzten Eintrag: Diese Sperre serialisiert die nebenläufigen Schreibvorgänge tatsächlich und verhindert, dass sich die Kette gabelt. Eine benannte MySQL-Sperre wird als zweiter Wall genommen, im Rahmen des Möglichen: Wird sie verweigert, läuft das Anhängen weiter, und eine Aktion wird ausgelöst, damit Sie es nachverfolgen können.
Die Werte werden vor der Signatur gekürzt, damit der signierte Wert exakt der gespeicherte Wert ist.
Die Ehrlichkeit zur Fälschungssicherheit
Das Plugin ermittelt selbst, woher sein Signaturschlüssel stammt:
| Herkunft | Bedingung | Urteil |
|---|---|---|
constant | OWC_LEDGER_KEY ist definiert | Fälschungssicher |
wp-config | AUTH_KEY und AUTH_SALT sind definiert, nicht leer, voneinander verschieden und ohne den Standardsatz | Fälschungssicher |
database | Sonst | Nicht fälschungssicher |
Im dritten Fall speichert WordPress die Salts in der Datenbank: Wer Zugriff auf die Datenbank hat, kann die Kette neu signieren. Das Plugin meldet es im Prüfergebnis und zeigt einen Admin-Hinweis, der es unmissverständlich ausspricht. Ein nicht umkehrbarer Fingerabdruck des Schlüssels wird aufbewahrt, wodurch sich eine Salt-Rotation von einer Neuschreibung unterscheiden lässt.
Genau deshalb empfiehlt der Abschnitt Installation, OWC_LEDGER_KEY zu
definieren.
Die Prüfung
Der Button „Verify the chain now“ im Tab Audit ledger — oder die Route
GET /owc/v1/ledger/verify — läuft die gesamte Kette in Paketen zu 500 Zeilen durch.
Drei Signaturschemata werden erkannt: das aktuelle kanonische Schema, ein früheres historisches Schema und ein schlüsselloses Schema aus den allerersten Versionen. Letzteres erzeugt einen Fingerabdruck, den jeder mit Zugriff auf die Datenbank nachrechnen kann: Es gilt nie als gültig, wird getrennt gezählt und als Bruch gemeldet. Ein schlüsselloser Hash ist kein Nachweis.
Gemeldete Brüche: hash_mismatch, chain_break, bad_genesis, unkeyed_rows,
table_emptied, tail_truncated, head_mismatch, count_mismatch.
Das Ergebnis enthält unter anderem: ok, total, checked, table_total, broken_at,
breaks, break_count, partial, legacy_rows, unverifiable_rows, anchor,
anchor_ok, key_source, tamper_evident, key_rotated.
Der Kopf-Anker
Ein Anker wird außerhalb der Tabelle aufbewahrt: Kennung, Fingerabdruck, Zeilenzahl, Zeitstempel. Ohne ihn würde das Löschen der jüngsten Zeilen oder das Leeren der Tabelle keine Spur hinterlassen. Bei jeder Bewegung des Ankers wird eine Aktion ausgelöst, und der Code fordert ausdrücklich dazu auf, ihn außerhalb der Datenbank zu replizieren — Datei, Syslog, externer Endpunkt —, damit ein vollständiges Neuschreiben erkennbar wird.
Das Plugin weigert sich, einen bestehenden Anker zu überschreiben, und weist ehrlich darauf hin, dass ein aus der Tabelle selbst abgeleiteter Anker nur spätere Kürzungen erkennbar macht.
Die Aufbewahrung
ledger_retention_days, Standard 1825 Tage (5 Jahre), Grenzen 0 bis 3650. Der Wert 0
bedeutet unbegrenzte Aufbewahrung.
Das Beschneiden läuft über einen eigenen täglichen Cron und entfernt nur ein zusammenhängendes Präfix: nie ein Loch mitten in der Kette. Der Fingerabdruck der zuletzt gelöschten Zeile wird gemerkt, damit der Rest überprüfbar bleibt. Obergrenze pro Lauf: 20 000 Zeilen (40 Pakete zu 500). Ein sehr großer Rückstand baut sich also über mehrere Tage ab.
Datenminimierung
- IP-Adresse: IPv4 mit auf null gesetztem letztem Oktett (das /24 bleibt erhalten), IPv6 auf /48 gekürzt, die verbleibenden 80 Bit auf null. Die Maskierung erfolgt auf der Binärform; eine IPv6-Adresse, die eine IPv4 abbildet, wird als IPv4 behandelt.
- User-Agent: Nur ein gesalzener Fingerabdruck wird gespeichert, nie die Zeichenkette.
page_url: gegen die Hosts der Website validiert. Der Aufrufer hat Vorrang — liefert er den Wert, auch leer, ist das die Antwort; derRefererwird nur herangezogen, wenn er gar nichts gesagt hat, und er wird auf dieselbe Weise validiert.- Besucher-Token: 32 Hexadezimalzeichen aus einem kryptografischen Generator, ohne Bezug zu einer Identität.
Der Algorithmus
ledger_hash_algo akzeptiert sha256 (Standard) und sha3-256, geschnitten mit den
Algorithmen, die Ihr PHP tatsächlich unterstützt. Die Einstellung wird im Backend angezeigt,
ist aber nicht änderbar: Ein Algorithmuswechsel würde die Prüfung aller bestehenden Zeilen
scheitern lassen. Die Spalten sind großzügiger dimensioniert, die tatsächliche Auswahl
beschränkt sich aber auf diese beiden Algorithmen.
Der Tab Audit ledger
Liste mit Seiten zu 25: Kennung, lokales Datum und roher UTC-Zeitstempel, Besucher-Token, Ereignis, Kategorien, Profil, pseudonymisierte IP und das Kettenglied (vorheriger Fingerabdruck → aktueller Fingerabdruck, in der Anzeige gekürzt, vollständiger Wert als Tooltip).
Filter: Besucher-Token (32 Hexadezimalzeichen), Ereignis, Profil, Datumsbereich — eingegeben in der Zeitzone der Website und mit den tatsächlich gespeicherten UTC-Zeitstempeln verglichen.
Exporte als CSV und JSON. Das JSON trägt einen Umschlag (Format, Algorithmus, Herkunft des Schlüssels), damit eine Behörde den Auszug nachprüfen kann, ohne den Rest der Kette zu haben. Alle CSV-Zellen sind gegen Tabellenkalkulations-Formelinjektion entschärft.
Das Protokoll über die API abfragen
GET /owc/v1/ledger akzeptiert page, per_page (1 bis 200, Standard 50), visitor_token,
from und to. Mit den letzten dreien lässt sich ein Auskunftsersuchen (Art. 15)
beantworten, ohne die gesamte Kette zu durchlaufen. Die Grenzen werden in UTC gelesen, und
ein Datum im Format JJJJ-MM-TT wird auf den ganzen Tag erweitert. Die tatsächlich
angewendeten Filter kommen in der Antwort zurück: Ein von den Prüfungen verworfener Filter
darf sich nicht als „hier ist das gesamte Protokoll“ lesen.
Was passiert, wenn das Protokoll einen Schreibvorgang verweigert
Das ist das wichtigste Verhalten des gesamten Plugins. Ist das Protokoll aktiviert und schlägt das Schreiben der Zeile fehl, wird das Einwilligungs-Cookie verworfen und die Antwort ist ein 503. Nichts wird gespeichert, kein Tracker wird freigegeben.
Die Begründung ist geradeheraus: Eine Einwilligung, die man nicht nachweisen kann, darf man nicht beanspruchen. Zum Vorgehen siehe Fehlerbehebung.
Erweiterungspunkte
add_action( 'owc_consent_updated', function ( $categories, $event, $source ) {}, 10, 3 );
add_action( 'owc_consent_cookie_not_sent', function ( $cookie, $event ) {}, 10, 2 );
add_action( 'owc_ledger_lock_failed', function ( $event, $token ) {}, 10, 2 );
add_action( 'owc_ledger_write_failed', function ( $error, $event, $token ) {}, 10, 3 );
add_action( 'owc_ledger_anchor', function ( array $anchor ) {} );
add_action( 'owc_ledger_pruned', function ( $deleted, $days ) {}, 10, 2 );
owc_ledger_anchor ist der Hook, mit dem Sie den Anker außerhalb der Datenbank replizieren.
Grenzen des Protokolls
- Die Fälschungssicherheit ist an eine Bedingung geknüpft, und das Plugin sagt es selbst.
- Zeilen aus der Zeit vor 1.2.0 tragen einen schlüssellosen Hash: Sie werden nie neu signiert — eine Neusignatur würde es einem Angreifer erlauben, eine gefälschte Historie neu signieren zu lassen — und sie verhindern das Urteil „Kette intakt“, solange sie bestehen.
- Die Aufbewahrung ist auf 20 000 Zeilen je täglichem Lauf gedeckelt.
- Das Protokoll wird vom WordPress-Eraser für personenbezogene Daten nicht gelöscht: Es ist eine Hash-Kette, sie zu entfernen würde genau den Nachweis zerstören, für den sie da ist, und sie enthält nur ein pseudonymes Token und eine gekürzte IP. Eine Meldung erklärt diese Entscheidung der betroffenen Person.
Das Portal für Betroffenenrechte (DSAR)
Das Portal erlaubt es einer Person, ihre Rechte von einer Seite Ihrer Website aus wahrzunehmen. Es ist standardmäßig aktiviert, erscheint aber nur dort, wo Sie den Shortcode platzieren.
Das Formular
[owc_dsar_form]
Attribute:
| Attribut | Standard | Zweck |
|---|---|---|
types | access,rectification,erasure,portability,restrict,object,optout | Angebotene Typen, durch Kommas getrennt |
title | „Meine Rechte an meinen personenbezogenen Daten wahrnehmen“ | Titel des Blocks |
submit_label | „Anfrage senden“ | Beschriftung des Buttons |
Ist dsar_enabled deaktiviert, zeigt der Shortcode „das Portal ist deaktiviert“ und die
REST-Route antwortet mit 404: Die Abschaltung wirkt tatsächlich serverseitig.
Die von Ihnen angeforderte Liste wird mit der Liste geschnitten, die der Server akzeptiert: Eine vom Endpunkt abgelehnte Option wird dem Besucher nie angeboten.
Die acht Anfragetypen
access, rectification, erasure, portability, restrict, object, optout,
withdraw.
withdraw ist bewusst aus dem Angebot des Formulars entfernt. Die Einwilligung in
Cookies zurückzuziehen geht im Präferenz-Panel sofort; sie durch ein schriftliches Verfahren
von 30 Tagen zu schleusen, würde den Widerruf schwerer machen als die Einwilligung
(Art. 7 Abs. 3 DSGVO). Ein Link unter dem Formular öffnet für diesen Fall direkt das
Präferenz-Panel.
Der Filter owc_dsar_types ist die einzige Wahrheitsquelle: Die Allowlist des Endpunkts wird
daraus abgeleitet.
Der vollständige Ablauf
1. Einreichung. POST /owc/v1/dsar. Drei serverseitige Schutzmaßnahmen, in dieser
Reihenfolge:
- Honeypot: Ein ausgefülltes verstecktes Feld führt zu einer Ablehnung mit 400 und der allgemeinen Meldung einer fehlerhaften Einreichung — ein Bot erfährt nichts über den Grund seiner Zurückweisung. Im Browser zeigt das Formular sogar die Erfolgsmeldung, ohne etwas zu senden.
- Bestätigung (Art. 12 Abs. 6): Das Kästchen „ich bestätige, ein Recht an MEINEN eigenen personenbezogenen Daten wahrzunehmen“ muss angehakt sein, und das wird serverseitig geprüft, nicht nur im Browser. Es wird zusammen mit der Anfrage gespeichert.
- Mindestwartezeit von 3 Sekunden zwischen Anzeige des Formulars und Absenden, clientseitig.
Rate-Limits: 3 pro Stunde und IP-Adresse, 3 pro Tag und betroffener E-Mail-Adresse — die Adresse wählt der Angreifer, also muss genau sie gedeckelt werden — und 30 pro Stunde für die gesamte Website.
Die Zeile wird mit dem Status pending eingefügt, dazu ein Token aus 64 Zeichen, von dem
nur der SHA-256-Fingerabdruck gespeichert wird, ein Ablaufdatum des Tokens und eine
Antwortfrist. Die Kennung wird nicht zurückgegeben: keine Aufzählung, kein Rückschluss
auf das Volumen. Die Antwort lautet {ok, mail_sent, message}, und mail_sent gibt einen
tatsächlichen Versandfehler wieder.
Der Datenschutzbeauftragte wird an dieser Stelle nicht benachrichtigt. Sonst würde ein anonymer Aufrufer je Einreichung zwei E-Mails von Ihrer Domain aus losschicken.
2. Verifizierungs-E-Mail. Der Link zeigt auf Ihre Startseite, mit dem Token im Klartext
als Parameter. Gültigkeit: dsar_token_ttl_days, Standard 7 Tage, Grenzen 1 bis 90. Die
E-Mail trägt einen Reply-To-Header, aber nie ein umgeschriebenes From — den Envelope
umzuschreiben ist es, was SPF zerlegt. Die Antwortadresse ist dsar_email, sonst
legal_dpo_email; niemals die Administrationsadresse der Website, die nicht
veröffentlicht werden darf.
3. Identitätsbestätigung. Der Link öffnet eine Seite, die nichts ausführt: Die Bestätigung erfolgt über einen mit Nonce geschützten POST. Genau das verhindert, dass ein Link-Scanner eines Mailsystems (Safe Links, URL Defense, Inbox-Vorschau) eine Identität anstelle der Person bestätigt.
Die Seite ist ein eigenständiges HTML-Dokument, außerhalb des Themes ausgeliefert, mit
noindex, nofollow und nicht cachebaren Headern. Die Versuche sind auf 30 pro Stunde und IP
begrenzt. Die Antworten sind unterscheidbar: 404 für einen unbekannten Link, 200 für einen
bereits bestätigten Link, 410 für einen abgelaufenen Link, 403 für ein abgelaufenes Nonce,
500 für einen Schreibfehler, 200 für eine erfolgreiche Bestätigung.
4. Was die Bestätigung auslöst.
- Der Status wechselt auf
verified. - Die Frist wird ab der Verifizierung neu berechnet. Artikel 12 Abs. 3: Die Frist läuft ab dem Zeitpunkt, an dem die Anfrage vollständig ist, nicht ab einer nie bestätigten Einreichung.
- Das Token wird verbrannt. Sein Fingerabdruck wird bewusst aufbewahrt, damit eine Person, die ihren Link erneut öffnet, „bereits bestätigt“ liest statt eines 404, das sie zwingen würde, von vorn zu beginnen. Die Einmaligkeit sichert die Statusprüfung.
- Gespeichert werden: das Datum der Bestätigung, die gekürzte IP, das pseudonyme Browser-Token — die einzig mögliche Brücke zwischen Einwilligungsprotokoll und Anfrage — und die Kennung der zugehörigen WordPress-Anfrage.
- Eine native WordPress-Anfrage wird eröffnet, mit bereits nachgewiesener Identität, also
direkt in Ihrer Warteschlange unter Werkzeuge → Personenbezogene Daten exportieren /
löschen. Damit erfasst die Ausführung alle Plugins der Website, nicht nur OW Consent.
Zuordnung:
accessundportability→ Export;erasure→ Löschung; die anderen Typen eröffnen keine native Anfrage. - Der Verantwortliche wird an
dsar_emailunddsar_notify_emailbenachrichtigt, mit Rückfall auf die Administrationsadresse, wenn keine davon gültig ist.
5. Ausführung. Ein Panel über dem Tab DSAR requests listet die 20 verifizierten Anfragen, nach Frist sortiert, mit der Zahl der verbleibenden oder überzogenen Tage.
| Aktion | Verhalten |
|---|---|
| Daten herunterladen (JSON) | Ablehnung mit 409, wenn die Identität nie bestätigt wurde. Die Datei heißt dsar-<id>-<JJJJMMTT>.json |
| Daten löschen | Nur für eine Anfrage vom Typ erasure angeboten, und erst nach der Identitätsbestätigung. Die Anfrage wird vor der Löschung abgeschlossen, sonst würde der Freitext der laufenden Anfrage ihre eigene Ausführung überleben |
| +2 Monate | Verlängerung nach Art. 12 Abs. 3, nur einmal, mit einer Begründung von höchstens 500 Zeichen. Die Frist verschiebt sich um 60 Tage, die Erinnerungen werden neu scharf geschaltet, und die betroffene Person erhält eine E-Mail mit der neuen Frist und den Gründen |
| Abschließen | Status resolved oder rejected, Notiz verpflichtend. Eine bereits abgeschlossene Anfrage lässt sich nicht neu schreiben, und „erfüllt“ lässt sich nicht auf eine nie bestätigte Identität eintragen |
| Link erneut senden | Erzeugt ein neues Token, wodurch das vorherige ungültig wird |
Fünf Status: pending, verified, resolved, rejected, expired.
Der Bildschirm lädt niemals das Token oder dessen Fingerabdruck und zeigt den Namen der anfragenden Person nicht an.
6. Fristüberwachung. Im täglichen Cron: bis zu 200 verifizierte Anfragen nach Frist durchlaufen, eine Erinnerung sieben Tage vorher, eine Erinnerung bei Überschreitung, jeweils genau einmal. Ein Banner im Backend weist auf überfällige Anfragen und auf solche mit weniger als sieben Tagen hin.
7. Bereinigung. Nie verifizierte Einreichungen werden nach Ablauf ihres Tokens gelöscht,
und abgeschlossene Anfragen werden über retention_dsar_days hinaus gelöscht. Gemessen wird
ab dem Abschluss, nicht ab der Einreichung.
Das Portabilitäts-Bundle
Der Export erzeugt ein Dokument im Format ow-consent/dsar-export, mit Zeitstempel,
Website, betroffener Person, Anfrage und Datengruppen. Er ruft alle registrierten Exporter
der Website auf, paginiert bis zu 50 Seiten je Exporter und stoppt nach 20 Sekunden. Die
Löschung tut dasselbe auf Seiten der Eraser, mit denselben Grenzen.
Filter: owc_dsar_export_bundle( $bundle, $email, $id ).
Was Export und Löschung abdecken, hängt also von den auf Ihrer Website installierten Plugins ab: Ein Plugin, das keinen dieser Hooks registriert, muss von Hand behandelt werden.
Anbindung an die Bordmittel von WordPress
- Exporter, registriert unter dem Schlüssel
ow-consent, mit zwei Gruppen: die Betroffenenanfragen und das Einwilligungsprotokoll. - Eraser:
- nie bestätigte Einreichungen werden gelöscht — kein Beweiswert, nur personenbezogene Daten;
- bei abgeschlossenen Anfragen werden Freitext und Name gelöscht, die minimale Zeile
(Datum, Typ, Status) bleibt als Nachweis erhalten (Art. 5 Abs. 2), bis
retention_dsar_dayserreicht ist; - eine noch offene Anfrage bleibt erhalten, mit einer Meldung, die erklärt, dass sie beantwortet werden muss, bevor sie gelöscht wird;
- das Einwilligungsprotokoll wird nicht gelöscht, aus dem oben erklärten Grund.
- Das Plugin speist außerdem den Entwurf der Datenschutzerklärung von WordPress.
Der Informationshinweis unter dem Formular
Unter dem Formular trägt ein aufklappbarer Block die Information nach Artikel 13: Identität
und Anschrift des Verantwortlichen, Datenschutzkontakt, Zweck und Rechtsgrundlage
(Art. 6 Abs. 1 lit. c), erhobene Daten, Empfänger und Speicherdauer, Antwortfrist und
Möglichkeit der Verlängerung, zuständige Aufsichtsbehörde, Link zur Datenschutzerklärung.
Filter: owc_dsar_form_notice( $html, $context ).
Die angezeigte Behörde stammt aus der Ableitung, die unter Die elf Compliance-Profile beschrieben ist, und wird nur übernommen, wenn sie mit einem Großbuchstaben beginnt: Die Roheinstellung zu lesen würde auf einer südafrikanischen, indischen, australischen oder kalifornischen Website die französische Behörde nennen.
Ohne JavaScript wird der Absende-Button ausgeblendet, und eine Meldung schlägt die Kontaktadresse vor — damit der Browser nie eine native Übermittlung ausführt, die die Adresse der anfragenden Person in die URL schriebe und damit in die Logs aller durchlaufenen Server und Proxys.
DSAR-Einstellungen
| Einstellung | Standard | Grenzen |
|---|---|---|
dsar_enabled | true | boolesch |
dsar_email | '' | öffentlicher Kontakt und Empfänger der Benachrichtigungen |
dsar_notify_email | '' | zusätzlicher Empfänger |
dsar_response_days | 30 | 1 bis 30 — nie mehr als ein Monat |
dsar_token_ttl_days | 7 | 1 bis 90 |
retention_dsar_days | 1095 (3 Jahre) | 1 bis 3650 |
Erweiterungspunkte
add_action( 'owc_dsar_submitted', function ( $type, $email, $message ) {}, 10, 3 );
add_action( 'owc_dsar_verified', function ( $id, array $row ) {}, 10, 2 );
add_action( 'owc_dsar_fulfilled', function ( $id, $what, $trace ) {}, 10, 3 );
add_action( 'owc_dsar_mail_failed', function ( $id, $email, $kind ) {}, 10, 3 );
Grenzen des Portals
- Die Identität ruht auf einem einzigen Faktor: dem E-Mail-Rückkanal. Jeder weitere Nachweis nach Art. 12 Abs. 6 wird von Hand in den Notizen der Anfrage festgehalten.
- Ein fehlgeschlagener E-Mail-Versand blockiert den Ablauf: Die Antwort weist
mail_sent: falseaus, und das Formular zeigt eine Meldung, die auf die Kontaktadresse verweist — aber die Anfrage bleibtpending, und die gesetzliche Frist beginnt nicht. - Fristerinnerungen und Bereinigung hängen an WP-Cron.
- Die Anfragetabelle wird bei der Deinstallation des Plugins immer gelöscht, unabhängig von Ihrer Einstellung. Exportieren Sie, bevor Sie löschen.
Das CCPA-Opt-out „Do Not Sell or Share“
Unter den US-Profilen verlangt das Gesetz ein benanntes, sichtbares Bedienelement, das das Opt-out tatsächlich ausführt.
Zwei Wege, es zu platzieren
Shortcode, wo Sie wollen:
[owc_dnsmpi]
[owc_dnsmpi label="Meine personenbezogenen Daten nicht verkaufen oder weitergeben" class="mein-link"]
| Attribut | Standard |
|---|---|
label | „Do Not Sell or Share My Personal Information“ |
class | owc-dnsmpi |
Automatisches Einfügen im Footer: Einstellung ccpa_inject_footer, standardmäßig
aktiv, gerendert auf wp_footer mit Priorität 20.
Was ein Klick bewirkt
Ein Klick führt das Opt-out aus. Er öffnet kein Panel. Das Runtime holt ein frisches
Nonce und sendet dann ein reject_all mit der Quelle footer_link und allen optionalen
Kategorien auf false. Der Link wechselt auf aria-busy="true", und ein Bereich mit
role="status" zeigt den Zustand: „wird gespeichert“, dann „Ihr Opt-out wurde für diesen
Browser gespeichert“ — oder die Fehlermeldung.
Der Code nennt den Grund: Nach den CCPA-Durchführungsvorschriften (§7026(a)(1)) ist ein Link, der lediglich ein Panel öffnet, kein konformer Mechanismus.
Rückfall ohne fetch und Promise (alte WebView, In-App-Browser): Der Klick öffnet das
Präferenz-Panel mit den Werbekategorien bereits auf aus.
Der Cache-Zwang
Das ausgelieferte HTML ist für alle gleich. Der Link wird deshalb sichtbar gerendert, wenn
das konfigurierte Profil der Website ccpa oder us_generic ist; sonst wird er versteckt
gerendert und clientseitig eingeblendet für die Besucher, deren Jurisdiktion ihn
verlangt, anhand des Cookies der regionalen Erkennung.
Ist die regionale Erkennung deaktiviert und Ihr konfiguriertes Profil kein amerikanisches, wird der Block gar nicht erst ausgegeben: kein totes Markup.
In der JavaScript-Konfiguration dieses Moduls reist keinerlei Besucherdatum mit — nur die Listen der Profile, nie der aufgelöste Boolean.
Die Assets dieses Moduls werden in <head> ausgegeben, nicht im Footer, damit die
Consent-Mode-Ablehnung gtag erreicht, bevor ein Tag-Manager auslöst. Das JavaScript ist
reines ES5.
Grenzen
- Das Ein-Klick-Element verlangt
fetchundPromise. - Der Link ist nur unter den Profilen
ccpaundus_genericvorgeschrieben; unter jedem anderen Profil wird er weder angezeigt noch eingeblendet. - Das clientseitige Einblenden hängt am Cookie der regionalen Erkennung, also an JavaScript.
Google Consent Mode v2
Das Modul ist standardmäßig aktiviert (gcm_enabled).
Die sieben Signale
Alle sieben Signale von Consent Mode v2 werden gesendet: ad_storage, ad_user_data,
ad_personalization, analytics_storage, functionality_storage,
personalization_storage und security_storage. Die sechs Kategorien des Plugins sind ihnen
über eine einzige Wahrheitsquelle zugeordnet, was garantiert, dass Banner, Blockade und
Bootstrap nicht auseinanderlaufen können. Die Tabelle steht unter
Die Cookie-Kategorien.
Die Standardwerte, vor jeder Einwilligung
Der default-Aufruf wird als statisches Markup ausgegeben, und das update wird im
Browser berechnet: Genau das hält die Seite cachebar.
| Signal | Opt-in-Rahmen | Opt-out-Rahmen |
|---|---|---|
ad_storage | denied | granted |
analytics_storage | denied | granted |
ad_user_data | denied | granted |
ad_personalization | denied | granted |
personalization_storage | denied | granted |
functionality_storage | denied, wenn die Website die Kategorie functional anbietet, sonst granted | granted |
security_storage | immer granted | granted |
Beide Sätze werden in derselben Seite ausgegeben. Das Runtime wählt anhand des Cookies der regionalen Erkennung, welcher gilt. Ohne das würde eine gecachte Seite die Jurisdiktion eines US-Besuchers auf einen europäischen Besucher festnageln.
Die beiden zugehörigen Einstellungen
| Einstellung | Standard | Wirkung |
|---|---|---|
gcm_ads_data_redaction | true | Verdeckt Werbekennungen, solange ad_storage abgelehnt ist |
gcm_url_passthrough | true | Reicht gclid / dclid über die URLs weiter, solange Cookies abgelehnt sind |
Gut zu wissen
security_storage wird von einem Update nie angerührt: Es bleibt freigegeben, so wie es die
Spezifikation vorsieht. Das Dashboard zeigt eine Karte, die angibt, ob Consent Mode aktiv
ist.
IAB TCF v2.2
Das TCF-Modul ist standardmäßig deaktiviert, und es verlangt eine Kennung, die das Plugin nicht liefern kann. Lesen Sie den Abschnitt zu den Grenzen, bevor Sie es aktivieren.
Aktivierung
| Einstellung | Standard | Grenzen |
|---|---|---|
tcf_enabled | false | boolesch |
tcf_cmp_id | 0 | 0 bis 4095 |
tcf_publisher_country | FR | ISO-Code mit 2 Buchstaben |
tcf_publisher_purposes_li | [] | Liste von Zwecken |
tcf_special_features | [] | Liste von Special Features |
Die Obergrenze 4095 ist nicht willkürlich: Das Feld CmpId belegt 12 Bit im TCF-String.
Drei Fälle, in denen das Modul gar nichts ausgibt
- Keine CMP-ID (
tcf_cmp_id < 1): kein__tcfapi, kein TC-String, kein Cookieeuconsent-v2, keine REST-Route. Ein Admin-Hinweis erklärt es. Die CMP-ID muss Ihnen von IAB Europe zugeteilt werden; das Plugin liefert keine. Einen String mit CmpId 0 auszugeben wäre schlimmer, als gar nichts auszugeben. - CMP-ID größer als 4095: dieselbe Verweigerung, mit eigenem Hinweis. Ein auf 12 Bit gekürzter Wert würde eine andere CMP bezeichnen — eine Identitätsanmaßung.
- Keine Global Vendor List im Cache: Der Stub wird ausgegeben, aber die API antwortet
mit
cmpStatus: 'error'und einem leeren String, statt eine Listenversionsnummer zu erfinden.
Eine Diagnose wird in eine Option geschrieben (disabled, missing_cmp_id, no_gvl,
active), und zwar nur im Backend- oder Cron-Kontext, nie auf einer öffentlichen Seite.
Die Global Vendor List
- Quelle:
https://vendor-list.consensu.org/v3/vendor-list.json. - Wird nie während des Renderns einer Seite heruntergeladen. Darum kümmert sich ein täglicher Cron, mit einem ersten Lauf fünf Minuten nach der Aktivierung; im Backend mit kaltem Cache wird ein einmaliger Abruf eingereiht.
- Anfrage: 5 Sekunden Timeout, 2 Weiterleitungen, Antwort auf 4 MB gedeckelt. Ein Body, der die Obergrenze erreicht, gilt als abgeschnitten und wird verworfen.
- Je Anbieter werden nur die nützlichen Felder behalten; die Stacks werden geleert. Bleibt die Serialisierung zu groß, greifen zwei Kürzungsstufen: zuerst die Bezeichnungen und URLs, dann die Reduktion auf die reinen Zwecke.
- Aufbewahrung: eine Woche in einem Transient, mit stale-if-error — schlägt der Abruf fehl, bleibt die letzte gültige Kopie erhalten.
- Öffentliche Route:
GET /owc/v1/tcf/gvl, begrenzt auf 10 Anfragen pro Stunde. Sie liefert die gecachte Kopie mit einemETagund einemCache-Control: public, max-age=86400und behandelt bedingte Anfragen. Ist nichts im Cache, antwortet sie mit 503 und einemRetry-After: 300— niemals mit einer erfundenen Liste. Diese Route löst nie eine ausgehende Anfrage aus.
Wo der TC-String berechnet wird
Im Browser, nicht in PHP. Ein vollständig statischer Stub wird in <head> mit
Priorität 0 ausgegeben: Locator-iframe, Implementierung von window.__tcfapi,
postMessage-Relay und ein Encoder für das Core-Segment in JavaScript. Die veröffentlichte
Konfiguration enthält keinerlei Besucherdaten — genau das hält sie mit einem Page-Cache
verträglich. Filter: owc_tcf_stub_config.
Ein PHP-Spiegel des Encoders existiert, hat aber keinen Aufrufer im Plugin: Er ist Integrationen und Tests vorbehalten, mit dem Hinweis, ihn niemals in cachebares HTML auszugeben.
Was kodiert wird
Nur das Core-Segment, in base64url ohne Padding. Der Anbieterabschnitt wird entweder als Bitfeld oder als Bereiche kodiert: Beide Größen werden gemessen, die kleinere gewinnt. Der an den Browser übergebene Anbieterindex nutzt ein eigenes kompaktes Format, mit einer harten Obergrenze, ab der der Index geleert wird (die Anbieter-Einwilligungen gehen dann verloren, die Listenversion bleibt erhalten).
Zuordnung Kategorien → TCF-Zwecke
| Kategorie | Zwecke |
|---|---|
necessary | keine — außerhalb des TCF-Geltungsbereichs, was garantiert, dass „Alle ablehnen“ keine Einwilligung für Zweck 1 erzeugen kann |
functional | 1 |
analytics | 1, 8, 9, 10 |
marketing | 1, 2, 3, 4, 7 |
preferences | 1, 5, 6, 11 |
social | 1 |
Filter: owc_tcf_purpose_map.
Berechtigtes Interesse des Publishers: Nur die Zwecke 2, 7, 8, 9, 10 und 11 werden
übernommen, weil TCF v2.2 das berechtigte Interesse für die Zwecke 1, 3, 4, 5 und 6
untersagt. Jeder andere Wert in tcf_publisher_purposes_li wird stillschweigend verworfen.
Ein Anbieter gilt als eingewilligt, sobald mindestens einer der Zwecke freigegeben ist, die er auf der Grundlage „Einwilligung“ deklariert.
Die Special Features
Nur zwei Einträge werden unterstützt: 1 — Verwendung genauer Standortdaten und
2 — aktives Auslesen von Geräteeigenschaften. Deklarieren Sie in tcf_special_features,
welche Sie nutzen; die Liste wird auf diesen Katalog zurückgeschnitten.
Sie erscheinen als echte Kontrollkästchen im Präferenz-Panel. „Alle akzeptieren“ hakt sie nicht an: Sie verlangen ein eigenes ausdrückliches Opt-in. „Alle ablehnen“ und „Do Not Sell“ hingegen entfernen die Häkchen. Sie leben im TC-String selbst und werden beim erneuten Öffnen des Panels aus der TCF-API rehydriert.
Die TCF-Ebene im Panel
Sie wird nur gerendert, wenn das Modul aktiv ist, also tcf_enabled und eine brauchbare
CMP-ID. Zwei Blöcke:
- Zwecke: nur die, die über eine nicht erzwungene Kategorie erreichbar und im Katalog der Anbieterliste benannt sind. Ein Schalter, der von allein zurückspringt, wäre schlimmer als gar kein Schalter. Einen Zweck umzuschalten schreibt in alle Kategorien, die ihn deklarieren, danach wird die Anzeige neu abgeleitet.
- Die deklarierten Special Features.
Nichts wird in den String kodiert, was nicht angezeigt wurde.
Die JavaScript-API
window.__tcfapi( command, version, callback, parameter );
// Befehle: ping, getTCData, getInAppTCData,
// addEventListener, removeEventListener, getVendorList
window.__owcTcfUpdateState( tcData ); // ersetzt die Daten und benachrichtigt die Listener
window.__owcTcfRefresh(); // rechnet neu und sendet 'useractioncomplete'
window.__owcTcfUiShown(); window.__owcTcfUiHidden();
window.__owcTcfSetSpecialFeatures( [ 1, 2 ] );
Akzeptierte Versionen: fehlend, null, 2, '2', 2.2, '2.2'. Jeder andere Wert liefert
callback(null, false).
gdprApplies
Wird clientseitig entschieden. Ist die regionale Erkennung deaktiviert, lautet der Wert
true. Andernfalls wird das Land des Besuchers mit der Liste der 31 Codes verglichen, in
denen die DSGVO im Sinne von TCF gilt (27 EU-Länder, dazu IS, LI, NO, GB und CH).
Geschlossener Fehlschlag: Ein unbekanntes Land ergibt true.
Das Cookie euconsent-v2
Wird ausschließlich clientseitig geschrieben, und nur, wenn das Modul bereit ist und
der Besucher gehandelt hat. Andernfalls wird das Cookie gelöscht. Seine Dauer ist die der
Einwilligung, gedeckelt auf 13 Monate (Empfehlung von IAB / CNIL). SameSite=Lax, unter
HTTPS Secure.
Grenzen des TCF-Moduls — unbedingt lesen
- Das ist keine bei IAB Europe registrierte CMP. Es verlangt Ihre eigene CMP-ID, und selbst damit schreibt die TCF-Policy einer registrierten CMP vor, Auswahlmöglichkeiten auf Zweck- und auf Anbieterebene anzubieten. Hier folgen die Zweckschalter den Kategorien, und es gibt keine Auswahl auf Anbieterebene: Anbieter dürfen dieses Signal zurückweisen. Der Backend-Bildschirm sagt das und spricht von „CMP-kompatiblem Modus (inoffiziell)“, den die meisten SSPs in der Entwicklung akzeptieren, im echten Produktivbetrieb im EWR aber ablehnen. Wenn Werbeerlöse unter TCF für Sie zählen, nutzen Sie eine zertifizierte CMP.
- Nur das Core-Segment: kein Segment
disclosedVendors,allowedVendorsoderpublisherTC. - Es werden keine Publisher Restrictions ausgegeben: Der entsprechende Zähler steht immer auf 0, und das Restriktionsobjekt ist leer.
purposeOneTreatmentunduseNonStandardTextssind immerfalse,isServiceSpecificist immertrue— es gibt keine globale Geltung — und der Consent Screen ist immer 0.getVendorListignoriert den Versionsparameter und liefert immer die gecachte Liste.- Die Publisher-Einwilligungen übernehmen die allgemeinen Zwecke: keine eigenen Zwecke.
- Nur zwei Special Features.
- Das Modul verlangt einen funktionierenden Cron und ausgehendes HTTPS. Ohne gecachte
Liste antwortet die API mit
cmpStatus: 'error', und die öffentliche Route liefert 503.
Global Privacy Control
GPC ist ein Signal, das der Browser sendet — der Header Sec-GPC: 1 und die Eigenschaft
navigator.globalPrivacyControl. Das Plugin beachtet es standardmäßig (gpc_honor), aber
seine Behandlung hängt vom Rechtsrahmen ab, und das ist der entscheidende Punkt.
Unter den US-Profilen: bindend
Das Signal wird unter den Profilen ccpa und us_generic als bindendes universelles Opt-out
behandelt. Australien ist ausdrücklich ausgenommen: Opt-out-Rahmen, der GPC aber nicht
anerkennt.
Der serverseitige Schreibvorgang erfolgt erst nach einer vollständigen Prüfkette, in dieser Reihenfolge:
gpc_honorist aktiviert;- das Signal ist vorhanden — der Header
Sec-GPC, mit Rückfall aufX-Sec-GPC, weil manche Proxys und CDNs den Header umbenennen; nur der exakte Wert1zählt; - das effektive Profil ist
ccpaoderus_generic— sonst wird nichts geschrieben; - es handelt sich um einen einfachen Seitenaufruf: kein Backend, kein Cron, kein AJAX, kein
REST, kein XML-RPC, kein WP-CLI, und die Methode ist
GET; - die Header sind noch nicht gesendet — ein Cookie, das man nicht setzen kann, ist eine Entscheidung, die man bei jeder Anfrage erneut erfassen würde;
- der Sitzungsmarker
owc_gpcfehlt: einmal je Browsersitzung; - der Besucher sieht nicht nach einem Bot aus (leerer User-Agent oder einer, der
bot,crawl,spider,slurp,monitor,uptime,pingdom,headless,preview,curl/,wget,python-,java/,go-http,okhttp,httpclient,libwwwoderfacebookexternalhitenthält); - die bereits gespeicherte Wahl erfüllt das Signal noch nicht — sonst wird nur der Browser markiert;
- das gemeinsame Rate-Limit ist eingehalten: 30 pro Stunde und IP;
- der Browser wird vor dem Schreiben markiert, damit ein Fehlschlag nicht zu einer Wiederholungsschleife wird.
Das Ereignis wird als gpc_opt_out mit der Quelle auto erfasst. Die Seiten-URL wird aus
der Website-URL und dem angefragten Pfad rekonstruiert — niemals aus dem Host-Header,
niemals aus dem Referer.
Reichweite: Alle optionalen Kategorien gehen auf false; die erzwungenen Kategorien
bleiben freigegeben. Das ist eine weite Auslegung des Begriffs von Verkauf oder Weitergabe.
Transparenz: Wenn GPC eine ausdrücklich erfasste Wahl überschreibt, löst ein Fünf-Minuten-Cookie clientseitig einen Hinweis am unteren Bildschirmrand aus, der das erklärt, mit einem Button „meine Präferenzen verwalten“, der das Panel öffnet, und einem Schließen-Button.
Unter den DSGVO-Profilen und Verwandten: nur ein Hinweis
Außerhalb der amerikanischen Opt-out-Rahmen wird das Signal als Hinweis behandelt, niemals als Einwilligung:
- das Attribut
data-owc-gpc="1"wird auf<html>gesetzt; - Consent Mode setzt
ad_storage,analytics_storage,ad_user_data,ad_personalizationundpersonalization_storageaufdenied; - alle optionalen Kategorien werden nur im Arbeitsspeicher auf
falsegesetzt; givenbleibt falsch, das Banner bleibt sichtbar, und nichts wird erfasst.
Ein internes Flag verhindert, dass das Runtime dem Besucher mitteilt, er sei „bereits im Opt-out“, obwohl weder das Cookie noch das Protokoll das hergeben. Die Begründung steht im Code: GPC ist unter DSGVO und ePrivacy, unter dem Schweizer revDSG, dem LGPD, POPIA, PIPL, DPDP und der Loi 25 kein rechtlich anerkanntes Signal.
Die beiden Cookies dieses Moduls
| Cookie | Dauer | Zweck |
|---|---|---|
owc_gpc | Sitzung | Merkt, dass das Signal für diesen Browser schon behandelt wurde |
owc_gpc_notice | 300 s | Löst den Hinweis „GPC hat Ihre Wahl ersetzt“ aus |
Beide liegen auf path=/, SameSite=Lax, unter HTTPS Secure, und sind per Skript lesbar.
Erweiterungspunkt
add_action( 'owc_gpc_honored', function ( array $categories ) {} );
Die regionale Erkennung
Die regionale Erkennung wendet auf jeden Besucher das Profil seiner Jurisdiktion an statt des konfigurierten Profils der Website. Sie ist standardmäßig deaktiviert.
| Einstellung | Standard |
|---|---|
geo_enabled | false |
geo_default_profile | gdpr |
geo_mmdb_enabled | false |
Die Erkennungskaskade
Der erste Treffer gewinnt:
- Cloudflare (
CF-IPCountry) — nur wenn die Website deklariert hat, hinter Cloudflare zu laufen; - AWS CloudFront (
CloudFront-Viewer-Country) — dieselbe Bedingung; GEOIP_COUNTRY_CODE, die Variable, die der Server selbst schreibt (mod_geoip, ngx_http_geoip), also nicht vom Client fälschbar; dann, wenn ein Proxy deklariert ist, die Varianten als HTTP-Header;- Lokale MaxMind-Datenbank, wenn
geo_mmdb_enabledaktiviert ist; - Nichts.
Ohne ausdrückliche Deklaration in wp-config.php wird keinem HTTP-Länder-Header
geglaubt: Sie sind vom Client fälschbar. Zu den Konstanten siehe
Installation.
Der Ländercode wird gegen die offiziell vergebene Allowlist nach ISO-3166-1 alpha-2 geprüft
(rund 249 fest hinterlegte Codes). Benutzerdefinierte oder reservierte Codes — XX, ZZ,
das T1 von Tor-Ausgangsknoten — werden zurückgewiesen.
Der geschlossene Fehlschlag
Ohne erkanntes Land liest das Plugin geo_default_profile, stuft aber jedes Opt-out-Profil
auf gdpr zurück. Ein geo_default_profile mit dem Wert ccpa, us_generic oder au
wird für nicht erkannte Besucher also ignoriert — und der Backend-Bildschirm bietet in diesem
Auswahlfeld nur Opt-in-Profile an, statt eine Wahl anzubieten, die stillschweigend ignoriert
würde.
Der Grund ist geradeheraus: Ohne diese Sicherung würde eine auf amerikanisches Englisch eingestellte Website jeden EWR-Besucher in einen Opt-out-Rahmen setzen, mit Trackern, die ohne jede Einwilligung als „freigegeben“ gemeldet werden.
Kein Rückfall auf die Locale der Website: Die Sprache einer Website sagt nichts über den Aufenthaltsort ihres Besuchers.
Das Cookie owc_geo
- Dauer 24 Stunden,
path=/,SameSite=Lax, unter HTTPSSecure, per Skript lesbar — das Frontend-Bootstrap braucht es. - Inhalt: das Land, das Profil, ein Zeitstempel und ein Authentifizierungscode. Nie eine IP-Adresse.
- Beim Lesen: Größe begrenzt, Land gegen die ISO-Liste geprüft, Zeitstempel innerhalb des Fensters, Code in konstanter Zeit verifiziert. Das Profil wird immer serverseitig aus dem Land neu berechnet: Ein Besucher kann sich seinen Rechtsrahmen nicht aussuchen.
- Nur eine echte Erkennung wird gecacht. Der Rückfall „geschlossener Fehlschlag“ wird nie gespeichert.
- Wird nur bei einer Frontend-Anfrage geschrieben, und nur wenn die Erkennung aktiviert ist.
Die Zuordnung Land → Profil
| Land | Profil |
|---|---|
| Die 30 EWR-Länder | gdpr |
| GB, JE, GG, IM | uk_pecr |
| CH | ch_nfadp |
| BR | lgpd |
| ZA | popia |
| CN, HK | pipl |
| IN | dpdp |
| AU, NZ | au |
| CA | quebec |
| US | ccpa |
| Alles Übrige | Der Rückfall, auf Opt-in zurückgestuft |
Hongkong unterliegt in Wirklichkeit einer eigenen lokalen Verordnung; es wird der Strenge
halber wie PIPL behandelt. Neuseeland wird wie Australien behandelt. Ganz Kanada bekommt
quebec — der strengste Rahmen gewinnt. Die USA bekommen ccpa, das stellvertretend für die
übrigen Bundesstaaten steht.
Der Cache-Zwang — was die Erkennung nicht tut
Das geolokalisierte Profil verändert das gerenderte HTML nicht. Das Überschreiben des
Profils greift nur bei den beiden Besucher-REST-Routen, /owc/v1/consent und
/owc/v1/state. Seitenrendering, Admin-Routen, wp-admin, Cron und WP-CLI behalten das
konfigurierte Profil. Jede Antwort, die das Überschreiben genutzt hat, wird als nicht
cachebar markiert.
Es ist das Frontend-Runtime, das den Rahmen clientseitig aus dem Cookie wählt. Bewusst hingenommene Folge: Welcher Rahmen auf einen Besucher angewendet wird, hängt an JavaScript, und ein Besucher, dessen allererste Seite aus dem Cache kommt, wird unter dem konfigurierten Profil der Website behandelt, solange das Cookie nicht existiert.
Der eingebaute MaxMind-Reader
Das Plugin bringt seinen eigenen MMDB-Reader mit, in reinem PHP geschrieben, ohne Composer-Abhängigkeit — ein auf WordPress.org veröffentlichtes Plugin kann das offizielle Paket nicht mitliefern.
- Nur Lesen, nur Land. Keine Stadt, kein ASN.
- Begrenzte Ein-/Ausgabe: Lesen in kleinen Blöcken, nie das Laden einer mehrere Megabyte großen Datei in den Arbeitsspeicher.
- Wirft nie eine Exception: Eine fehlende, unlesbare, abgeschnittene, beschädigte oder
bösartige Datei ergibt
null, und die Erkennung fällt auf ihr strenges Profil zurück. - Interne Sicherungen für die Traversierungstiefe, das Dekodierbudget und die Nutzlastgröße. Die Metadaten werden in einem Transient gecacht, dessen Schlüssel Größe und Datum der Datei einschließt: Ihren monatlichen Download zu ersetzen macht den Cache von selbst ungültig.
registered_countryundrepresented_countrywerden bewusst ignoriert. Das ist die dokumentierte Form anonymer Proxy-, VPN- und Satellitenbereiche, in denen das Registrierungsland den Ort der Blockregistrierung durch den Anbieter bezeichnet, nicht den Besucher. Sie zu verwenden würde einen EWR-Besucher hinter einem US-VPN in einen Opt-out-Rahmen setzen.- Wenn ein anderes Plugin bereits einen GeoIP2-Reader lädt, wird er als Rückfall nach dem eigenen Reader genutzt.
Wohin die Datei gehört: wp-content/uploads/ow-geoip/GeoLite2-Country.mmdb. Der Pfad ist
über owc_geo_mmdb_path filterbar, mit Prüfung gegen Directory Traversal.
Wichtige Grenze: Das Plugin lädt die Datenbank nicht herunter und bietet keinen Upload-Bildschirm. Sie müssen die Datei bei MaxMind beziehen, selbst ablegen und selbst aktualisieren. Im Gegenzug wird nichts an MaxMind gesendet: Die Abfrage läuft vollständig lokal, die IP-Adresse dient allein dem Nachschlagen und wird danach ausdrücklich verworfen — nie protokolliert, nie gespeichert, nie ins Cookie geschrieben.
Grenzen der regionalen Erkennung
- Standardmäßig deaktiviert, und die MaxMind-Variante verlangt eine Datei, die Sie liefern.
- Länder-Header werden ignoriert, solange Sie Ihren Proxy nicht deklariert haben.
- Keine Granularität nach US-Bundesstaat und keine nach kanadischer Provinz.
- Der Rahmen des Besuchers hängt an JavaScript und am 24-Stunden-Cookie.
- Das Profil
us_genericwird nie automatisch zugewiesen.
Die OW Forms-Integration
Genauer Geltungsbereich: Diese Integration zielt auf das Schwester-Plugin OW Forms, und auf nichts anderes. Es gibt keine Integration für Contact Form 7, Gravity Forms oder WPForms.
Einstellung: forms_integration_enabled, standardmäßig aktiv, aber die Integration tut
nichts, wenn OW Forms nicht aktiv ist.
Was sie bringt
1. Die Verknüpfung Einwilligung ↔ Übermittlung. Bei jeder gespeicherten Übermittlung wird eine Zeile in eine Tabelle geschrieben, die OW Consent gehört — das Schema von OW Forms wird nie angerührt —, mit:
- dem pseudonymen Besucher-Token (32 Hexadezimalzeichen, nie die E-Mail-Adresse);
- der Kennung des jüngsten Protokolleintrags zu diesem Token;
- den freigegebenen Kategorien und dem geltenden Compliance-Profil;
- dem vollständigen Fingerabdruck der in diesem Moment veröffentlichten Dokumente;
- dem Zeitstempel der Einwilligung;
- dem Zustand des DSGVO-Kästchens im Formular und der genauen Beschriftung, die daneben stand.
Der letzte Punkt ist in der Praxis der nützlichste: Sie können nicht nur nachweisen, dass das Kästchen angehakt war, sondern auch, was daneben stand.
2. Die Löschkaskade. Eine verifizierte Löschanfrage delegiert die Löschung an die Routine von OW Forms — die auch die hochgeladenen Dateien entfernt — und löscht dann die Verknüpfungszeilen. Die Integration erkennt, ob OW Forms bereits einen eigenen Listener an dieselbe Aktion gehängt hat; in diesem Fall beschränkt sie sich darauf, ihre Verknüpfungen zu beschneiden.
3. Die Datenschutz-Werkzeuge von WordPress. Ein Exporter und ein Eraser werden registriert, sodass Werkzeuge → Personenbezogene Daten exportieren / löschen auch die OW Forms-Übermittlungen abdeckt — und das Portal für Betroffenenrechte von OW Consent ebenfalls, da es dieselben Hooks durchläuft. Der Export übernimmt die tatsächlichen Feldbezeichnungen und ergänzt die Einwilligungsfelder. Jeder exportierte Wert wird gegen Tabellenkalkulations-Formelinjektion entschärft und gekürzt.
4. Die Aufbewahrung. Im täglichen Cron werden Verknüpfungen, die älter sind als
retention_form_data_days (Standard 1095 Tage, Grenzen 1 bis 3650), in Paketen zu 500
gelöscht, samt einem Durchlauf für verwaiste Einträge. Nur die Zeilen von OW Consent werden
angefasst: Die Aufbewahrung der Übermittlungen selbst gehört OW Forms.
Grenzen
- Kein Übermittlungsereignis wird in die verkettete Kette geschrieben. Die Verknüpfungszeile verweist auf einen bestehenden Eintrag, sie erzeugt keinen — die Kette darf nicht von außen beschrieben werden.
- Eine Übermittlung lässt sich nicht verknüpfen, wenn OW Forms so eingestellt ist, dass es Übermittlungen nicht speichert: Es gibt dann keine Zeile, an der man ansetzen könnte.
- Keine rückwirkende Erfassung: Die Verknüpfung beginnt mit der ersten Übermittlung nach dem Update.
- Der Abgleich läuft über den gesalzenen Fingerabdruck der Adresse, den OW Forms berechnet, mit Rückfall auf die Klartextadresse, die OW Forms ebenfalls aufbewahrt. Das ist kein Zero-Knowledge-Verfahren: Die Adresse bleibt bei OW Forms im Klartext, weil man der Person antworten können muss.
- Die Integration verändert niemals das Plugin OW Forms, seine Tabellen oder seine Optionen.
- Ist OW Forms aktiv, aber zu alt, um seine Löschroutine bereitzustellen, antwortet der Eraser ausdrücklich, dass die Übermittlungen nicht angerührt wurden.
Der schwebende Button
Ein kleiner dauerhafter Button erlaubt es, das Präferenz-Panel jederzeit wieder zu öffnen. Das ist die Anforderung aus Artikel 7 Abs. 3 — der Widerruf muss so einfach bleiben wie die Einwilligung — und aus dem CNIL-Beschluss 2020-091, der einen von jeder Seite aus erreichbaren Mechanismus verlangt.
Voraussetzungen für seine Existenz
Er verlangt beide Einstellungen: floating_button_enabled und banner_enabled. Das
Präferenz-Panel und die JavaScript-API leben im Runtime des Banners; ohne dieses wäre der
Button ein Bedienelement ohne Wirkung.
Er steigt außerdem aus im Backend, in einem Feed, bei robots.txt und wenn wp_head nicht
ausgelöst wurde.
Optionen
| Einstellung | Werte | Standard |
|---|---|---|
floating_button_enabled | boolesch | true |
floating_button_position | bottom-left, bottom-right, top-left, top-right | bottom-left |
floating_button_style | pill, icon | pill |
floating_button_label | freier Text | Cookies |
Der Button hat keine eigene Theme-Einstellung: Er übernimmt banner_style, damit beide
Oberflächen derselben Palette folgen.
Verhalten und Barrierefreiheit
Es ist ein echter <button>, also tastaturbedienbar. Er trägt aria-haspopup="dialog" und
ein übersetzbares, aber nicht konfigurierbares aria-label („Manage my cookie choices“):
Nur die sichtbare Beschriftung lässt sich einstellen. Im Modus icon wird die Beschriftung
visuell ausgeblendet, bleibt aber für Screenreader lesbar.
Er wird mit dem Attribut hidden gerendert; erst das JavaScript entscheidet, ihn anzuzeigen.
Er ist in allen Zuständen sichtbar, außer wenn das Banner oder das Panel bereits auf dem
Bildschirm ist — auch unmittelbar nach einer Wahl auf der aktuellen Seite.
Ein Klick öffnet das Präferenz-Panel. Fehlt die Banner-API, fällt der Button auf das Fragment
#owc-preferences zurück und löst das Ereignis von Hand erneut aus, wenn es bereits das
aktuelle Fragment ist.
z-index 99990, beim Drucken ausgeblendet, Unterstützung für den Modus mit erhöhtem Kontrast
und für prefers-reduced-motion, Versatz unter der Adminleiste bei oberer Position.
Shortcodes
Das Plugin deklariert zwei Shortcodes, und nur diese zwei. Weder das Banner noch der schwebende Button haben einen: Sie erscheinen überall oder nirgends, gesteuert über ihre Einstellungen.
[owc_dsar_form] — das Portal für Betroffenenrechte
[owc_dsar_form]
[owc_dsar_form types="access,erasure,portability" title="Meine Rechte" submit_label="Senden"]
| Attribut | Standard |
|---|---|
types | access,rectification,erasure,portability,restrict,object,optout |
title | „Meine Rechte an meinen personenbezogenen Daten wahrnehmen“ |
submit_label | „Anfrage senden“ |
Die angeforderten Typen werden mit denen geschnitten, die der Server akzeptiert. Der Typ
withdraw wird vom Formular nie angeboten; siehe
Das Portal für Betroffenenrechte.
[owc_dnsmpi] — das CCPA-Opt-out
[owc_dnsmpi]
[owc_dnsmpi label="Meine personenbezogenen Daten nicht verkaufen oder weitergeben" class="footer-link"]
| Attribut | Standard |
|---|---|
label | „Do Not Sell or Share My Personal Information“ |
class | owc-dnsmpi |
Ein Klick führt das Opt-out aus; siehe Das CCPA-Opt-out. Wenn Sie
ccpa_inject_footer aktiviert lassen, ist der Link bereits im Footer eingefügt, und dieser
Shortcode ist nur dann nützlich, wenn Sie ihn anderswo platzieren wollen.
Das Panel aus einem Menü oder einem Link öffnen
Dafür gibt es keinen Shortcode, weil ein Klassenattribut genügt:
<a href="#owc-preferences" class="owc-open-preferences">Cookies verwalten</a>
<button type="button" data-owc-open>Meine Präferenzen</button>
<a href="#owc-dnsmpi" data-owc-dnsmpi="1">Meine Daten nicht verkaufen</a>
Das ist der empfohlene Weg, um Ihrem Footer-Menü einen Eintrag „Cookies“ hinzuzufügen.
REST API
Alle Routen liegen unter dem Namespace owc/v1, an der üblichen REST-Wurzel
(https://beispiel.de/wp-json/owc/v1/…). Dreizehn Routen insgesamt: zwölf vom REST-Modul
registriert, dazu die Route der Anbieterliste, die das TCF-Modul registriert.
Öffentliche Routen
Keine Authentifizierung. Ihre Sicherheit ruht auf der Origin-Prüfung, einem plugin-eigenen Token und den weiter unten beschriebenen Rate-Limits.
| Methode | Pfad | Parameter | Zweck |
|---|---|---|---|
GET | /nonce | action (Standard wp_rest) | Liefert ein frisches Token. Antwort: {nonce, action, header: "X-OWC-Nonce", ttl: 43200}, mit no-store und Vary: Cookie |
POST | /consent | event (Standard save_preferences), source (Standard banner), categories (erforderlich), page_url (Standard ''), cookie_unreadable (boolesch, Standard false) | Erfasst eine Wahl, setzt das Cookie und schreibt die Protokollzeile |
GET | /state | — | Der Zustand allein des Aufrufers: {given, categories, profile, at}. Nie das Besucher-Token, nie die IP, nie die Seiten-URL. no-store + Vary: Cookie |
GET | /tcf/gvl | — | Liefert die gecachte Global Vendor List. ETag, Cache-Control: public, max-age=86400, 304 bei bedingter Anfrage, 503 + Retry-After: 300, wenn nichts im Cache ist |
POST | /dsar | type (erforderlich), email (erforderlich, E-Mail-Format), message (Standard '', höchstens 2000 Zeichen) | Reicht eine Betroffenenanfrage ein. Antwort {ok, mail_sent, message} — nie die Kennung |
Akzeptierte Werte:
event:accept_all,reject_all,save_preferences,withdraw,auto,gpc_opt_outsource:banner,preferences,footer_link,api,autotype(DSAR):access,rectification,erasure,portability,restrict,object,optout,withdrawcategories: ein Objekt, höchstens 32 Einträge, nur skalare Werteaction(Nonce): nurwp_rest
Administrative Routen
Alle verlangen die Berechtigung manage_options.
| Methode | Pfad | Parameter | Zweck |
|---|---|---|---|
GET | /ledger | page (≥1, Standard 1), per_page (1–200, Standard 50), visitor_token (32 Hex), from, to | Liest das Protokoll. Die tatsächlich angewendeten Filter kommen in der Antwort zurück |
GET | /ledger/verify | — | Prüft die Kette von Anfang bis Ende |
GET | /settings | — | Die effektiven Einstellungen |
POST | /settings | freier JSON-Body | Schreibt die Einstellungen. Antwort {ok, updated, rejected, settings} |
POST | /scanner/run | — | Startet einen Durchlauf |
POST | /scanner/ingest | JSON-Body {page, findings[]} | Nimmt die Beobachtungen der Sonde entgegen |
GET | /scanner/findings | page, per_page (1–200, Standard 50), filter (Kategorie-Slug oder unknown) | Listet die Funde |
POST | /policies/generate | type (erforderlich), publish (boolesch, Standard false) | Erzeugt ein Dokument |
GET | /policies/preview | type (erforderlich) | Zeigt ein Dokument in der Vorschau |
/scanner/ingest verlangt zusätzlich ein gültiges wp_rest-Nonce, im Header
X-WP-Nonce oder als Parameter _wpnonce — weil sendBeacon keinen Header setzen kann.
/settings akzeptiert beim Schreiben nur Schlüssel, die als echte Einstellungen deklariert
sind: Ein Filter kann synthetische Schlüssel einschleusen, die keine sind. Jeder Wert wird
einzeln bereinigt. Kein einziger bekannter Schlüssel ergibt einen 400.
/ledger prüft die Berechtigung im Handler erneut, als Verteidigung in der Tiefe gegen
einen anderswo gefilterten permission_callback.
Das Sicherheitsmodell öffentlicher Schreibvorgänge
Der Ausgangsbefund ist einfach: Ein Nonce kann nicht in cachebarem HTML leben.
/consent und /dsar haben deshalb eine großzügige Zugriffsprüfung, abgesichert durch vier
Schichten in einer Reihenfolge, die zählt.
- Origin-Prüfung auf denselben Host. Kostenlos, deterministisch, verbraucht kein Budget.
- Plugin-eigenes Token im Header
X-OWC-Nonce— das ist ein Nachweis, nie ein Veto. AufX-WP-Noncezu verzichten ist Absicht: Der WordPress-Core fängt diesen Header vor jeder routenspezifischen Zugriffsprüfung ab und weist die ganze Anfrage zurück, wenn er ihn nicht validiert. Ein aus einem Cache stammendes abgelaufenes Token würde also einen Schreibvorgang töten, den der Endpunkt ganz ohne Token akzeptiert hätte. - Geschlossener Fehlschlag: Weder Origin noch geprüftes Token ergeben einen 403
owc_missing_origin. - Rate-Limit zuletzt. Käme es zuerst, würde eine Fehlkonfiguration zwei Token pro Klick verbrauchen und in einem 429 enden, was den Konfigurationsfehler hinter einem Rate-Limit verstecken würde.
Akzeptierte Hosts: die, die WordPress deklariert (Website-URL, WordPress-URL,
REST-Wurzel) samt ihrem www./Apex-Zwilling, dazu der Host aus dem Host-Header der
aktuellen Anfrage und dessen Zwilling. „Same Origin“ heißt „der Origin entspricht dem Host,
mit dem sich der Browser verbunden hat“, nicht „entspricht dem, was WordPress in der
Datenbank stehen hat“ — sonst würde jede Website, die über eine Vorschaudomain, einen Alias,
einen Staging-Namen, eine im Multisite gemappte Domain oder hinter einem Host
umschreibenden Proxy erreicht wird, stillschweigend abgewiesen, ohne Möglichkeit zur
Selbstreparatur. Filter: owc_allowed_request_hosts.
CORS bleibt bewusst dem WordPress-Core überlassen.
/nonce weist die JSONP-Form ausdrücklich zurück: Ohne diese Zurückweisung könnte eine
fremde Seite das lebende Token eines vorbeikommenden Administrators über ein einfaches
<script src> abgreifen, das keiner Origin-Prüfung unterliegt.
Die Rate-Limits
| Bucket | Budget | Zeitfenster | Schlüssel |
|---|---|---|---|
nonce | 120 | 5 Minuten | IP-Adresse |
consent | 30 | 5 Minuten | IP-Adresse |
dsar | 3 | 1 Stunde | IP-Adresse |
dsar_email | 3 | 24 Stunden | betroffene E-Mail-Adresse |
dsar_global | 30 | 1 Stunde | die gesamte Website |
gpc | 30 | 1 Stunde | IP-Adresse |
tcf_gvl | 10 | 1 Stunde | IP-Adresse |
- Festes Zeitfenster, nicht gleitend: Ein Bucket, der Verkehr bekommt, läuft irgendwann immer ab.
- Der gespeicherte Schlüssel ist ein gesalzener Fingerabdruck: keine IP-Adresse und keine E-Mail-Adresse im Klartext liegt in den Optionen oder im Object Cache.
- IP-Normalisierung: IPv4 bleibt erhalten, IPv6 wird auf /64 gekürzt — der Client kontrolliert jedes Bit des Interface-Identifiers, ein vollständiger Schlüssel würde also bei jeder Anfrage ein frisches Budget erlauben.
- Geteilte Identität: Hinter einem CDN oder einem nicht über
OWC_TRUSTED_PROXYdeklarierten Proxy kommen alle Besucher mit derselben Adresse an. Das Budget wird dann je Besucher aufgeteilt, mit einem erweiterten Zähler auf der geteilten Adresse. Das ist eine gröbere Grenze: Deklarieren Sie Ihren Proxy. - Filter
owc_throttle_max( $max, $bucket, $window )—0zurückzugeben schaltet die Grenze ab. - Der Limiter schlägt offen fehl, wenn der Object Cache nicht verfügbar ist: Lieber nicht begrenzen, als jemanden daran zu hindern, seine Rechte wahrzunehmen.
Die Route /consent im Detail
headers_sent()wird als Allererstes gelesen. Hat die Ausgabe schon begonnen, kann das Server-Cookie nicht gesetzt werden: Die Zeile wird trotzdem geschrieben, und die Antwort bleibt 200, mitcookie_set: falseund einem Deskriptorcookie(name,value,ttl,path,samesite,secure), den der Client selbst setzt.- Kategorien, die die Website nicht anbietet, kommen in
dropped_categorieszurück, statt stillschweigend ignoriert zu werden. page_urlwird gegen die Hosts der Website validiert, mit Rückfall auf einen genauso validiertenReferer, sonst der leere String. Der Schlüssel ist immer vorhanden, damit das Protokoll nicht selbst den rohenRefererheranzieht.- Ist das Protokoll aktiviert und wird der Schreibvorgang verweigert, wird das Cookie
verworfen, und die Antwort ist ein 503
owc_ledger_write_refused. Nichts wird gespeichert, kein Tracker wird freigegeben. cookie_unreadableist reine Telemetrie: Es wird keinerlei Validierung darauf angewendet, genau damit ein Diagnosefeld niemals einen Einwilligungs-Schreibvorgang ablehnen kann. Seine einzige Wirkung ist eine Notiz im Ablehnungsprotokoll.
Typische Antwort: {ok, state, dropped_categories, logged, cookie_set[, cookie]}. Das Feld
logged ist null, wenn das Protokoll deaktiviert ist.
Fehlercodes
| Code | HTTP | Bedeutung |
|---|---|---|
owc_bad_param | 400 | Ungültiger Parameter |
owc_bad_categories | 400 | Objekt categories fehlerhaft, zu groß oder nicht skalar |
owc_bad_email | 400 | Ungültige E-Mail-Adresse |
owc_bad_dsar | 400 | Fehlerhafte DSAR-Einreichung (Honeypot eingeschlossen) |
owc_dsar_not_attested | 400 | Bestätigung nach Art. 12 Abs. 6 fehlt |
owc_no_settings | 400 | Kein bekannter Einstellungsschlüssel im Body |
owc_missing_origin | 403 | Weder Origin noch Token: geschlossener Fehlschlag |
owc_bad_origin | 403 | Der angegebene Origin ist kein Host dieser Website — die Antwort listet bis zu zehn akzeptierte Hosts |
owc_bad_nonce | 403 | Ungültiges Nonce auf /scanner/ingest |
owc_jsonp_forbidden | 403 | JSONP-Form auf /nonce abgelehnt |
owc_forbidden | 401/403 | Berechtigung nicht ausreichend |
owc_dsar_disabled | 404 | Das Portal für Betroffenenrechte ist serverseitig deaktiviert |
owc_no_template | 404 | Keine Vorlage für diesen Typ und dieses Profil |
owc_rate_limited | 429 | Rate-Limit erreicht |
owc_consent_failed | 500 | Anwenden der Einwilligung fehlgeschlagen |
owc_dsar_store_failed | 500 | Schreiben der Anfrage fehlgeschlagen |
owc_gen_failed | variabel | Dokumenterzeugung verweigert (fehlende Felder, Sprachsperre) |
owc_ledger_write_refused | 503 | Das Protokoll hat den Schreibvorgang verweigert — nichts wird erfasst, nichts wird freigegeben |
Das Ablehnungsprotokoll
Die letzten zwanzig verweigerten Schreibvorgänge werden aufbewahrt und auf dem Dashboard angezeigt — nur wenn das Protokoll nicht leer ist. Zwei Arten werden dort unterschieden:
- ein Eintrag mit HTTP-Status ist eine echte Verweigerung: Es wurde nichts gespeichert, und der Besucher hat einen Fehler gesehen;
- ein Eintrag mit Status 0 ist eine Warnung: Die Wahl wurde sehr wohl erfasst.
Das Panel zeigt nebeneinander den vom Origin angegebenen Host und den Host-Header der
Anfrage. Genau das weicht ab, wenn Ihre Besucher auf einem Host unterwegs sind, während
WordPress mit einem anderen konfiguriert ist — die häufigste Ursache dafür, dass eine
Einwilligung „nicht gespeichert wird“.
Grenzen der API
/consentund/dsarakzeptieren konstruktionsbedingt anonyme Schreibvorgänge; der Schutz ist der Origin plus das Rate-Limit, kein Nonce.- Der Rate-Limiter schlägt ohne Object Cache offen fehl.
- Das Einwilligungs-Cookie ist Host-only: Ein für den Apex gesetztes Cookie ist von einer
www.-Seite aus nicht lesbar, und kein CORS-Header kann das beheben. Das Mittel ist eine Schreib-URL mit demselben Origin. /scanner/ingestakzeptiert nurmanage_options: Die Sonde kann nicht von einem Besucher kommen./settingshat kein eigenes Nonce: Es istmanage_optionsplus die Cookie-Nonce-Prüfung des Cores.
Einstellungsreferenz
Alle Einstellungen liegen in einer einzigen Option, owc_settings, die automatisch
geladen wird, da sie auf jeder Frontend-Seite gelesen wird.
Lesen und Schreiben in PHP
$einstellungen = OWC_Core::settings(); // effektive Einstellungen (Standards + gespeichert + Filter)
$profil = OWC_Core::setting( 'compliance_profile' );
$roh = OWC_Core::stored_setting( 'compliance_profile' ); // ignoriert das Überschreiben pro Besucher
OWC_Core::update_settings( array(
'consent_renewal_months' => 6,
'compliance_strict' => true,
) );
update_settings() legt nur die übergebenen Schlüssel über den Bestand, niemals die
Gesamtheit der Standardwerte. Genau das erlaubt es der Optionszeile, leer zu bleiben, solange
Sie nichts angepasst haben — und damit den Texten, der Sprache der Website zu folgen.
Das Ergebnis von settings() wird memoisiert, mit einem Schlüssel, der auf der Gesamtheit
der Callbacks des Filters owc_settings beruht: Ein Modul, das seinen Filter nach dem ersten
Lesen registriert, macht das Memo ungültig, statt ignoriert zu werden. Das Memo wird bei
jedem Schreiben der Option geleert.
Standardwerte
[
// Banner
'banner_enabled' => true,
'banner_position' => 'bottom-bar', // bottom-bar | bottom-card | center-modal | top-bar
'banner_style' => 'auto', // auto | light | dark
'banner_accept_all' => true,
'banner_reject_all' => true,
'banner_preferences' => true,
'banner_close_x' => false, // Kreuz = stillschweigende Ablehnung
'banner_show_logo' => true,
'text_title' => 'We use cookies',
'text_message' => 'We use cookies to personalise content, measure audience, '
. 'and provide social media features. You can accept or reject, '
. 'and change your choice at any time.',
'text_accept_all' => 'Accept all',
'text_reject_all' => 'Reject all',
'text_preferences' => 'Customize',
'text_save' => 'Save my choices',
// Schwebender Button
'floating_button_enabled' => true,
'floating_button_position' => 'bottom-left',
'floating_button_style' => 'pill',
'floating_button_label' => 'Cookies',
// Einwilligung
'consent_renewal_months' => 12, // 0 wird zu 13 umgewandelt, nicht zu „nie“
'consent_policy_hash_check' => true,
// Compliance
'compliance_profile' => 'gdpr',
'compliance_strict' => true,
'geo_enabled' => false,
'geo_default_profile' => 'gdpr',
'geo_mmdb_enabled' => false,
// IAB TCF v2.2
'tcf_enabled' => false,
'tcf_cmp_id' => 0,
'tcf_publisher_country' => 'FR',
'tcf_publisher_purposes_li' => [],
'tcf_special_features' => [],
// CCPA / GPC
'ccpa_inject_footer' => true,
'gpc_honor' => true,
// Google Consent Mode v2
'gcm_enabled' => true,
'gcm_ads_data_redaction' => true,
'gcm_url_passthrough' => true,
// Kategorien
'cat_necessary_available' => true,
'cat_functional_available' => true,
'cat_analytics_available' => true,
'cat_marketing_available' => true,
'cat_preferences_available' => true,
'cat_social_available' => true,
'cat_necessary_label' => 'Necessary',
'cat_necessary_desc' => 'Strictly required for the site to function …',
'cat_functional_label' => 'Functional',
'cat_functional_desc' => 'Enhance the experience (chat, embedded videos, maps) …',
'cat_analytics_label' => 'Statistics',
'cat_analytics_desc' => 'Help us understand how you use the site (anonymously) …',
'cat_marketing_label' => 'Marketing',
'cat_marketing_desc' => 'Enable us to show you ads and content tailored …',
'cat_preferences_label' => 'Preferences',
'cat_preferences_desc' => 'Remember your interface choices (layout, saved filters).',
'cat_social_label' => 'Social & embeds',
'cat_social_desc' => 'Allow embedded social content (YouTube, Instagram, X) to load.',
// Protokoll
'ledger_enabled' => true,
'ledger_retention_days' => 1825, // 5 Jahre; 0 = unbegrenzt
'ledger_hash_algo' => 'sha256',
// Scanner
'scanner_enabled' => false,
'scanner_frequency' => 'weekly',
'scanner_alert_email' => '',
'scanner_max_urls' => 25,
'scanner_timeout' => 8,
'scanner_probe_mode' => 'admins',
// Portal für Betroffenenrechte
'dsar_enabled' => true,
'dsar_email' => '',
'dsar_response_days' => 30,
'dsar_notify_email' => '',
'dsar_token_ttl_days' => 7,
// Blockade
'blocker_unknown_script_policy' => 'allow',
'blocker_unknown_iframe_policy' => 'block',
'blocker_allowlist' => '', // ein Host pro Zeile
'blocker_block_resource_hints' => true,
// Integration und Lebenszyklus
'forms_integration_enabled' => true,
'auto_footer_menu_inject' => false,
'delete_data_on_uninstall' => false,
// Rechtliche Identität
'legal_company_name' => '',
'legal_company_legal_form' => '',
'legal_company_capital' => '',
'legal_company_address' => '',
'legal_company_email' => '',
'legal_company_phone' => '',
'legal_country' => 'FR',
'legal_company_reg_number' => '',
'legal_company_reg_place' => '',
'legal_company_vat' => '',
'legal_publication_director' => '',
'legal_eu_representative' => '',
'legal_host_name' => '',
'legal_host_address' => '',
'legal_host_phone' => '',
'legal_host_url' => '',
'legal_profession_body' => '',
'legal_profession_title' => '',
'legal_profession_state' => '',
'legal_profession_rules' => '',
'legal_mediator_name' => '',
'legal_mediator_address' => '',
'legal_mediator_url' => '',
'legal_dpo_name' => '',
'legal_dpo_email' => '',
'legal_dpa_authority' => '', // bewusst leer: wird aus Land + Profil abgeleitet
'legal_transfer_countries' => '',
'legal_third_parties_note' => '',
'legal_automated_decisions' => false,
'legal_automated_decisions_desc' => '',
'legal_minor_age' => 15,
'legal_data_provision_note' => '',
'legal_currency' => 'EUR',
'legal_tax_label' => 'TTC',
'legal_business_type' => 'auto',
'retention_form_data_days' => 1095,
'retention_dsar_days' => 1095,
'policy_disclaimer' => true,
// Links
'link_privacy_policy' => '',
'link_cookie_policy' => '',
'link_terms' => '',
'link_legal_notice' => '',
]
Geschlossene Wertelisten
Ein Wert außerhalb der Liste wird auf den Standard zurückgesetzt.
| Einstellung | Akzeptierte Werte |
|---|---|
banner_position | bottom-bar, bottom-card, center-modal, top-bar |
banner_style | auto, light, dark |
floating_button_position | bottom-left, bottom-right, top-left, top-right |
floating_button_style | icon, pill |
compliance_profile, geo_default_profile | gdpr, ccpa, lgpd, popia, pipl, dpdp, quebec, uk_pecr, ch_nfadp, au, us_generic |
ledger_hash_algo | sha256, sha3-256 (geschnitten mit dem, was PHP unterstützt) |
scanner_frequency | hourly, twicedaily, daily, weekly |
scanner_probe_mode | admins, off |
legal_business_type | auto, vitrine, rental, ecommerce, services, saas, content |
blocker_unknown_script_policy, blocker_unknown_iframe_policy | allow, block |
Grenzen der Ganzzahlwerte
| Einstellung | Grenzen |
|---|---|
consent_renewal_months | 0 bis 13 (0 wird wie 13 behandelt) |
dsar_response_days | 1 bis 30 |
dsar_token_ttl_days | 1 bis 90 |
ledger_retention_days | 0 bis 3650 (0 = unbegrenzt) |
scanner_max_urls | 1 bis 500 |
scanner_timeout | 1 bis 60 |
legal_minor_age | 13 bis 18 |
retention_form_data_days | 1 bis 3650 |
retention_dsar_days | 1 bis 3650 |
tcf_cmp_id | 0 bis 4095 |
Bereinigung
text_messageist das einzige Feld mit Rich-HTML; es akzeptiert das in einem WordPress-Beitrag erlaubte HTML, und das Banner rendert am Ende nur<a href target rel>.- Mehrzeilige Felder:
legal_company_address,legal_eu_representative,legal_host_address,legal_mediator_address,legal_third_parties_note,legal_automated_decisions_desc,legal_data_provision_note,blocker_allowlistsowie jeder Schlüssel, der auf_descendet. - URLs: jeder Schlüssel mit dem Präfix
link_oder der Endung_url, dazulegal_profession_rules. - E-Mail-Adressen: jeder Schlüssel, der
emailenthält. - Alles Übrige: einfacher Text.
- Ein nicht skalarer Wert, der für eine skalare Einstellung übergeben wird, wird ignoriert, der Schlüssel wird nicht geschrieben.
Wo was eingestellt wird
| Tab | Einstellungen |
|---|---|
| Banner | banner_*, text_*, floating_button_*, consent_renewal_months, consent_policy_hash_check |
| Compliance | compliance_profile, compliance_strict, gcm_*, blocker_*, ccpa_inject_footer, gpc_honor, tcf_*, geo_*, auto_footer_menu_inject, forms_integration_enabled, delete_data_on_uninstall, link_* |
| Legal identity | legal_*, retention_form_data_days, retention_dsar_days, policy_disclaimer |
| Categories | cat_*_available, cat_*_label, cat_*_desc |
| Audit ledger | ledger_enabled, ledger_retention_days (der Algorithmus wird angezeigt, nicht geändert) |
| Scanner | scanner_* |
| DSAR requests | dsar_* |
Tabellen
| Tabelle | Inhalt |
|---|---|
{prefix}owc_ledger | Verkettetes Einwilligungsprotokoll |
{prefix}owc_dsar | Betroffenenanfragen |
{prefix}owc_scanner | Funde des Scanners |
{prefix}owc_scripts | Signaturkatalog der Blockade |
{prefix}owc_form_links | Verknüpfungen Einwilligung ↔ OW Forms-Übermittlung |
Ein PHP-Helfer owc_table( 'ledger' | 'dsar' | 'scanner' | 'scripts' ) berechnet den Namen
aus dem aktuellen Präfix neu: Verwenden Sie ihn innerhalb eines switch_to_blog(), da
Konstanten für die Dauer der Anfrage eingefroren sind.
Weitere Optionen und Transients
Optionen: owc_settings, owc_version, owc_pending_upgrade, owc_upgrade_lock,
owc_ledger_head, owc_ledger_trim, owc_ledger_key_source, owc_scanner_secret,
owc_scanner_lock, owc_scanner_queue, owc_scanner_status, owc_scanner_alerted,
owc_scanner_probe_status, owc_scanner_manual, owc_refusal_log, owc_tcf_status,
owc_tcf_gvl_version, owc_forms_db_version, dazu die Migrationsflags
(owc_catalog_sanitized_v2, owc_match_target_migrated_v1, owc_ledger_hmac_migrated_v1,
owc_inline_sig_labels_cleaned_v1, owc_scanner_secret_rotated_v1).
Transients: owc_catalog_<version>, owc_invalid_patterns, owc_gvl_cache,
owc_gvl_stub, owc_gvl_etag, owc_gvl_retry, owc_mmdb_<fingerabdruck>,
owc_policies_hash, owc_site_analysis, owc_scanner_last_run,
owc_scanner_run_result, owc_scanner_pruned, owc_scanner_fail_alerted,
owc_ledger_verify_result, owc_ledger_write_error, owc_policy_gen_result,
owc_dsar_sla_alert, owc_dsar_admin_result, sowie die Zähler der Rate-Limitierung.
In wp-config.php erkannte Konstanten
| Konstante | Wirkung |
|---|---|
OWC_LEDGER_KEY | HMAC-Schlüssel des Protokolls und abgeleiteter Schlüssel des Cookies für die regionale Erkennung |
OWC_TRUSTED_PROXY / OWC_TRUSTED_PROXIES | CIDR-Bereiche der vertrauenswürdigen Proxys; ohne sie werden die Client-IP-Header ignoriert |
OWC_GEO_TRUSTED_HEADERS | cloudflare, cloudfront, proxy oder all |
OWC_BEHIND_CLOUDFLARE | Kurzform für den Länder-Header von Cloudflare |
OWC_BEHIND_CLOUDFRONT | Kurzform für den Länder-Header von CloudFront |
Die Entwickler-Hooks
Filter
| Filter | Zweck |
|---|---|
owc_settings | Effektive Einstellungen. Die Antwort muss von etwas abhängen, das für die gesamte Anfrage stabil ist |
owc_banner_texts | Texte des Banners |
owc_bootstrap_config | Statische Konfiguration, die in <head> ausgegeben wird — nie besucherspezifische Daten |
owc_scripts_catalog | Katalogzeilen vor der Validierung |
owc_blocker_allowlist | Hosts, die nie blockiert werden |
owc_scanner_urls | Zu durchlaufende URLs (danach erneut auf den Host der Website eingeschränkt) |
owc_throttle_max | Budget eines Rate-Limits; 0 schaltet es ab |
owc_allowed_request_hosts | Für einen öffentlichen Schreibvorgang akzeptierte Hosts |
owc_allow_headerless_write | Hebt den geschlossenen Fehlschlag bei Schreibvorgängen ohne Origin auf (Standard false) |
owc_geo_mmdb_path | Pfad zur MaxMind-Datenbank |
owc_tcf_purpose_map | Zuordnung Kategorien → TCF-Zwecke |
owc_tcf_stub_config | Statische Konfiguration des TCF-Stubs |
owc_policy_template | Roher Textkörper einer Vorlage — hebt die Sprachsperre auf |
owc_policy_vars | Variablen eines Dokuments |
owc_policy_html | Fertiges HTML eines Dokuments |
owc_dsar_types | Angebotene und akzeptierte Anfragetypen |
owc_dsar_form_notice | Informationshinweis unter dem Formular |
owc_dsar_export_bundle | Inhalt des Portabilitäts-Bundles |
owc_dsar_show_fulfilment_panel | Anzeige des Ausführungs-Panels |
Aktionen
| Aktion | Signatur |
|---|---|
owc_consent_updated | ( array $categories, string $event, string $source ) |
owc_consent_cookie_not_sent | ( array $cookie, string $event ) |
owc_ledger_lock_failed | ( string $event, string $token ) |
owc_ledger_write_failed | ( $error, string $event, string $token ) |
owc_ledger_anchor | ( array $anchor ) |
owc_ledger_pruned | ( int $deleted, int $days ) |
owc_catalog_updated | — |
owc_gpc_honored | ( array $categories ) |
owc_tcf_inactive | ( string $reason ) |
owc_dsar_submitted | ( string $type, string $email, string $message ) |
owc_dsar_verified | ( int $id, array $row ) |
owc_dsar_fulfilled | ( int $id, string $what, $trace ) |
owc_dsar_mail_failed | ( int $id, string $email, string $kind ) |
Crons: owc_daily_maintenance, owc_ledger_retention, owc_scanner_run,
owc_scanner_run_batch, owc_tcf_refresh_gvl, owc_run_upgrade.
Internationalisierung
Die Textdomain ist ow-consent, der Pfad /languages. Die Ausgangssprache ist Englisch.
Das Paket liefert die Vorlage ow-consent.pot und eine vollständige französische
Übersetzung.
Zur Erinnerung an den oben beschriebenen Mechanismus: Solange eine Bezeichnung oder ein Bannertext in den Einstellungen nicht angepasst ist, folgt er der Sprache der Website. Sobald Sie Ihren eigenen Wert eintragen, wird er unverändert ausgeliefert, unabhängig von der Sprache des Besuchers.
Die Textkörper der Rechtstexte laufen nicht durch diesen Mechanismus: Ihre Sprache folgt der Jurisdiktion, niemals der Locale des Administrators.
Fehlerbehebung
Das Banner erscheint nicht
Gehen Sie die Liste der Reihe nach durch:
- Ist
banner_enabledaktiviert? Das Abzeichen oben im Backend-Bildschirm sagt es. - Ruft Ihr Theme
wp_head()undwp_footer()auf? Ohne sie weigert sich das Banner zu erscheinen, statt inertes Markup auszugeben. - Hat der Besucher bereits gewählt? Das Banner erscheint nur bei
<html data-owc="none">. Testen Sie im privaten Fenster oder mitwindow.OWCBanner.reset(). - Hat der Besucher JavaScript? Ohne es bleibt das Banner verborgen — mit Absicht — und
der
<noscript>-Block übernimmt. - Liefert ein Page-Cache eine Version von vor der Aktivierung aus? Leeren Sie ihn.
Das Banner kommt auf jeder Seite zurück, obwohl die Wahl erfasst wurde
Drei Ursachen, nach Häufigkeit geordnet.
- Der besuchte Host weicht vom in WordPress konfigurierten Host ab (
www.gegen Apex, Alias, Staging-Domain). Der Browser weigert sich dann, das Cookie zu speichern, während WordPress mit 200 antwortet. Öffnen Sie das Dashboard: Das Ablehnungsprotokoll zeigt Origin undHost-Header nebeneinander. Das Mittel ist, die Website unter einem einzigen kanonischen Host auszuliefern. consent_policy_hash_checkist aktiviert, und Ihre Dokumente haben sich geändert — das ist das gewollte Verhalten, der Besucher wird nach einer Änderung der Rechtstexte erneut gefragt.- Sie sind auf einer Version vor 1.4.3. Das Cookie war damals doppelt kodiert, und der Browser konnte es nicht wieder lesen, während der Server es problemlos las. Aktualisieren Sie: Vor der Korrektur geschriebene Cookies bleiben lesbar.
„Ihre Wahl konnte nicht gespeichert werden“ — Fehler refused oder 403
Sehen Sie sich data-owc-code auf dem Meldungselement an oder das Ablehnungsprotokoll auf
dem Dashboard.
owc_bad_origin: Der angegebene Origin ist kein erkannter Host. Die Antwort listet die akzeptierten Hosts auf. Wird Ihre Website berechtigterweise unter mehreren Namen erreicht, ergänzen Sie sie über den Filterowc_allowed_request_hosts.owc_missing_origin: weder Origin noch Token. Typischerweise eine Privatsphäre-Erweiterung, die Header entfernt, oder ein Proxy, der sie umschreibt.owc_bad_nonce: betrifft nur die Sonde des Scanners, nicht den Einwilligungs-Schreibvorgang — das Nonce ist auf/consentnie ein Veto.
Fehler ratelimit — 429
Die Grenzen sind bei öffentlichen Schreibvorgängen bewusst niedrig. Zwei Ursachen:
- Ein nicht deklariertes CDN oder ein nicht deklarierter Proxy: Alle Ihre Besucher kommen
mit derselben Adresse an und teilen sich dasselbe Budget. Deklarieren Sie ihn mit
OWC_TRUSTED_PROXYinwp-config.php. - Ein automatisierter Test, der mehr als 30 Schreibvorgänge in 5 Minuten von derselben Adresse aus schickt.
Ein 503 owc_ledger_write_refused
Das Protokoll hat den Schreibvorgang verweigert, also wurde nichts erfasst und kein Tracker freigegeben. Das ist das gewollte Verhalten: Eine Einwilligung, die man nicht nachweisen kann, darf man nicht beanspruchen.
- Prüfen Sie, ob die Tabelle
{prefix}owc_ledgerexistiert. Der Tab Audit ledger zeigt eine lesbare Meldung „noch nicht installiert“ statt eines weißen Bildschirms. - Prüfen Sie die Schreibrechte des MySQL-Nutzers.
- Als letztes Mittel deaktivieren Sie
ledger_enabledvorübergehend, um den Dienst wiederherzustellen — im Wissen, dass Sie in dieser Zeit den Nachweis verlieren.
Es laden weiterhin Tracker vor der Einwilligung
- Ist
compliance_strictaktiviert? Ohne es werden nur die von WordPress eingereihten Skripte behandelt. - Steht der Tracker im Katalog? Ein unbekanntes Drittanbieter-Skript ist standardmäßig erlaubt. Starten Sie einen Durchlauf und ordnen Sie den Fund ein: Das schreibt die Blockade-Regel.
- Wird er von First-Party-JavaScript eingefügt? Die dynamische Absicherung deckt nur zwanzig Hosts ab. Ergänzen Sie eine Katalogregel für die Domain des Trackers.
- Ist es ein per
Set-Cookie-Header gesetztes Cookie? Keine clientseitige Blockade kann es aufhalten. Das muss an der Quelle behandelt werden, serverseitig. - Stellen Sie
blocker_unknown_script_policyaufblock— und testen Sie die Website dann gründlich, denn diese Einstellung blockiert jeden nicht erkannten Dritten.
Eine legitime Einbindung wird blockiert
Ergänzen Sie ihren Host in blocker_allowlist, einen pro Zeile, oder über den Filter
owc_blocker_allowlist. Prüfen Sie außerdem blocker_unknown_iframe_policy: Unbekannte
iframes werden standardmäßig blockiert, das ist der häufigste Fall.
Soll die Einbindung von der Einwilligung abhängig bleiben, ordnen Sie sie lieber der richtigen Kategorie zu: Der sichtbare Platzhalter trägt einen Button „… akzeptieren“, der sie mit einem Klick freigibt.
Der Scanner findet nichts
- Ist er aktiviert? Er ist standardmäßig deaktiviert.
- Funktioniert WP-Cron? Mit
DISABLE_WP_CRONund ohne System-Cron startet der geplante Durchlauf nie. Starten Sie einen von Hand, um es zu prüfen. - Ist HTTP-Loopback möglich? Eine HTTP-Authentifizierung auf einer Staging-Umgebung oder eine Firewall blockiert den Durchlauf. Das Abdeckungs-Panel zeigt den ersten Fehler.
- Der Server-Durchlauf führt kein JavaScript aus. Rufen Sie eine Seite der Website als angemeldeter Administrator auf, damit die Sonde meldet, was ein Tag-Manager einschleust.
Lesen Sie in jedem Fall das Panel „was dieser Durchlauf wirklich abdeckt“, bevor Sie Schlüsse ziehen: Es unterscheidet „nichts gefunden“ von „nichts gelesen“.
Die Erzeugung eines Dokuments wird verweigert
Zwei mögliche Ursachen, und die Meldung sagt es:
- Pflichtfelder sind leer — die Liste der fehlenden Schlüssel wird angezeigt. Vervollständigen Sie den Tab Legal identity.
- Sprachsperre — Sie verlangen ein Impressum oder AGB für eine nicht französischsprachige
Jurisdiktion. Der Button ist in diesem Fall ausgeblendet. Der einzige Weg ist, Ihren eigenen
Textkörper über den Filter
owc_policy_templatezu liefern.
Die DSAR-Verifizierungs-E-Mail kommt nicht an
Das liegt fast immer an der Zustellbarkeit, nicht am Plugin.
- Die Antwort der API trägt
mail_sent: false, wenn der Versand fehlgeschlagen ist, und das Formular zeigt dann eine eigene Meldung, die auf die Kontaktadresse verweist. - Installieren Sie ein SMTP-Plugin. Die PHP-Funktion
mail()wird von den meisten Empfangsservern abgelehnt. - Prüfen Sie SPF, DKIM und DMARC Ihrer Domain. Das Plugin schreibt die Absenderadresse
niemals um — genau das würde SPF zerlegen — es setzt nur ein
Reply-To. - Prüfen Sie, ob
dsar_emaileine gültige Adresse ist.
Solange die E-Mail nicht empfangen und bestätigt ist, bleibt die Anfrage pending, und die
gesetzliche Frist beginnt nicht.
Das TCF-Modul wird nicht aktiv
Öffnen Sie den Tab Compliance: Ein Admin-Hinweis benennt die Ursache.
missing_cmp_id:tcf_cmp_idsteht auf 0. Sie müssen eine CMP-ID bei IAB Europe beziehen; das Plugin liefert keine und weigert sich, einen String mit der Kennung 0 auszugeben.- CMP-ID größer als 4095: Der Wert passt nicht in das 12-Bit-Feld des Strings und würde eine andere CMP bezeichnen.
no_gvl: Die Global Vendor List wurde noch nicht heruntergeladen. Sie kommt über einen täglichen Cron; prüfen Sie, ob WP-Cron läuft und ob Ihr Servervendor-list.consensu.orgüber ausgehendes HTTPS erreichen kann.
Alle Besucher bekommen das konfigurierte Profil, trotz regionaler Erkennung
- Ist
geo_enabledaktiviert? Es ist standardmäßig deaktiviert. - Haben Sie Ihren Proxy deklariert? Ohne
OWC_BEHIND_CLOUDFLARE,OWC_BEHIND_CLOUDFRONToderOWC_GEO_TRUSTED_HEADERSinwp-config.phpwerden die Länder-Header ignoriert, weil sie fälschbar sind. - Liegt die MaxMind-Datei bereit? Das Plugin lädt sie nicht herunter und bietet keinen Upload-Bildschirm.
- Vielleicht ist es normal: Der erste Seitenaufruf eines aus dem Cache bedienten Besuchers nutzt das konfigurierte Profil, solange das 24-Stunden-Cookie nicht existiert. Das Dashboard zeigt einen Diagnoseblock mit erkanntem Land, angewendetem Profil und Quelle.
Das Backend meldet, der Protokollschlüssel liege in der Datenbank
Das ist der Hinweis notice_ledger_key. Er bedeutet, dass AUTH_KEY und AUTH_SALT nicht
in wp-config.php stehen — WordPress speichert sie dann in der Datenbank — und dass
OWC_LEDGER_KEY ebenfalls nicht definiert ist. Die Kette wird weiter gebaut, aber wer
Zugriff auf die Datenbank hat, kann sie neu signieren: Der Anspruch auf
Fälschungssicherheit hält nicht mehr.
Das Mittel ist, OWC_LEDGER_KEY (und, wenn Sie schon dabei sind, AUTH_KEY und
AUTH_SALT) in wp-config.php zu ergänzen. Die Prüfung unterscheidet danach eine
Schlüsselrotation von einer Neuschreibung, dieser Wechsel entwertet Ihre Historie also nicht.
Das Plugin tut überhaupt nichts, mit einem roten Hinweis
Ihr WordPress ist älter als 6.2. Das Plugin verweigert den Start, und der Hinweis sagt ausdrücklich, dass nichts blockiert und keine Einwilligung erfasst wird. Aktualisieren Sie WordPress, oder deaktivieren Sie das Plugin und nehmen Sie das Banner solange von Ihren Seiten.
Katalogregeln „können nicht greifen“
Ein Admin-Hinweis weist darauf hin, und der Tab Tracker catalogue hat einen eigenen Filter. Vier mögliche Gründe: leeres oder nur aus unsichtbaren Zeichen bestehendes Muster, regulärer Ausdruck, der nicht kompiliert oder katastrophal zurückverfolgt, für eine URL zu kurzes Muster ohne Punkt, oder Kategorie, die es auf der Website nicht mehr gibt. Korrigieren oder löschen Sie diese Zeilen: Sie erwecken einen falschen Eindruck von Abdeckung.
FAQ
Funktioniert das Plugin hinter einem Page-Cache? Ja, und seine gesamte Architektur ist um diese Vorgabe herum gebaut. Das erzeugte HTML ist für alle Besucher identisch; die Einwilligung wird im Browser gelesen und vor dem ersten Rendern angewendet. Kein Nonce wird in cachebares HTML gedruckt. Nur wirklich personenbezogene Antworten werden als nicht cachebar markiert.
Ersetzt es eine kostenpflichtige CMP? Auf den meisten Websites deckt es dasselbe Feld ab: Banner, Blockade, Audit-Protokoll, Betroffenenanfragen, geografisches Routing und erzeugte Dokumente. Zwei Dinge tut es nicht: Es ist keine bei IAB Europe registrierte CMP, und es liefert keine Rechtsberatung und keine geprüften Dokumente — der Generator produziert Entwürfe, die Sie prüfen lassen müssen.
Ist das Protokoll fälschungssicher?
Es ist unter einer Bedingung manipulationssicher nachweisbar. Jede Zeile wird per HMAC
über den Fingerabdruck der vorherigen signiert: Eine geänderte oder gelöschte Zeile bricht
die Kette, und die Prüfung sagt, wo. Die Garantie beruht darauf, dass der Signaturschlüssel
außerhalb der Datenbank liegt. Das ist der Fall, wenn AUTH_KEY und AUTH_SALT in
wp-config.php stehen oder wenn Sie OWC_LEDGER_KEY definieren. Andernfalls speichert
WordPress die Salts in der Datenbank, und ein Angreifer mit Zugriff darauf könnte die Kette
neu signieren — das Plugin erkennt diese Lage und warnt Sie.
Bremst der Scanner die Website aus? Nein. Er ist standardmäßig deaktiviert, und einmal aktiviert läuft er über WP-Cron in der von Ihnen gewählten Frequenz und ruft serverseitig eine Stichprobe Ihrer eigenen Seiten ab. Er läuft nie während des Besuchs eines Nutzers.
Findet der Scanner die Cookies?
Teilweise, und das ist wichtig zu verstehen. Der Server-Durchlauf liest die
Set-Cookie-Header Ihrer Seiten: Er findet also die vom Server gesetzten Cookies,
einschließlich der HttpOnly-Cookies. Er führt kein JavaScript aus, die von Skripten im
Browser geschriebenen Cookies sind für ihn also unsichtbar; diese sammelt eine Sonde ein, die
nur für einen angemeldeten Administrator läuft. Behandeln Sie das Ergebnis als Inventar
dessen, was gesehen wurde, nicht als vollständige Liste — beide Bildschirme sagen das, statt
Sie im Gegenteil zu lassen.
Wie wird eine Betroffenenanfrage bearbeitet? Die Person sendet das Formular ab und erhält eine Verifizierungs-E-Mail. Die Anfrage auf der verlinkten Seite zu bestätigen startet die Frist nach Artikel 12 Abs. 3 und eröffnet eine native WordPress-Anfrage. Vom DSAR-Bildschirm aus laden Sie einen JSON-Export herunter, den alle auf der Website registrierten Exporter erzeugen, Sie starten alle Eraser, und Sie schließen mit einer schriftlichen Antwort ab, die an der Anfrage hängen bleibt. Was der Export abdeckt, hängt also von den installierten Plugins ab; jene, die keinen dieser Hooks registrieren, müssen von Hand behandelt werden.
Kann ich das TCF-Modul für AdSense oder Ad Manager nutzen? Nur mit Ihrer eigenen, von IAB Europe vergebenen CMP-ID — und selbst dann mit einem Vorbehalt. Ohne CMP-ID lädt das Modul gar nicht. Mit einer CMP-ID gibt es einen korrekt kodierten TC-String aus, und das Panel zeigt jeden Zweck und jedes Special Feature, das dieser String beanspruchen kann — aber die TCF-Policy verlangt von einer registrierten CMP Auswahlmöglichkeiten auf Zweck- und auf Anbieterebene. Hier folgen die Zweckschalter den Kategorien, und es gibt keine Anbieterauswahl: Das ist keine registrierte CMP, und Anbieter dürfen ihr Signal zurückweisen. Wenn Werbeerlöse unter TCF für Ihre Website zählen, nutzen Sie eine zertifizierte CMP.
In welcher Sprache werden die Dokumente erzeugt? Datenschutzerklärung und Cookie-Richtlinie gibt es für alle elf Profile, in der Sprache der Jurisdiktion: Englisch, Französisch für Frankreich, Belgien, Luxemburg und Québec, Portugiesisch für Brasilien. Impressum und AGB gibt es nur auf Französisch; für jede andere Jurisdiktion verweigert der Generator ihre Erzeugung, statt ein unpassendes Dokument zu veröffentlichen.
Was kann ich am Banner ändern?
Vier Positionen, ein helles, dunkles oder automatisches Theme, ein optionales Logo, die
Beschriftungen und einen schwebenden Button zum erneuten Öffnen. Jedes Element mit der Klasse
owc-open-preferences öffnet das Panel wieder. „Alle ablehnen“ wird mit derselben Prominenz
gerendert wie „Alle akzeptieren“. Das Schließkreuz ist standardmäßig deaktiviert; aktiviert
erfasst es eine vollständige Ablehnung, niemals ein stilles Schließen. Das Panel ist mit der
Tastatur bedienbar, seine Schalter tragen einen sichtbaren Zustand, und das Modal fängt den
Fokus und gibt ihn zurück. Die Texte sind übersetzbar und über den Filter owc_banner_texts
ersetzbar.
Was genau blockiert die automatische Blockade? Drittanbieter-Skripte, Inline-Tracking-Snippets, iframes, Mess-Pixel, Analytics- und Marketing-Stylesheets sowie Drittanbieter-Medienquellen werden vor der Einwilligung umgeschrieben und danach freigegeben, in Dokumentreihenfolge. Ressourcen-Hints auf einen katalogisierten Dritten werden entfernt statt aufgeschoben, da ein Hint eine Verbindung öffnet und danach nichts wiederherzustellen ist. Stylesheets und Schriften, die von einem als funktional eingestuften Host kommen, bleiben unangetastet. Die Lazy-Loading-Attribute der Cache-Plugins werden entschärft, damit kein Loader eine blockierte URL wiederherstellt. Das Plugin liefert 175 Signaturen mit, editierbar über den Bildschirm Tracker catalogue und per Filter erweiterbar.
Was wird im Protokoll festgehalten? Jede Einwilligungsaktion — Annahme, Ablehnung, teilweise Speicherung, GPC-Opt-out, Erneuerung, Widerruf — wird an die verkettete Tabelle angehängt. Eine Zeile enthält eine pseudonymisierte IP, einen User-Agent-Fingerabdruck, die Seiten-URL, das Compliance-Profil, einen Fingerabdruck der geltenden Dokumente, einen Fingerabdruck des tatsächlich angezeigten Banners und die Plugin-Version — die Elemente, mit denen sich rekonstruieren lässt, was der Besucher gesehen hat.
Welche Schutzmaßnahmen hat das Formular für Betroffenenrechte? Einen Honeypot, eine Mindestausfüllzeit, eine verpflichtende, serverseitig geprüfte Bestätigung, drei getrennte Rate-Limits, ein Einmal-Token, das nur als Fingerabdruck gespeichert wird, und eine Bestätigung, die eine ausdrückliche Handlung auf der Seite verlangt — damit ein Link-Scanner eines Mailsystems nicht anstelle der Person eine Identität bestätigen kann. Eine Anfrage, deren Urheber seine Identität nie bestätigt hat, kann weder exportiert noch gelöscht noch als erfüllt eingetragen werden, und diese Prüfung läuft serverseitig, nicht nur durch das Ausblenden von Buttons.
Welche Google-Consent-Mode-v2-Signale werden gesendet?
Alle sieben: ad_storage, ad_user_data, ad_personalization, analytics_storage,
functionality_storage, personalization_storage und security_storage. Die sechs
Kategorien sind ihnen über eine einzige Wahrheitsquelle zugeordnet, sodass Banner, Blockade
und Bootstrap nicht auseinanderlaufen können.
Wie werden CCPA-Opt-out und GPC gehandhabt? Ein Bedienelement „Do Not Sell or Share“ wird im Footer eingefügt oder per Shortcode platziert. Der erste Klick erfasst das Opt-out, wie es die kalifornischen Vorschriften verlangen, statt ein Panel zu öffnen. Das Global-Privacy-Control-Signal wird unter den US-Profilen als bindendes Opt-out behandelt, einmal je Browsersitzung, und der Besucher wird benachrichtigt, wenn es eine von ihm gespeicherte Wahl ersetzt hat. Unter den Profilen der DSGVO-Familie gilt GPC als Hinweis: Die optionalen Kategorien sind in der Oberfläche vorabgelehnt, das Banner bleibt sichtbar, und nichts wird erfasst — weil die Einwilligung dort eine aktive Handlung sein muss.
Welche Cookies setzt das Plugin selbst?
Alle sind interne Cookies, keines dient dem Tracking, und alle sind in der erzeugten
Cookie-Richtlinie deklariert: owc_consent (die Wahl, das pseudonyme Browser-Token und das
Profil; Dauer gemäß der Erneuerungseinstellung, standardmäßig 12 Monate, gedeckelt auf 13),
owc_geo (erkanntes Land und Profil, 24 Stunden, ohne jede IP-Adresse), owc_gpc
(Sitzungsmarker), owc_gpc_notice (5 Minuten) und euconsent-v2 (TCF-String, nur wenn das
Modul aktiviert ist und nach einer Handlung des Besuchers).
Funktioniert es im Multisite-Betrieb? Ja. Jede Website im Netzwerk hat ihre eigenen Tabellen und ihre eigenen Einstellungen. Eine netzwerkweite Aktivierung geht alle Websites nur dann durch, wenn das Netzwerk höchstens 200 umfasst; darüber wird jede Website bei ihrer ersten Anfrage bereitgestellt.
Und wenn ich das Plugin lösche? Protokoll, Scanner-Funde, Katalog, OW Forms-Verknüpfungen, Optionen und Einstellungen bleiben standardmäßig erhalten. Zwei Dinge verschwinden immer, unabhängig von Ihrer Einstellung: die sechs geplanten Aufgaben und die Tabelle der Betroffenenanfragen — sie ist die einzige mit direkt identifizierenden personenbezogenen Daten Dritter, und sobald das Plugin weg ist, begrenzt nichts mehr ihre Aufbewahrung, und kein Bildschirm erlaubt es noch, darauf zu antworten. Exportieren Sie Ihre Anfragen, bevor Sie das Plugin löschen. Für ein vollständiges Aufräumen des Rests aktivieren Sie „Delete all data on uninstall“ vor der Löschung.
Wo finde ich Support?
- Support-Portal: https://optionweb.dev/de/addons/support/
- E-Mail: support@optionweb.dev
- Dokumentation: https://optionweb.dev/de/addons/ow-consent/