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>
This commit is contained in:
@@ -244,6 +244,10 @@ class CB_Renderer {
|
||||
$name
|
||||
)
|
||||
. '</button>'
|
||||
. '<label class="cb-blocker__remember">'
|
||||
. '<input type="checkbox" class="cb-blocker__remember-cb" checked> '
|
||||
. esc_html__( 'Diesen Dienst künftig immer laden', 'gdpr-content-blocker' )
|
||||
. '</label>'
|
||||
. '</div>'
|
||||
. '</div>';
|
||||
}
|
||||
|
||||
@@ -137,6 +137,7 @@ class CB_Settings {
|
||||
return;
|
||||
}
|
||||
wp_enqueue_style( 'wp-color-picker' );
|
||||
wp_enqueue_style( 'dashicons' );
|
||||
wp_enqueue_script(
|
||||
'cb-admin',
|
||||
CB_URL . 'assets/admin.js',
|
||||
@@ -164,6 +165,8 @@ class CB_Settings {
|
||||
'thirdParty' => __( 'Drittanbieter', 'gdpr-content-blocker' ),
|
||||
'firstParty' => __( 'eigene Domain', 'gdpr-content-blocker' ),
|
||||
'addService' => __( 'Als Dienst übernehmen', 'gdpr-content-blocker' ),
|
||||
'useTemplate' => __( 'Vorlage übernehmen', 'gdpr-content-blocker' ),
|
||||
'templateAvail' => __( 'Vorlage verfügbar', 'gdpr-content-blocker' ),
|
||||
'scannedPages'=> __( 'Gescannte Seiten:', 'gdpr-content-blocker' ),
|
||||
'foundOn' => __( 'Gefunden auf', 'gdpr-content-blocker' ),
|
||||
],
|
||||
@@ -180,7 +183,7 @@ class CB_Settings {
|
||||
'id' => 'google-maps',
|
||||
'name' => 'Google Maps',
|
||||
'match_pattern' => 'google.com/maps',
|
||||
'recipient' => 'Google Ireland Ltd., Irland / Google LLC, USA',
|
||||
'recipient' => __( 'Google Ireland Ltd., Irland / Google LLC, USA', 'gdpr-content-blocker' ),
|
||||
'third_country' => true,
|
||||
'sets_cookie' => true,
|
||||
'loads_script' => true,
|
||||
@@ -191,7 +194,7 @@ class CB_Settings {
|
||||
'id' => 'youtube',
|
||||
'name' => 'YouTube',
|
||||
'match_pattern' => 'youtube',
|
||||
'recipient' => 'Google Ireland Ltd., Irland / Google LLC, USA',
|
||||
'recipient' => __( 'Google Ireland Ltd., Irland / Google LLC, USA', 'gdpr-content-blocker' ),
|
||||
'third_country' => true,
|
||||
'sets_cookie' => true,
|
||||
'loads_script' => true,
|
||||
@@ -202,7 +205,7 @@ class CB_Settings {
|
||||
'id' => 'openstreetmap',
|
||||
'name' => 'OpenStreetMap',
|
||||
'match_pattern' => 'openstreetmap.org',
|
||||
'recipient' => 'OpenStreetMap Foundation, Großbritannien',
|
||||
'recipient' => __( 'OpenStreetMap Foundation, Großbritannien', 'gdpr-content-blocker' ),
|
||||
'third_country' => true,
|
||||
'sets_cookie' => false,
|
||||
'loads_script' => true,
|
||||
@@ -213,7 +216,7 @@ class CB_Settings {
|
||||
'id' => 'vimeo',
|
||||
'name' => 'Vimeo',
|
||||
'match_pattern' => 'player.vimeo.com',
|
||||
'recipient' => 'Vimeo LLC, USA',
|
||||
'recipient' => __( 'Vimeo LLC, USA', 'gdpr-content-blocker' ),
|
||||
'third_country' => true,
|
||||
'sets_cookie' => true,
|
||||
'loads_script' => true,
|
||||
@@ -406,6 +409,57 @@ class CB_Settings {
|
||||
.cb-admin-wrap .cb-switch input:checked + .cb-switch__slider::before {
|
||||
transform: translateX(18px);
|
||||
}
|
||||
/* expand/collapse +/- icon */
|
||||
.cb-admin-wrap .cb-service-toggle {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
font-size: 22px;
|
||||
line-height: 1;
|
||||
font-weight: 400;
|
||||
color: #2043B7;
|
||||
background: #f0f3fc;
|
||||
border: 1px solid #c7d2f5;
|
||||
border-radius: 6px;
|
||||
padding: 0;
|
||||
}
|
||||
.cb-admin-wrap .cb-service-toggle:hover {
|
||||
background: #e3e9fb;
|
||||
}
|
||||
/* trash remove button */
|
||||
.cb-admin-wrap .cb-remove-service {
|
||||
background: none;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
padding: 4px;
|
||||
color: #888;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
}
|
||||
.cb-admin-wrap .cb-remove-service:hover {
|
||||
color: #b32d2e;
|
||||
}
|
||||
.cb-admin-wrap .cb-remove-service .dashicons {
|
||||
font-size: 20px;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
}
|
||||
/* active tab indicator */
|
||||
.cb-admin-wrap .nav-tab-wrapper {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.cb-admin-wrap .nav-tab-active,
|
||||
.cb-admin-wrap .nav-tab-active:focus,
|
||||
.cb-admin-wrap .nav-tab-active:hover {
|
||||
background: #fff;
|
||||
color: #2043B7;
|
||||
border-bottom: 3px solid #2043B7;
|
||||
font-weight: 600;
|
||||
margin-bottom: -1px;
|
||||
}
|
||||
/* 20px breathing room between tabs and content */
|
||||
.cb-admin-wrap .cb-tab-content {
|
||||
padding-top: 20px;
|
||||
}
|
||||
.cb-admin-wrap .cb-field label {
|
||||
display: block;
|
||||
font-weight: 600;
|
||||
@@ -449,7 +503,7 @@ class CB_Settings {
|
||||
?>
|
||||
<div class="cb-service-box" data-cb-index="<?php echo $idx; ?>">
|
||||
<div class="cb-service-head">
|
||||
<button type="button" class="cb-service-toggle" aria-expanded="false" title="<?php esc_attr_e( 'Details anzeigen/ausblenden', 'gdpr-content-blocker' ); ?>">▸</button>
|
||||
<button type="button" class="cb-service-toggle" aria-expanded="false" aria-label="<?php esc_attr_e( 'Details anzeigen/ausblenden', 'gdpr-content-blocker' ); ?>">+</button>
|
||||
<span class="cb-service-title"><?php echo esc_html( $headname ); ?></span>
|
||||
|
||||
<label class="cb-switch" title="<?php esc_attr_e( 'Blocker aktiv/inaktiv', 'gdpr-content-blocker' ); ?>">
|
||||
@@ -458,8 +512,8 @@ class CB_Settings {
|
||||
<span class="cb-switch__slider"></span>
|
||||
</label>
|
||||
|
||||
<button type="button" class="button-link-delete cb-remove-service">
|
||||
<?php esc_html_e( 'Entfernen', 'gdpr-content-blocker' ); ?>
|
||||
<button type="button" class="cb-remove-service" aria-label="<?php esc_attr_e( 'Dienst entfernen', 'gdpr-content-blocker' ); ?>" title="<?php esc_attr_e( 'Dienst entfernen', 'gdpr-content-blocker' ); ?>">
|
||||
<span class="dashicons dashicons-trash"></span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="cb-service-grid" style="display:none;">
|
||||
@@ -710,11 +764,14 @@ class CB_Settings {
|
||||
wp_send_json_error( [ 'message' => $msg ] );
|
||||
}
|
||||
|
||||
// Annotate each finding: is it already covered by a configured service?
|
||||
// Annotate each finding: already covered by a configured service? And is
|
||||
// there a ready-made template (preset) for it?
|
||||
$services = self::get_services();
|
||||
$presets = self::get_presets();
|
||||
$findings = is_array( $data['findings'] ?? null ) ? $data['findings'] : [];
|
||||
foreach ( $findings as &$f ) {
|
||||
$f['covered'] = self::is_covered( $f, $services );
|
||||
$f['preset'] = self::match_preset( $f, $presets ); // preset key or ''
|
||||
}
|
||||
unset( $f );
|
||||
|
||||
@@ -724,12 +781,17 @@ class CB_Settings {
|
||||
] );
|
||||
}
|
||||
|
||||
/** True if any configured service's match_pattern matches this finding. */
|
||||
private static function is_covered( array $finding, array $services ): bool {
|
||||
$haystacks = array_merge(
|
||||
/** Collect host + sample URLs of a finding for substring matching. */
|
||||
private static function finding_haystacks( array $finding ): array {
|
||||
return array_merge(
|
||||
[ (string) ( $finding['host'] ?? '' ) ],
|
||||
array_map( 'strval', (array) ( $finding['sample_urls'] ?? [] ) )
|
||||
);
|
||||
}
|
||||
|
||||
/** True if any configured service's match_pattern matches this finding. */
|
||||
private static function is_covered( array $finding, array $services ): bool {
|
||||
$haystacks = self::finding_haystacks( $finding );
|
||||
foreach ( $services as $svc ) {
|
||||
$pattern = $svc['match_pattern'] ?? '';
|
||||
if ( $pattern === '' ) {
|
||||
@@ -743,4 +805,21 @@ class CB_Settings {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Return the key of a preset whose match_pattern fits this finding, or ''. */
|
||||
private static function match_preset( array $finding, array $presets ): string {
|
||||
$haystacks = self::finding_haystacks( $finding );
|
||||
foreach ( $presets as $key => $preset ) {
|
||||
$pattern = $preset['match_pattern'] ?? '';
|
||||
if ( $pattern === '' ) {
|
||||
continue;
|
||||
}
|
||||
foreach ( $haystacks as $h ) {
|
||||
if ( $h !== '' && str_contains( $h, $pattern ) ) {
|
||||
return (string) $key;
|
||||
}
|
||||
}
|
||||
}
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user