Live · Status OK
Dokumentation · OW Consent v1.4.3

OW Consent
Dokumentation

Die WordPress-Einwilligung, die Tracker vor dem Klick blockiert – nicht danach.

v1.4.3GPL-2.0-or-laterDokumentation

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

  1. Überblick
  2. Installation
  3. Schnellstart
  4. Die elf Compliance-Profile
  5. Die Cookie-Kategorien
  6. Das Banner
  7. Die automatische Blockade
  8. Der Tracker-Scanner
  9. Der Generator für Rechtstexte
  10. Das Einwilligungsprotokoll
  11. Das Portal für Betroffenenrechte (DSAR)
  12. Das CCPA-Opt-out „Do Not Sell or Share“
  13. Google Consent Mode v2
  14. IAB TCF v2.2
  15. Global Privacy Control
  16. Die regionale Erkennung
  17. Die OW Forms-Integration
  18. Der schwebende Button
  19. Shortcodes
  20. REST API
  21. Einstellungsreferenz
  22. Fehlerbehebung
  23. 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 bekommt quebec.
  • 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

  1. Laden Sie ow-consent-1.4.3.zip von https://optionweb.dev/de/addons/ow-consent/
  2. Plugins → Installieren → Plugin hochladen
  3. 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 %i von wpdb::prepare() gebunden, den WordPress erst ab 6.2 versteht. Auf einem älteren Core würde prepare() 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 Header Requires at least verhindert 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:

TabelleInhalt
{prefix}owc_ledgerDas Einwilligungsprotokoll, per Hash verkettet
{prefix}owc_dsarDie Betroffenenanfragen
{prefix}owc_scannerDie Funde des Tracker-Scanners
{prefix}owc_scriptsDer 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 per INSERT IGNORE eingefü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_upgrade fü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:

  1. Immer, unabhängig von Ihrer Einstellung: Die sechs Crons werden gelöscht und die Tabelle {prefix}owc_dsar wird 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.
  2. Nur wenn delete_data_on_uninstall ausdrücklich aktiviert ist: Löschung der Tabellen owc_ledger, owc_dsar, owc_scanner, owc_scripts und owc_form_links, der benannten Optionen, aller Optionen mit dem Präfix owc_ (inklusive Transients) und der usermeta mit dem Präfix owc_. 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

ProfilAngesprochener RechtsrahmenModell
gdprDSGVO + ePrivacy (EU/EWR)Opt-in
uk_pecrUK GDPR + PECR (Vereinigtes Königreich)Opt-in
ch_nfadpSchweizer revDSGOpt-in
quebecLoi 25 (Québec)Opt-in
lgpdLGPD (Brasilien)Opt-in
popiaPOPIA (Südafrika)Opt-in
piplPIPL (China)Opt-in
dpdpDPDP Act 2023 (Indien)Opt-in
ccpaCCPA / CPRA (Kalifornien)Opt-out
us_genericAllgemeine US-BundesstaatengesetzeOpt-out
auPrivacy 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 ändertDetail
EinwilligungsmodellOpt-in, außer bei ccpa, us_generic, au
Standardwerte von Consent ModeUnter einem Opt-out-Profil stehen alle sieben Signale auf granted
„Do Not Sell or Share“-Link vorgeschriebenNur ccpa und us_generic
GPC rechtlich bindendNur ccpa und us_generic — Australien ist ausdrücklich ausgenommen: Opt-out-Rahmen, der GPC aber nicht anerkennt
Geltungsbereich „die DSGVO gilt“ für TCF27 EU-Länder + IS, LI, NO + GB + CH, also 31 Codes
Sprache des erzeugten Dokumentsquebec → Französisch; lgpd → Portugiesisch; gdpr mit Land FR, BE oder LU → Französisch; alles Übrige → Englisch
Genannte AufsichtsbehördeTabelle je Profil, für die DSGVO nach Land verfeinert
Veröffentlichte Liste der BetroffenenrechteEine je Profil formulierte Liste, mit Artikelangabe
Abschnitt „Cookie-Regime“ des englischen DokumentsText, Ü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

ProfilGenannte Behörde
gdpr, Land FRCNIL
gdpr, Land BEAPD-GBA
gdpr, Land LUCNPD
gdpr, Land DEBfDI
gdpr, anderes EWR-LandAllgemeine Formulierung („die zuständige Aufsichtsbehörde“)
uk_pecrICO
ch_nfadpEDÖB / FDPIC
quebecCommission d'accès à l'information
lgpdANPD
ccpaCalifornia Privacy Protection Agency
popiaInformation Regulator (South Africa)
piplCyberspace Administration of China
dpdpData Protection Board of India
auOAIC
us_genericAttorney 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_generic existiert 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_template Ihren eigenen Textkörper.

Die Cookie-Kategorien

Die kanonische Liste

Sechs Kategorien, in dieser Anzeigereihenfolge, necessary immer zuerst:

SlugMitgelieferte BezeichnungMitgelieferte Beschreibung
necessaryNecessaryStrictly required for the site to function (cart, login, language preferences). Cannot be disabled.
functionalFunctionalEnhance the experience (chat, embedded videos, maps). Without them some features may not work.
analyticsStatisticsHelp us understand how you use the site (anonymously). No personal data is shared for commercial purposes.
marketingMarketingEnable us to show you ads and content tailored to your interests on other sites.
preferencesPreferencesRemember your interface choices (layout, saved filters).
socialSocial & embedsAllow 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.

KategorieConsent-Mode-v2-Signale
necessarysecurity_storage, functionality_storage
functionalfunctionality_storage, personalization_storage
analyticsanalytics_storage
marketingad_storage, ad_user_data, ad_personalization
preferencespersonalization_storage
socialad_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

functionalfunctional, analyticsmeasurement, marketingadvertising, preferencespersonalization, socialsocial_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

EinstellungWerteStandard
banner_positionbottom-bar, bottom-card, center-modal, top-barbottom-bar
banner_styleauto, light, darkauto

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

EinstellungStandardWirkung
banner_accept_alltrueZeigt „Alle akzeptieren“
banner_reject_alltrueZeigt „Alle ablehnen“
banner_preferencestrueZeigt „Anpassen“
banner_close_xfalseZeigt das Schließkreuz
banner_show_logotrueZeigt 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:

  1. Wenn banner_close_x aus ist, steckt das Kreuz zwar im Markup, trägt aber das Attribut hidden, und das CSS entfernt es vollständig: weder sichtbar noch fokussierbar noch für Screenreader angekündigt.
  2. Wenn es aktiviert ist, führt ein Klick auf das Kreuz den vollständigen Pfad „Alle ablehnen“ aus, niemals ein stilles Schließen.
  3. 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 einem wp_kses gerendert, 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"> mit aria-checked, aria-labelledby und aria-describedby. Der Zustand wird über aria-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

EinstellungStandardGrenzen
consent_renewal_months120 bis 13
consent_policy_hash_checktrue

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.

  1. 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 Host umschreibt), ist diese URL Cross-Origin, und der Browser weigert sich, das Set-Cookie zu speichern, während WordPress mit 200 antwortet. Das Runtime verankert den von PHP gelieferten Pfad deshalb neu auf dem tatsächlich besuchten Origin.
  2. Nonce. Frisch über GET /owc/v1/nonce unmittelbar vor dem Schreiben geholt, nie in cachebares HTML eingebettet, im Header X-OWC-Nonce gesendet. 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.
  3. Ausdrückliche page_url im Body der Anfrage, damit die Protokollzeile nicht vom Referer-Header abhängt, den eine Erweiterung, eine Meta-Referrer-Angabe oder ein Proxy entfernen kann.
  4. Blockade-Schutz von 15 Sekunden mit AbortController: Die Anfrage wird abgebrochen, nicht nur ignoriert, damit ein verspäteter POST keine zweite Zeile schreibt.
  5. Definition von Erfolg. Der POST gilt genau dann als erfolgreich, wenn: die Antwort ok ist, der Body auswertbares JSON ist, json.ok === true gilt 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.
  6. 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.
  7. Genau ein Wiederholungsversuch, und nur bei einem 403, dessen Code owc_bad_nonce, rest_cookie_invalid_nonce oder rest_nonce_invalid lautet, und nur wenn das erhaltene Nonce tatsächlich ein anderes ist.
  8. 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 bei hashchange ausgewertet;
  • jedes Element mit der Klasse owc-open-preferences oder dem Attribut data-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() und wp_footer(): Ein Theme, das sie nicht aufruft, bekommt nichts.
  • Ohne window.fetch und window.Promise ist kein Schreiben möglich, und der Fehler browser wird 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_tag ist eingehängt. Anders gesagt: Nur die über wp_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 selbst Content-Type: text/html deklariert 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:

  1. bereits behandelt → unverändert;
  2. Skript des Plugins selbst → unverändert;
  3. type="text/plain" oder Nicht-JS-Typ (ld+json, importmap, x-template) → unverändert;
  4. 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;
  5. Host auf der Allowlist → unverändert; First-Party-Ressource, die nicht nach einem Tracker aussieht → unverändert;
  6. Abgleich mit dem Katalog über die Form Host + Pfad; eine data:- oder javascript:-URL wird dekodiert und wie ein Inline-Textkörper bewertet;
  7. eine als necessary eingestufte Regel wird nie blockiert (Stripe.js, reCAPTCHA, Turnstile, cdnjs …): Sie zu blockieren bringt keinerlei Compliance und zerlegt das aufrufende Snippet;
  8. keine Übereinstimmung → blocker_unknown_script_policy, Standard allow;
  9. sonst Umschreiben auf type="text/plain" mit data-owc-cat, data-owc-vendor, data-owc-src und, falls der ursprüngliche Typ besonders war (module etwa), 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 akzeptieren“ enthält, welcher die zugehörige Kategorie freigibt.

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 analytics oder marketing eingestuftes Stylesheet wird entschärft.
  • Google Fonts und andere als functional eingestufte 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_consent wird 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.src und setAttribute werden umhüllt. Ein First-Party-Loader, der s.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 onload oder onerror, mit einer Obergrenze von 5 Sekunden, damit ein nicht erreichbarer Anbieter nicht den Rest aufhält. Das Attribut async wird nur gesetzt, wenn es ursprünglich vorhanden war — sonst würde ein per createElement erzeugtes Skript zwangsweise asynchron und das Konfigurations-Snippet liefe vor seiner Bibliothek. Bei einem wiederhergestellten Inline-Skript wird document.write vorübergehend umgeleitet, um das Dokument nicht zu löschen.
  • Widerruf der Einwilligung: Wenn eine bereits angewendete Kategorie ausdrücklich auf false wechselt, 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 MutationObserver scannt 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:

AufteilungDetail
Nach Ziel110 URL-Muster, 65 Cookie-Namen
Nach Typ172 Textfragmente, 3 reguläre Ausdrücke
Nach Kategorienecessary 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

EinstellungStandardWerte
compliance_stricttrueboolesch
blocker_unknown_script_policyallowallow, block
blocker_unknown_iframe_policyblockallow, block
blocker_block_resource_hintstrueboolesch
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

  1. Ohne compliance_strict werden nur die von WordPress eingereihten Skripte behandelt.
  2. 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.
  3. 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.
  4. Als functional eingestufte Stylesheets (Webfonts) werden bewusst durchgelassen.
  5. Ein im Katalog geführter Tracker in einem <img>, der anders als analytics oder marketing eingestuft ist, wird nicht entschärft.
  6. Medien (object, embed, source, video, audio) werden nie standardmäßig blockiert: Nur ein bereits katalogisierter Dritter wird behandelt.
  7. 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.
  8. 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

RandbedingungWert
URLs pro Laufscanner_max_urls, Standard 25, Grenzen 1 bis 500
Timeout pro Anfragescanner_timeout, Standard 8 s, Grenzen 1 bis 60
Zeitbudget pro Paketmax_execution_time − 10 s, sonst 45 s, begrenzt auf 5 bis 60 s
Ausführungssperre15 Minuten
Lebensdauer der Warteschlange6 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 cookie wird zu einer Regel match_target = cookie auf dem Cookie-Namen;
  • ein Fund vom Typ inline_script schreibt 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:

  1. Nicht kategorisierte Tracker — nur für wirklich neue Kennungen versandt, mit einem auf 500 Einträge gedeckelten Gedächtnis.
  2. „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

EinstellungStandardGrenzen
scanner_enabledfalseboolesch
scanner_frequencyweeklyhourly, twicedaily, daily, weekly
scanner_max_urls251 bis 500
scanner_timeout81 bis 60
scanner_probe_modeadminsadmins, off
scanner_alert_email''E-Mail-Adresse

Wichtig: scanner_probe_mode wird 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 auf scanner_enabled. off zu speichern legt den Wert ab, ohne die Sonde abzuschalten. Um die Sonde wirklich zu stoppen, deaktivieren Sie den Scanner.

Grenzen des Scanners

  1. Der Server-Durchlauf führt kein JavaScript aus. Ohne die Sonde fehlt im Inventar, was ein Tag-Manager einschleust.
  2. 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.
  3. Ein per Set-Cookie-Header gesetztes Cookie wird erkannt, ist aber nicht blockierbar.
  4. Der Durchlauf verlässt die Domain nie und ist standardmäßig auf 25 URLs gedeckelt: Eine große Website wird nie vollständig abgedeckt.
  5. Auf einem Host, bei dem HTTP-Loopback blockiert ist (HTTP-Authentifizierung auf einer Staging-Umgebung, Firewall), liest der Durchlauf gar nichts.
  6. Ein seit 90 Tagen nicht mehr gesehener Fund verschwindet — und damit auch aus der Cookie-Richtlinie.
  7. Der Scanner hängt an WP-Cron: Auf einer Website mit DISABLE_WP_CRON und ohne System-Cron wird der geplante Durchlauf nicht ausgelöst.

Der Generator für Rechtstexte

Die vier Dokumente

TypInhaltVerfügbare Sprachen
cookie_policyCookie-RichtlinieFranzösisch, Englisch, Portugiesisch
privacy_policyDatenschutzerklärungFranzösisch, Englisch, Portugiesisch
legal_noticeImpressumnur Französisch
termsAGBnur 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.

DokumentVerlangte Felder
Allelegal_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

ProfilSprache des Dokuments
quebecFranzösisch
lgpdPortugiesisch
gdpr mit legal_country ∈ {FR, BE, LU}Französisch
Alles ÜbrigeEnglisch

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.

  1. 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.
  2. 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.
  3. Nicht eingeordnete Tracker werden nicht versteckt: Sie bekommen einen eigenen Abschnitt. Es sind die, die niemand geprüft hat.
  4. 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.
  5. 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 Einstellungenledger_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

MethodePfadParameterZugriff
POST/owc/v1/policies/generatetype (erforderlich), publish (boolesch, Standard false)manage_options
GET/owc/v1/policies/previewtype (erforderlich)manage_options

Das HTML der Vorschau läuft vor der Rückgabe durch wp_kses_post().

Grenzen des Generators

  1. Das sind Vorlagen, keine Rechtsberatung. Lassen Sie sie prüfen.
  2. 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.
  3. Nur drei Sprachen: Französisch, Englisch, Portugiesisch.
  4. Vier EWR-Länder haben eine namentlich genannte Behörde; anderswo eine allgemeine Formulierung.
  5. Die Tracker-Tabelle ist nur so viel wert wie Ihr Durchlauf — und das Dokument sagt es.
  6. 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:

SpalteTypInhalt
idbigintPrimärschlüssel
created_atdatetimeZeitstempel in UTC
visitor_tokenchar(32)Pseudonymes Browser-Token, 32 Hexadezimalzeichen
eventvarchar(20)accept_all, reject_all, save_preferences, withdraw, auto, gpc_opt_out
categoriesvarchar(255)Liste der freigegebenen Kategorien
profilevarchar(20)Zum Zeitpunkt der Aktion geltendes Compliance-Profil
sourcevarchar(60)banner, preferences, footer_link, api, auto
ip_pseudonymousvarchar(45)Gekürzte IP
ua_hashchar(64)Gesalzener Fingerabdruck des User-Agents
page_urlvarchar(500)Seite, auf der die Aktion stattfand
prev_hashvarchar(128)Fingerabdruck der vorherigen Zeile
row_hashvarchar(128)Fingerabdruck dieser Zeile
policies_hashchar(64)Fingerabdruck der geltenden Dokumente
banner_revisionvarchar(40)Fingerabdruck des tatsächlich angezeigten Banners
plugin_versionvarchar(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:

HerkunftBedingungUrteil
constantOWC_LEDGER_KEY ist definiertFälschungssicher
wp-configAUTH_KEY und AUTH_SALT sind definiert, nicht leer, voneinander verschieden und ohne den StandardsatzFälschungssicher
databaseSonstNicht 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; der Referer wird 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

  1. Die Fälschungssicherheit ist an eine Bedingung geknüpft, und das Plugin sagt es selbst.
  2. 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.
  3. Die Aufbewahrung ist auf 20 000 Zeilen je täglichem Lauf gedeckelt.
  4. 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:

AttributStandardZweck
typesaccess,rectification,erasure,portability,restrict,object,optoutAngebotene 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: access und portability → Export; erasure → Löschung; die anderen Typen eröffnen keine native Anfrage.
  • Der Verantwortliche wird an dsar_email und dsar_notify_email benachrichtigt, 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.

AktionVerhalten
Daten herunterladen (JSON)Ablehnung mit 409, wenn die Identität nie bestätigt wurde. Die Datei heißt dsar-<id>-<JJJJMMTT>.json
Daten löschenNur 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 MonateVerlä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ßenStatus 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 sendenErzeugt 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:
    1. nie bestätigte Einreichungen werden gelöscht — kein Beweiswert, nur personenbezogene Daten;
    2. 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_days erreicht ist;
    3. eine noch offene Anfrage bleibt erhalten, mit einer Meldung, die erklärt, dass sie beantwortet werden muss, bevor sie gelöscht wird;
    4. 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

EinstellungStandardGrenzen
dsar_enabledtrueboolesch
dsar_email''öffentlicher Kontakt und Empfänger der Benachrichtigungen
dsar_notify_email''zusätzlicher Empfänger
dsar_response_days301 bis 30 — nie mehr als ein Monat
dsar_token_ttl_days71 bis 90
retention_dsar_days1095 (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

  1. 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.
  2. Ein fehlgeschlagener E-Mail-Versand blockiert den Ablauf: Die Antwort weist mail_sent: false aus, und das Formular zeigt eine Meldung, die auf die Kontaktadresse verweist — aber die Anfrage bleibt pending, und die gesetzliche Frist beginnt nicht.
  3. Fristerinnerungen und Bereinigung hängen an WP-Cron.
  4. 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"]
AttributStandard
label„Do Not Sell or Share My Personal Information“
classowc-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

  1. Das Ein-Klick-Element verlangt fetch und Promise.
  2. Der Link ist nur unter den Profilen ccpa und us_generic vorgeschrieben; unter jedem anderen Profil wird er weder angezeigt noch eingeblendet.
  3. 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.

SignalOpt-in-RahmenOpt-out-Rahmen
ad_storagedeniedgranted
analytics_storagedeniedgranted
ad_user_datadeniedgranted
ad_personalizationdeniedgranted
personalization_storagedeniedgranted
functionality_storagedenied, wenn die Website die Kategorie functional anbietet, sonst grantedgranted
security_storageimmer grantedgranted

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

EinstellungStandardWirkung
gcm_ads_data_redactiontrueVerdeckt Werbekennungen, solange ad_storage abgelehnt ist
gcm_url_passthroughtrueReicht 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

EinstellungStandardGrenzen
tcf_enabledfalseboolesch
tcf_cmp_id00 bis 4095
tcf_publisher_countryFRISO-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

  1. Keine CMP-ID (tcf_cmp_id < 1): kein __tcfapi, kein TC-String, kein Cookie euconsent-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.
  2. 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.
  3. 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 einem ETag und einem Cache-Control: public, max-age=86400 und behandelt bedingte Anfragen. Ist nichts im Cache, antwortet sie mit 503 und einem Retry-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

KategorieZwecke
necessarykeine — außerhalb des TCF-Geltungsbereichs, was garantiert, dass „Alle ablehnen“ keine Einwilligung für Zweck 1 erzeugen kann
functional1
analytics1, 8, 9, 10
marketing1, 2, 3, 4, 7
preferences1, 5, 6, 11
social1

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

  1. 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.
  2. Nur das Core-Segment: kein Segment disclosedVendors, allowedVendors oder publisherTC.
  3. Es werden keine Publisher Restrictions ausgegeben: Der entsprechende Zähler steht immer auf 0, und das Restriktionsobjekt ist leer.
  4. purposeOneTreatment und useNonStandardTexts sind immer false, isServiceSpecific ist immer true — es gibt keine globale Geltung — und der Consent Screen ist immer 0.
  5. getVendorList ignoriert den Versionsparameter und liefert immer die gecachte Liste.
  6. Die Publisher-Einwilligungen übernehmen die allgemeinen Zwecke: keine eigenen Zwecke.
  7. Nur zwei Special Features.
  8. 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:

  1. gpc_honor ist aktiviert;
  2. das Signal ist vorhanden — der Header Sec-GPC, mit Rückfall auf X-Sec-GPC, weil manche Proxys und CDNs den Header umbenennen; nur der exakte Wert 1 zählt;
  3. das effektive Profil ist ccpa oder us_genericsonst wird nichts geschrieben;
  4. 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;
  5. 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;
  6. der Sitzungsmarker owc_gpc fehlt: einmal je Browsersitzung;
  7. 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, libwww oder facebookexternalhit enthält);
  8. die bereits gespeicherte Wahl erfüllt das Signal noch nicht — sonst wird nur der Browser markiert;
  9. das gemeinsame Rate-Limit ist eingehalten: 30 pro Stunde und IP;
  10. 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_personalization und personalization_storage auf denied;
  • alle optionalen Kategorien werden nur im Arbeitsspeicher auf false gesetzt;
  • given bleibt 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

CookieDauerZweck
owc_gpcSitzungMerkt, dass das Signal für diesen Browser schon behandelt wurde
owc_gpc_notice300 sLö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.

EinstellungStandard
geo_enabledfalse
geo_default_profilegdpr
geo_mmdb_enabledfalse

Die Erkennungskaskade

Der erste Treffer gewinnt:

  1. Cloudflare (CF-IPCountry) — nur wenn die Website deklariert hat, hinter Cloudflare zu laufen;
  2. AWS CloudFront (CloudFront-Viewer-Country) — dieselbe Bedingung;
  3. 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;
  4. Lokale MaxMind-Datenbank, wenn geo_mmdb_enabled aktiviert ist;
  5. 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 HTTPS Secure, 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

LandProfil
Die 30 EWR-Ländergdpr
GB, JE, GG, IMuk_pecr
CHch_nfadp
BRlgpd
ZApopia
CN, HKpipl
INdpdp
AU, NZau
CAquebec
USccpa
Alles ÜbrigeDer 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_country und represented_country werden 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

  1. Standardmäßig deaktiviert, und die MaxMind-Variante verlangt eine Datei, die Sie liefern.
  2. Länder-Header werden ignoriert, solange Sie Ihren Proxy nicht deklariert haben.
  3. Keine Granularität nach US-Bundesstaat und keine nach kanadischer Provinz.
  4. Der Rahmen des Besuchers hängt an JavaScript und am 24-Stunden-Cookie.
  5. Das Profil us_generic wird 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

  1. 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.
  2. 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.
  3. Keine rückwirkende Erfassung: Die Verknüpfung beginnt mit der ersten Übermittlung nach dem Update.
  4. 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.
  5. Die Integration verändert niemals das Plugin OW Forms, seine Tabellen oder seine Optionen.
  6. 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

EinstellungWerteStandard
floating_button_enabledbooleschtrue
floating_button_positionbottom-left, bottom-right, top-left, top-rightbottom-left
floating_button_stylepill, iconpill
floating_button_labelfreier TextCookies

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"]
AttributStandard
typesaccess,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"]
AttributStandard
label„Do Not Sell or Share My Personal Information“
classowc-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.

MethodePfadParameterZweck
GET/nonceaction (Standard wp_rest)Liefert ein frisches Token. Antwort: {nonce, action, header: "X-OWC-Nonce", ttl: 43200}, mit no-store und Vary: Cookie
POST/consentevent (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/stateDer 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/gvlLiefert 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/dsartype (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_out
  • source: banner, preferences, footer_link, api, auto
  • type (DSAR): access, rectification, erasure, portability, restrict, object, optout, withdraw
  • categories: ein Objekt, höchstens 32 Einträge, nur skalare Werte
  • action (Nonce): nur wp_rest

Administrative Routen

Alle verlangen die Berechtigung manage_options.

MethodePfadParameterZweck
GET/ledgerpage (≥1, Standard 1), per_page (1–200, Standard 50), visitor_token (32 Hex), from, toLiest das Protokoll. Die tatsächlich angewendeten Filter kommen in der Antwort zurück
GET/ledger/verifyPrüft die Kette von Anfang bis Ende
GET/settingsDie effektiven Einstellungen
POST/settingsfreier JSON-BodySchreibt die Einstellungen. Antwort {ok, updated, rejected, settings}
POST/scanner/runStartet einen Durchlauf
POST/scanner/ingestJSON-Body {page, findings[]}Nimmt die Beobachtungen der Sonde entgegen
GET/scanner/findingspage, per_page (1–200, Standard 50), filter (Kategorie-Slug oder unknown)Listet die Funde
POST/policies/generatetype (erforderlich), publish (boolesch, Standard false)Erzeugt ein Dokument
GET/policies/previewtype (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.

  1. Origin-Prüfung auf denselben Host. Kostenlos, deterministisch, verbraucht kein Budget.
  2. Plugin-eigenes Token im Header X-OWC-Nonce — das ist ein Nachweis, nie ein Veto. Auf X-WP-Nonce zu 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.
  3. Geschlossener Fehlschlag: Weder Origin noch geprüftes Token ergeben einen 403 owc_missing_origin.
  4. 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

BucketBudgetZeitfensterSchlüssel
nonce1205 MinutenIP-Adresse
consent305 MinutenIP-Adresse
dsar31 StundeIP-Adresse
dsar_email324 Stundenbetroffene E-Mail-Adresse
dsar_global301 Stundedie gesamte Website
gpc301 StundeIP-Adresse
tcf_gvl101 StundeIP-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_PROXY deklarierten 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 )0 zurü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, mit cookie_set: false und einem Deskriptor cookie (name, value, ttl, path, samesite, secure), den der Client selbst setzt.
  • Kategorien, die die Website nicht anbietet, kommen in dropped_categories zurück, statt stillschweigend ignoriert zu werden.
  • page_url wird gegen die Hosts der Website validiert, mit Rückfall auf einen genauso validierten Referer, sonst der leere String. Der Schlüssel ist immer vorhanden, damit das Protokoll nicht selbst den rohen Referer heranzieht.
  • 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_unreadable ist 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

CodeHTTPBedeutung
owc_bad_param400Ungültiger Parameter
owc_bad_categories400Objekt categories fehlerhaft, zu groß oder nicht skalar
owc_bad_email400Ungültige E-Mail-Adresse
owc_bad_dsar400Fehlerhafte DSAR-Einreichung (Honeypot eingeschlossen)
owc_dsar_not_attested400Bestätigung nach Art. 12 Abs. 6 fehlt
owc_no_settings400Kein bekannter Einstellungsschlüssel im Body
owc_missing_origin403Weder Origin noch Token: geschlossener Fehlschlag
owc_bad_origin403Der angegebene Origin ist kein Host dieser Website — die Antwort listet bis zu zehn akzeptierte Hosts
owc_bad_nonce403Ungültiges Nonce auf /scanner/ingest
owc_jsonp_forbidden403JSONP-Form auf /nonce abgelehnt
owc_forbidden401/403Berechtigung nicht ausreichend
owc_dsar_disabled404Das Portal für Betroffenenrechte ist serverseitig deaktiviert
owc_no_template404Keine Vorlage für diesen Typ und dieses Profil
owc_rate_limited429Rate-Limit erreicht
owc_consent_failed500Anwenden der Einwilligung fehlgeschlagen
owc_dsar_store_failed500Schreiben der Anfrage fehlgeschlagen
owc_gen_failedvariabelDokumenterzeugung verweigert (fehlende Felder, Sprachsperre)
owc_ledger_write_refused503Das 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

  1. /consent und /dsar akzeptieren konstruktionsbedingt anonyme Schreibvorgänge; der Schutz ist der Origin plus das Rate-Limit, kein Nonce.
  2. Der Rate-Limiter schlägt ohne Object Cache offen fehl.
  3. 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.
  4. /scanner/ingest akzeptiert nur manage_options: Die Sonde kann nicht von einem Besucher kommen.
  5. /settings hat kein eigenes Nonce: Es ist manage_options plus 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.

EinstellungAkzeptierte Werte
banner_positionbottom-bar, bottom-card, center-modal, top-bar
banner_styleauto, light, dark
floating_button_positionbottom-left, bottom-right, top-left, top-right
floating_button_styleicon, pill
compliance_profile, geo_default_profilegdpr, ccpa, lgpd, popia, pipl, dpdp, quebec, uk_pecr, ch_nfadp, au, us_generic
ledger_hash_algosha256, sha3-256 (geschnitten mit dem, was PHP unterstützt)
scanner_frequencyhourly, twicedaily, daily, weekly
scanner_probe_modeadmins, off
legal_business_typeauto, vitrine, rental, ecommerce, services, saas, content
blocker_unknown_script_policy, blocker_unknown_iframe_policyallow, block

Grenzen der Ganzzahlwerte

EinstellungGrenzen
consent_renewal_months0 bis 13 (0 wird wie 13 behandelt)
dsar_response_days1 bis 30
dsar_token_ttl_days1 bis 90
ledger_retention_days0 bis 3650 (0 = unbegrenzt)
scanner_max_urls1 bis 500
scanner_timeout1 bis 60
legal_minor_age13 bis 18
retention_form_data_days1 bis 3650
retention_dsar_days1 bis 3650
tcf_cmp_id0 bis 4095

Bereinigung

  • text_message ist 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_allowlist sowie jeder Schlüssel, der auf _desc endet.
  • URLs: jeder Schlüssel mit dem Präfix link_ oder der Endung _url, dazu legal_profession_rules.
  • E-Mail-Adressen: jeder Schlüssel, der email enthä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

TabEinstellungen
Bannerbanner_*, text_*, floating_button_*, consent_renewal_months, consent_policy_hash_check
Compliancecompliance_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 identitylegal_*, retention_form_data_days, retention_dsar_days, policy_disclaimer
Categoriescat_*_available, cat_*_label, cat_*_desc
Audit ledgerledger_enabled, ledger_retention_days (der Algorithmus wird angezeigt, nicht geändert)
Scannerscanner_*
DSAR requestsdsar_*

Tabellen

TabelleInhalt
{prefix}owc_ledgerVerkettetes Einwilligungsprotokoll
{prefix}owc_dsarBetroffenenanfragen
{prefix}owc_scannerFunde des Scanners
{prefix}owc_scriptsSignaturkatalog der Blockade
{prefix}owc_form_linksVerknü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

KonstanteWirkung
OWC_LEDGER_KEYHMAC-Schlüssel des Protokolls und abgeleiteter Schlüssel des Cookies für die regionale Erkennung
OWC_TRUSTED_PROXY / OWC_TRUSTED_PROXIESCIDR-Bereiche der vertrauenswürdigen Proxys; ohne sie werden die Client-IP-Header ignoriert
OWC_GEO_TRUSTED_HEADERScloudflare, cloudfront, proxy oder all
OWC_BEHIND_CLOUDFLAREKurzform für den Länder-Header von Cloudflare
OWC_BEHIND_CLOUDFRONTKurzform für den Länder-Header von CloudFront

Die Entwickler-Hooks

Filter

FilterZweck
owc_settingsEffektive Einstellungen. Die Antwort muss von etwas abhängen, das für die gesamte Anfrage stabil ist
owc_banner_textsTexte des Banners
owc_bootstrap_configStatische Konfiguration, die in <head> ausgegeben wird — nie besucherspezifische Daten
owc_scripts_catalogKatalogzeilen vor der Validierung
owc_blocker_allowlistHosts, die nie blockiert werden
owc_scanner_urlsZu durchlaufende URLs (danach erneut auf den Host der Website eingeschränkt)
owc_throttle_maxBudget eines Rate-Limits; 0 schaltet es ab
owc_allowed_request_hostsFür einen öffentlichen Schreibvorgang akzeptierte Hosts
owc_allow_headerless_writeHebt den geschlossenen Fehlschlag bei Schreibvorgängen ohne Origin auf (Standard false)
owc_geo_mmdb_pathPfad zur MaxMind-Datenbank
owc_tcf_purpose_mapZuordnung Kategorien → TCF-Zwecke
owc_tcf_stub_configStatische Konfiguration des TCF-Stubs
owc_policy_templateRoher Textkörper einer Vorlage — hebt die Sprachsperre auf
owc_policy_varsVariablen eines Dokuments
owc_policy_htmlFertiges HTML eines Dokuments
owc_dsar_typesAngebotene und akzeptierte Anfragetypen
owc_dsar_form_noticeInformationshinweis unter dem Formular
owc_dsar_export_bundleInhalt des Portabilitäts-Bundles
owc_dsar_show_fulfilment_panelAnzeige des Ausführungs-Panels

Aktionen

AktionSignatur
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:

  1. Ist banner_enabled aktiviert? Das Abzeichen oben im Backend-Bildschirm sagt es.
  2. Ruft Ihr Theme wp_head() und wp_footer() auf? Ohne sie weigert sich das Banner zu erscheinen, statt inertes Markup auszugeben.
  3. Hat der Besucher bereits gewählt? Das Banner erscheint nur bei <html data-owc="none">. Testen Sie im privaten Fenster oder mit window.OWCBanner.reset().
  4. Hat der Besucher JavaScript? Ohne es bleibt das Banner verborgen — mit Absicht — und der <noscript>-Block übernimmt.
  5. 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.

  1. 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 und Host-Header nebeneinander. Das Mittel ist, die Website unter einem einzigen kanonischen Host auszuliefern.
  2. consent_policy_hash_check ist aktiviert, und Ihre Dokumente haben sich geändert — das ist das gewollte Verhalten, der Besucher wird nach einer Änderung der Rechtstexte erneut gefragt.
  3. 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 Filter owc_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 /consent nie ein Veto.

Fehler ratelimit — 429

Die Grenzen sind bei öffentlichen Schreibvorgängen bewusst niedrig. Zwei Ursachen:

  1. 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_PROXY in wp-config.php.
  2. 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.

  1. Prüfen Sie, ob die Tabelle {prefix}owc_ledger existiert. Der Tab Audit ledger zeigt eine lesbare Meldung „noch nicht installiert“ statt eines weißen Bildschirms.
  2. Prüfen Sie die Schreibrechte des MySQL-Nutzers.
  3. Als letztes Mittel deaktivieren Sie ledger_enabled vorübergehend, um den Dienst wiederherzustellen — im Wissen, dass Sie in dieser Zeit den Nachweis verlieren.

Es laden weiterhin Tracker vor der Einwilligung

  1. Ist compliance_strict aktiviert? Ohne es werden nur die von WordPress eingereihten Skripte behandelt.
  2. 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.
  3. 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.
  4. Ist es ein per Set-Cookie-Header gesetztes Cookie? Keine clientseitige Blockade kann es aufhalten. Das muss an der Quelle behandelt werden, serverseitig.
  5. Stellen Sie blocker_unknown_script_policy auf block — 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

  1. Ist er aktiviert? Er ist standardmäßig deaktiviert.
  2. Funktioniert WP-Cron? Mit DISABLE_WP_CRON und ohne System-Cron startet der geplante Durchlauf nie. Starten Sie einen von Hand, um es zu prüfen.
  3. 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.
  4. 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_template zu liefern.

Die DSAR-Verifizierungs-E-Mail kommt nicht an

Das liegt fast immer an der Zustellbarkeit, nicht am Plugin.

  1. 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.
  2. Installieren Sie ein SMTP-Plugin. Die PHP-Funktion mail() wird von den meisten Empfangsservern abgelehnt.
  3. 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.
  4. Prüfen Sie, ob dsar_email eine 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_id steht 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 Server vendor-list.consensu.org über ausgehendes HTTPS erreichen kann.

Alle Besucher bekommen das konfigurierte Profil, trotz regionaler Erkennung

  1. Ist geo_enabled aktiviert? Es ist standardmäßig deaktiviert.
  2. Haben Sie Ihren Proxy deklariert? Ohne OWC_BEHIND_CLOUDFLARE, OWC_BEHIND_CLOUDFRONT oder OWC_GEO_TRUSTED_HEADERS in wp-config.php werden die Länder-Header ignoriert, weil sie fälschbar sind.
  3. Liegt die MaxMind-Datei bereit? Das Plugin lädt sie nicht herunter und bietet keinen Upload-Bildschirm.
  4. 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?