diff --git a/gdpr-content-blocker/assets/admin.js b/gdpr-content-blocker/assets/admin.js index eb5f6b7..213529e 100644 --- a/gdpr-content-blocker/assets/admin.js +++ b/gdpr-content-blocker/assets/admin.js @@ -28,7 +28,7 @@ function setExpanded( box, open ) { $( '.cb-service-grid', box ).toggle( open ); const $btn = $( '.cb-service-toggle', box ); - $btn.attr( 'aria-expanded', open ? 'true' : 'false' ).text( open ? '▾' : '▸' ); + $btn.attr( 'aria-expanded', open ? 'true' : 'false' ).text( open ? '−' : '+' ); } function bindToggle( box ) { $( '.cb-service-toggle', box ).on( 'click', function () { @@ -211,21 +211,33 @@ $ex.append( $( '' ).css( { fontSize: '11px', wordBreak: 'break-all' } ).text( sample ) ); $tr.append( $ex ); + // Does a ready-made template exist for this finding? + const preset = ( f.preset && cbAdmin.presets && cbAdmin.presets[ f.preset ] ) + ? cbAdmin.presets[ f.preset ] + : null; + // Status const $st = $( '' ); if ( f.covered ) { $st.append( $( '' ).css( { color: '#1a7f37', fontWeight: '600' } ).text( '✓ ' + ( i18n.covered || 'covered' ) ) ); + } else if ( preset ) { + $st.append( $( '' ).css( { color: '#2043B7', fontWeight: '600' } ).text( '★ ' + ( i18n.templateAvail || 'Vorlage verfügbar' ) ) ); } $tr.append( $st ); // Action: take over as a new service (only useful for uncovered third parties) const $act = $( '' ); if ( f.third_party && ! f.covered ) { + // Prefill from the matching preset (full data) if there is one, + // otherwise just seed host + pattern. + const data = preset + ? preset + : { name: f.host, match_pattern: f.suggested_pattern || f.host, third_country: true }; $( '' ) - .text( i18n.addService || 'Add as service' ) + .text( preset ? ( i18n.useTemplate || 'Vorlage übernehmen' ) : ( i18n.addService || 'Add as service' ) ) .on( 'click', function () { activateTab( 'services' ); - const $box = addServiceRow( { name: f.host, match_pattern: f.suggested_pattern || f.host, third_country: true } ); + const $box = addServiceRow( data ); if ( $box && $box.length ) { $box[ 0 ].scrollIntoView( { behavior: 'smooth', block: 'center' } ); $box.find( '.cb-input-id' ).trigger( 'focus' ); diff --git a/gdpr-content-blocker/assets/frontend.css b/gdpr-content-blocker/assets/frontend.css index e707e5f..68642ae 100644 --- a/gdpr-content-blocker/assets/frontend.css +++ b/gdpr-content-blocker/assets/frontend.css @@ -117,6 +117,22 @@ outline-offset: 2px; } +/* "Remember this service" checkbox under the button */ +.cb-blocker .cb-blocker__remember { + display: flex; + align-items: center; + justify-content: center; + gap: 6px; + margin-top: 0.8em; + font-size: 0.8rem; + opacity: 0.85; + cursor: pointer; +} +.cb-blocker .cb-blocker__remember input { + margin: 0; + cursor: pointer; +} + /* ── Revoke button ── */ .cb-revoke-btn { display: inline-block; diff --git a/gdpr-content-blocker/assets/frontend.js b/gdpr-content-blocker/assets/frontend.js index 8b4f23a..b7ef4bf 100644 --- a/gdpr-content-blocker/assets/frontend.js +++ b/gdpr-content-blocker/assets/frontend.js @@ -71,9 +71,17 @@ const serviceId = btn.dataset.cbId; if ( ! serviceId ) return; - grantConsent( serviceId ); - const wrapper = btn.closest( '.cb-blocker' ); + + // "Remember" checkbox (default checked): persist consent only when + // ticked; otherwise load this embed once without storing consent. + const remember = wrapper + ? wrapper.querySelector( '.cb-blocker__remember-cb' ) + : null; + if ( ! remember || remember.checked ) { + grantConsent( serviceId ); + } + if ( wrapper ) { loadContent( wrapper ); } diff --git a/gdpr-content-blocker/gdpr-content-blocker.php b/gdpr-content-blocker/gdpr-content-blocker.php index e211c51..e7cbf8e 100644 --- a/gdpr-content-blocker/gdpr-content-blocker.php +++ b/gdpr-content-blocker/gdpr-content-blocker.php @@ -38,6 +38,17 @@ require_once CB_DIR . 'includes/class-autodetect.php'; require_once CB_DIR . 'includes/class-license.php'; require_once CB_DIR . 'includes/class-updater.php'; +// Language policy: German source strings for any German locale (de_*), English +// for everything else. We map the plugin's locale accordingly and ship an +// en_US translation. Applies to admin and frontend (filter runs for both). +add_filter( 'plugin_locale', 'cb_plugin_locale', 10, 2 ); +function cb_plugin_locale( $locale, $domain ) { + if ( $domain !== 'gdpr-content-blocker' ) { + return $locale; + } + return str_starts_with( (string) $locale, 'de' ) ? 'de_DE' : 'en_US'; +} + add_action( 'plugins_loaded', 'cb_init' ); function cb_init(): void { diff --git a/gdpr-content-blocker/includes/class-renderer.php b/gdpr-content-blocker/includes/class-renderer.php index 637037a..a73164d 100644 --- a/gdpr-content-blocker/includes/class-renderer.php +++ b/gdpr-content-blocker/includes/class-renderer.php @@ -244,6 +244,10 @@ class CB_Renderer { $name ) . '' + . '' . '' . ''; } diff --git a/gdpr-content-blocker/includes/class-settings.php b/gdpr-content-blocker/includes/class-settings.php index 31224fa..9501d72 100644 --- a/gdpr-content-blocker/includes/class-settings.php +++ b/gdpr-content-blocker/includes/class-settings.php @@ -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 { ?>
- + -