24 Commits

Author SHA1 Message Date
s4luorth
839c364758 chore: alle versionsangaben einheitlich auf 1.7.0 + readme aktualisiert
- Plugin: Header-Version + CB_VERSION -> 1.7.0
- readme.txt: Stable tag 1.7.0, Features aktualisiert (skript-blockierung,
  consent-shortcode, textausrichtung, ganzseitiger scan, kein weissraum, ...),
  changelog-eintrag 1.7.0 + upgrade notice
- Backend package.json -> 1.7.0
- Doku-beispiele (README.md, SPICKZETTEL.md, license-backend/README.md) auf
  1.7.0 angeglichen

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 09:34:25 +02:00
s4luorth
54cebab1f5 feat: admin-endpunkt zum direkten download des release-ZIP (fuer n8n/CI)
GET /api/v1/releases/:product/download (X-Admin-Token) streamt das aktuelle
release-ZIP; optional ?version=1.2.3 fuer eine bestimmte version. Kein lizenz-
key/token noetig - gedacht fuer automatisierung (n8n, CI). Antwort:
application/zip + header X-Release-Version. Integrationstest ergaenzt.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-10 10:31:19 +02:00
s4luorth
fed29ab175 feat: "Lizenz upgraden" oeffnet vorausgefuellte mail (v1.5.4)
Button im Lizenz-tab (status "Plaetze belegt") oeffnet jetzt einen mailto-link
an info@lucas-orth.de, Betreff "Lizenzupgrade", body mit leeren feldern
"Lizenzkey:" und "Bestellmail:" zum ausfuellen (key NICHT vorausgefuellt).

+ i18n DE/EN. version 1.5.4.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-08 18:48:49 +02:00
s4luorth
3228965c60 fix: tabs ohne seiten-rahmen, scan aller unterseiten, button-radius bei hover (v1.5.3)
- Admin-tabs: kein rahmen/box/outline in irgendeinem zustand mehr - nur die
  untere unterstreichung markiert den aktiven tab (WP-default-borders ueber-
  schrieben, auch :focus/:active).
- Scan deckt jetzt ALLE veroeffentlichten seiten/beitraege (alle public post
  types) ab statt nur 4. Backend: limit 10 -> 60 URLs und PARALLELE abfrage
  (concurrency 12, 8s/seite), plugin-AJAX-timeout 45 -> 90s.
- Platzhalter-button: border-radius in hover/focus/active festgenagelt (3px) ->
  theme kann die ecken beim hover nicht mehr veraendern.

+ version 1.5.3. (Backend-redeploy noetig fuer den scan.)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-08 18:19:57 +02:00
s4luorth
ef84c43ded fix: textausrichtung-option + hover-fixes (link/badge) + remember-farbe (v1.5.2)
- Darstellung: neue option "Textausrichtung" (mittig/links/rechts). Setzt
  --cb-align (text-align) und --cb-justify (remember-zeile) inline.
- "Diesen Dienst kuenftig immer laden" nutzt jetzt die textfarbe (var(--cb-text),
  ohne dimming).
- Datenschutz-link: schriftgroesse/-gewicht/laufweite/transform/decoration in
  allen zustaenden festgenagelt -> keine theme-a:hover-aenderung mehr.
- Werbe-badge: dito -> wird beim hover nicht mehr riesig (theme-scaling/
  font-size gesperrt).

+ i18n DE/EN (138 strings). version 1.5.2.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-08 17:41:26 +02:00
s4luorth
6caece78f5 feat: plugin-icon einbinden (auto-erkennung in assets/) (v1.5.1)
CB_Updater::icons() liefert das plugin-icon fuer den Aktualisierungen-screen
und das "Versionsdetails"-popup. Es erkennt automatisch eine icon-datei in
assets/ (icon.svg|png|webp|jpg); ohne datei wird kein icon gesetzt.
Bild wird vom betreiber selbst hinzugefuegt (nicht im repo).

+ version 1.5.1.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-08 14:18:30 +02:00
s4luorth
2ef1d0769b feat: Werbe-Badge im content blocker (unten rechts) + abschaltbar nur mit unlimited (v1.5.0)
- Kleines Badge "GDPR Content Blocker" unten rechts im platzhalter, verlinkt
  auf die kaufseite (rel=nofollow sponsored). Server- und client-seitig.
- Wird IMMER angezeigt; abschaltbar via checkbox im Darstellung-tab
  ("Werbe-Badge ausblenden") - die checkbox ist aber nur mit aktiver
  Unlimited-lizenz nutzbar (sonst disabled) und greift am render-punkt nur,
  wenn is_unlimited() true ist.
- Dafuer speichert das plugin jetzt max_activations aus der backend-antwort
  (activate/validate/swap) und bietet is_unlimited().

+ i18n DE/EN (134 strings). version 1.5.0.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-08 14:08:08 +02:00
s4luorth
c796400492 feat: dienst-ID im Dienste-tab anzeigen + shortcode-hilfe fuer text/style (v1.4.9)
- Unter jedem dienstnamen wird jetzt die auto-erzeugte ID angezeigt
  (z. B. "ID: eigenes-matomo") - kopierbar, fuer den consent-shortcode.
  Bei neuen diensten live-vorschau aus dem namen (slugify, spiegelt
  sanitize_title); bei gespeicherten die stabile ID.
- Shortcode-tab: [content_blocker_consent] erklaert jetzt id/text/style einzeln
  mit beispielen (button vs. link).

+ i18n DE/EN ergaenzt (131 strings). version 1.4.9.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-08 14:00:22 +02:00
s4luorth
d0ced7b179 fix: drittland-hinweis ohne icon/farbe + kein trennstrich beim empfaenger (v1.4.8)
- Drittland-hinweis: kein warn-dreieck mehr und gleiche farbe/groesse wie der
  restliche text (eigene zeile statt inline). CSS ::before + amber entfernt.
- Der "komische strich" hinter dem empfaenger war mein " — "-trennzeichen vor
  dem hinweis (nicht aus den daten). Entfernt in PHP und JS; der hinweis steht
  jetzt sauber in der naechsten zeile.

+ version 1.4.8.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-08 13:51:56 +02:00
s4luorth
3c93027253 fix: YouTube-Elementor-widget zeigt video auch nach reload (v1.4.7)
Nach reload mit bereits erteilter einwilligung blieb das e-youtube-base-video
leer: ich kehrte frueh zurueck und ueberliess es Elementors eigenem render
(unzuverlaessig). Die anderen blocker haben einen server-platzhalter, den
loadPreConsented direkt laedt - das JS-gebaute YouTube-element nicht.

Jetzt verwalte ich das widget mit embed-URL komplett selbst:
- nicht eingewilligt -> platzhalter (eingeklappt, kein weissraum)
- eingewilligt (auch nach reload) -> iframe wird sofort direkt gebaut (16:9),
  unabhaengig von Elementor/iframe_api.
Reload-fallback nur noch ohne URL.

+ version 1.4.7.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-08 13:46:17 +02:00
s4luorth
6c034ed714 fix: YouTube-Elementor-widget laedt video wieder zuverlaessig (v1.4.6)
Der reload-ansatz aus 1.4.4 fuer e-youtube-base war unzuverlaessig (Elementor
rendert nach reload nicht sicher nativ). Zurueck zum direkten weg: aus dem
"source"-key habe ich die embed-URL -> ich baue das iframe bei einwilligung
selbst (unabhaengig von Elementor/iframe_api). Das iframe bekommt eine
responsive 16:9-aspect-ratio (data-cb-aspect) und laedt damit voll und in
originalproportionen, auch ohne definite parent-hoehe.

Reload-pfad bleibt nur fuer den fall ganz ohne URL (video_type-fallback).
Weissraum-einklappen unveraendert. node --check ok.

+ version 1.4.6.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-08 13:42:00 +02:00
s4luorth
ad7aad1b74 fix: weissraum auch bei inline-hoehe + oEmbed (::before) weg (v1.4.5)
Zwei faelle, die 1.4.4 nicht abdeckte:
- Eigenes iframe im HTML-widget liegt in <div style="height:800px"> - inline-
  hoehe, keine klasse. Mein klassenbasiertes einklappen verfehlte das.
- WordPress-oEmbed (testbeitrag, ohne Elementor) reserviert die hoehe ueber
  einen ::before-padding-trick, nicht ueber aspect-ratio.

Neu: statt inline-styles zu manipulieren wird per attribut [data-cb-collapsed]
+ EINER eingeschleusten CSS-regel alles neutralisiert (aspect-ratio, min/height,
::before/::after padding-hack, inline height via !important). Original-styles
bleiben unangetastet -> beim laden kommt die volle groesse exakt zurueck.
shouldCollapse() greift jetzt auch bei inline-hoehe und computed aspect-ratio,
aber nur bei "engen" wrappern (<=1 kind), damit keine ganze section schrumpft.
Logik isoliert getestet.

+ version 1.4.5.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-08 13:36:01 +02:00
s4luorth
6fa41fb3a6 fix: kein weissraum unter blocker + originalgroesse nach einwilligung (v1.4.4)
Der weissraum kam nicht von meinem platzhalter, sondern vom seitenverhaeltnis-
container (z. B. Elementor .e-youtube-base mit 16:9, oder wp-block-embed
aspect-ratio) - das reserviert die hoehe per CSS, unabhaengig vom inhalt.

- collapseAncestors(): bekannte aspect-ratio/video-wrapper um einen platzhalter
  werden eingeklappt (aspect-ratio/min-height/height auto !important), solange
  der blocker steht -> kein leerraum darunter. Laeuft fuer server-platzhalter
  (autodetect) und JS-gebaute (Elementor-widgets).
- restoreCollapsed(): bei einwilligung wird die reservierung wieder entfernt,
  sodass das embed in originalgroesse laedt.
- Elementor JS-widgets (e-youtube-base etc.) nutzen jetzt durchgaengig den
  reload-pfad bei einwilligung -> Elementor rendert das video nativ in voller
  originalgroesse statt eines geratenen iframes.

+ version 1.4.4 (assets cache-busting).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-08 13:30:59 +02:00
s4luorth
494518e98e fix: kein s.w.org-emoji-request + kein weissraum unter dem blocker (v1.4.3)
1) Das Warn-Emoji "⚠" im platzhalter-text loeste WordPress' wp-emoji aus, das
   die grafik von s.w.org nachlud (drittanbieter-request). Emoji aus den texten
   entfernt; das warn-dreieck wird jetzt rein per CSS gezeichnet (kein netzwerk).
   Hinweis: s.w.org ist der WP-emoji-CDN, NICHT Google.
2) Der platzhalter reservierte die hoehe des eingebetteten elements -> bei
   kuerzerem inhalt entstand weissraum darunter. Hoehen-reservierung entfernt
   (PHP min-height-style, JS minHeight, CSS min-height:180px) - der content
   blocker ist jetzt exakt so hoch wie sein eigener inhalt. Die original-masse
   bleiben als data-attribute fuer das iframe nach einwilligung erhalten.
3) Redundante, partielle de_DE-.po/.mo (mit altem emoji) entfernt - deutsche
   locales nutzen direkt die deutschen quell-strings.

+ version 1.4.3 (assets cache-busting).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-08 13:23:34 +02:00
s4luorth
176ded0228 fix: Elementor e-youtube-base widget erkennen (v1.4.2)
Das YouTube-video auf der startseite ist kein .elementor-widget-video, sondern
Elementors neueres element <div class="e-youtube-base" data-e-type="e-youtube"
data-settings='{"source":"https://www.youtube.com/watch?v=..."}'>. Daher griff
weder server-autodetect (kein iframe) noch mein client-handler -> leere box.

- selektor erweitert um .e-youtube-base/.e-vimeo-base und
  [data-e-type^="e-youtube"|"e-vimeo"].
- URL-extraktion liest jetzt auch den key "source" (und "url").
An der echten data-settings der live-seite verifiziert.

+ version 1.4.2 (assets cache-busting).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-08 13:15:53 +02:00
s4luorth
1ce9f8121b fix: leerer elementor-video-platzhalter wenn URL nicht auslesbar (v1.4.1)
Wenn ein Elementor-video per JS gebaut wird und im DOM weder URL noch
Thumbnail steht (nur {"video_type":"youtube"}), konnte mein handler keinen
platzhalter bauen -> Elementor baut nichts (API blockiert) -> leere box.

Fallback: dienst ueber den video_type erkennen und trotzdem einen
einwilligungs-platzhalter zeigen. Da keine embed-URL bekannt ist, gibt dessen
button die einwilligung und laedt die seite neu - danach rendert Elementor das
video normal (scripts sind dann freigegeben). "Einmal laden" entfaellt dort.

+ version 1.4.1 (assets cache-busting fuer die JS-aenderung).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-08 12:58:28 +02:00
s4luorth
2361228c14 chore: CB_VERSION auf 1.4.0 (assets cache-busting) - war noch 1.3.0
Header stand bereits auf 1.4.0, CB_VERSION aber auf 1.3.0. Dadurch wurden
geaenderte frontend.js/admin.js mit unveraendertem ?ver=1.3.0 ausgeliefert
und vom browser/cache als alte version geladen. Jetzt konsistent 1.4.0, damit
die JS-fixes (script-guard, elementor-youtube-erkennung) tatsaechlich greifen.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-08 12:52:56 +02:00
s4luorth
ca945d2d80 feat: third-party-scripts blockieren (server + client-guard)
Loest die YouTube/Vimeo-API-Luecke: viele dienste laden ueber <script>
(z. B. youtube.com/iframe_api, www-widgetapi.js, analytics) statt iframes -
oft per JavaScript nachgeladen, daher fuer den scanner unsichtbar.

- Pro dienst aktivierbar ueber das (umbenannte) feld "Zugehoerige Skripte
  blockieren (z. B. YouTube-/Vimeo-API)" = das vorhandene loads_script-flag.
  Presets (YouTube, Vimeo, Maps) haben es bereits an.
- Server-seitig: passende <script src> werden zu type="text/plain"
  (src -> data-cb-src) neutralisiert, laden also nicht.
- Client-seitig: winziger guard ganz frueh im <head> patcht
  appendChild/insertBefore/replaceChild und neutralisiert dynamisch
  injizierte scripts VOR dem einfuegen -> kein request. Faengt damit auch
  die per JS nachgeladene iframe_api ab.
- Einwilligung (per-dienst-consent, z. B. ueber den video-platzhalter)
  schaltet die scripts via cbActivateScripts frei und laedt sie nach.
- Neuer shortcode [content_blocker_consent id="…"] als einwilligungs-button
  fuer reine skript-dienste ohne sichtbaren platzhalter.
- guard-logik mit DOM-mock getestet (block + reinject), server-regex
  isoliert geprueft. i18n DE/EN ergaenzt (127 strings).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-08 08:24:33 +02:00
s4luorth
b6df4c64af revert: lokales Google-Fonts-Hosting entfernt + scan zeigt nur hinweis
- Feature "Schriften lokal hosten" komplett zurueckgebaut (class-fonts.php,
  tab, ajax-endpunkte, output-buffer, admin-js-handler, optionen).
- Scan: wird fonts.googleapis.com / fonts.gstatic.com erkannt, steht in der
  Aktion-spalte jetzt der nicht-klickbare hinweis "Schriftart fuer
  DSGVO-konformen Betrieb lokal hosten." statt eines buttons.
- i18n entsprechend bereinigt (123 strings).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-08 07:39:34 +02:00
s4luorth
377c64f8d0 feat: lokales Google-Fonts-Hosting + "Lizenz upgraden"-button (v1.3.0)
- Lizenz-Tab: bei vollen Plaetzen erscheint ein "Lizenz upgraden"-Button
  (https://lucas-orth.de/wp-plugins/gdpr-content-blocker/) zusaetzlich zur
  domain-freigabe.
- Neues Feature "Schriften": Google Fonts lokal hosten (button-modell).
  Admin klickt "Jetzt herunterladen & einbinden" -> plugin scannt die seiten,
  laedt googleapis-CSS + gstatic-schriftdateien einmalig in den uploads-ordner,
  schreibt die pfade lokal um und tauscht sie per output-buffer im quelltext.
  Abgedeckt: <link>, inline-@import/url() UND @import/url() in gleicher-origin
  externen CSS-dateien (mit absolutierung der restlichen relativen pfade).
  preconnect/dns-prefetch zu google-font-hosts werden entfernt (kein IP-leak).
  Toggle zum aus/einschalten + "Lokale Schriften loeschen".
- i18n-pipeline robuster: build-en-mo.py nutzt jetzt translations-en.json
  (lookup per quell-string, reihenfolge-unabhaengig) und bricht mit liste ab,
  falls eine uebersetzung fehlt. Alle neuen strings DE/EN ergaenzt (139).
- version 1.3.0 (header + CB_VERSION).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-08 07:16:19 +02:00
s4luorth
de4f16fefa fix: scanner ignoriert metadaten-links (gmpg.org rel=profile); version 1.2.0
- Nur ladende <link rel=...> (stylesheet/preload/icon/...) werden gezaehlt;
  rel=profile/canonical/pingback etc. (z.B. gmpg.org) sind keine Requests mehr.
- Plugin-Version + Header auf 1.2.0 (passend zu readme), Changelog-Eintrag.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 16:57:09 +02:00
s4luorth
576ad1f74a fix: pfeil groesser, tab ohne fokus-kasten, version 1.1.0 (cache-bust)
- Aufklapp-Pfeil deutlich groesser (26px).
- Tabs: kein Fokus-Kasten mehr, nur untere Linie markiert den aktiven Tab.
- CB_VERSION + Header auf 1.1.0 -> bricht gecachte alte admin.js/frontend.js
  (Ursache, dass ein Dienst auf einer Seite nicht aufklappbar war).
- Aufklappen via Event-Delegation (robust gegen Load-Order/dynamische Zeilen).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 15:31:28 +02:00
s4luorth
3c37bf63cc feat: UI-feinschliff, scan-vorlagenerkennung, einmal-laden, DE/EN-sprachen
UI:
- Ein-/Ausklappen jetzt mit grossem +/- Icon statt kleinem Pfeil.
- "Entfernen" ist ein Papierkorb-Symbol (dashicon).
- Aktiver Tab klar gekennzeichnet (Akzent-Unterstrich + Farbe).
- 20px Abstand zwischen Tabs und Inhalt.

Funktionen:
- Scan erkennt Anbieter, fuer die es eine Vorlage gibt ("Vorlage verfuegbar"),
  und "Vorlage uebernehmen" fuellt die komplette Vorlage statt nur Host/Pattern.
- Platzhalter: Checkbox "Diesen Dienst kuenftig immer laden" (Standard AN).
  Abgewaehlt -> Inhalt wird nur einmal geladen, keine dauerhafte Einwilligung.

i18n:
- Sprachumschaltung: Deutsch fuer alle de_* Locales, Englisch fuer alle anderen
  (plugin_locale-Filter). Vollstaendige englische Uebersetzung (126 Strings,
  inkl. Vorlagentexte/Empfaenger) als gdpr-content-blocker-en_US.po/.mo.
- Helper-Skripte (extract/build) in hilfsdaten/.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 15:06:16 +02:00
s4luorth
ecb5e1bd22 chore: monorepo - plugin, backend und hilfsdaten in einem repo
- Eltern-Ordner ist jetzt EIN Git-Repo (statt getrennter Repos).
- root .gitignore haelt Secrets (.env), node_modules, DB und Build-Artefakte raus.
- release.ps1: manueller Release (ZIP bauen + ans Backend laden).
- root README mit Struktur und Release-Ablauf.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 14:41:38 +02:00