tags. */ public static function script_services(): array { $out = []; foreach ( CB_Settings::get_services() as $svc ) { if ( empty( $svc['match_pattern'] ) || empty( $svc['loads_script'] ) || ! ( $svc['enabled'] ?? true ) ) { continue; } $out[] = [ 'id' => $svc['id'], 'match' => $svc['match_pattern'] ]; } return $out; } /** * Inline guard printed very early in
. It blocks third-party scripts * (both already in the DOM and dynamically injected) until the matching * service has consent, by neutralising the \n"; } public static function enqueue_assets(): void { wp_enqueue_style( 'cb-frontend', CB_URL . 'assets/frontend.css', [], CB_VERSION ); $style = CB_Settings::get_style(); // Build one inline block: CSS variables first, the user's Custom-CSS LAST // so it always overrides. Emitted as a single wp_add_inline_style call. $inline = sprintf( ':root{--cb-text:%s;--cb-bg:%s;--cb-btn-bg:%s;--cb-btn-text:%s;--cb-btn-hover-bg:%s;--cb-btn-hover-text:%s;}', esc_attr( $style['text_color'] ), esc_attr( $style['bg_color'] ), esc_attr( $style['button_bg'] ), esc_attr( $style['button_text'] ), esc_attr( $style['button_hover_bg'] ), esc_attr( $style['button_hover_text'] ) ); if ( trim( (string) $style['custom_css'] ) !== '' ) { $inline .= "\n/* gdpr-content-blocker custom css */\n" . $style['custom_css']; } wp_add_inline_style( 'cb-frontend', $inline ); wp_enqueue_script( 'cb-frontend', CB_URL . 'assets/frontend.js', [], CB_VERSION, true ); // Service data + i18n for client-side detection (JS-injected iframes such // as Elementor video widgets, sliders, …). wp_localize_script( 'cb-frontend', 'cbConfig', [ 'services' => self::services_for_js(), 'showBadge' => self::show_badge(), 'i18n' => [ 'recipient' => __( 'Empfänger:', 'gdpr-content-blocker' ), 'purpose' => __( 'Zweck:', 'gdpr-content-blocker' ), 'thirdCountry' => __( 'Datenübermittlung in ein Drittland außerhalb der EU/des EWR', 'gdpr-content-blocker' ), 'privacy' => __( 'Datenschutzerklärung des Anbieters', 'gdpr-content-blocker' ), 'load' => __( '%s jetzt laden', 'gdpr-content-blocker' ), 'remember' => __( 'Diesen Dienst künftig immer laden', 'gdpr-content-blocker' ), 'defaultText' => __( 'Um diesen Inhalt von %s zu laden, ist Ihre Einwilligung erforderlich. Dabei werden personenbezogene Daten (z. B. Ihre IP-Adresse) an den Anbieter übertragen.', 'gdpr-content-blocker' ), ], ] ); } /** Minimal, public service data for client-side detection. */ private static function services_for_js(): array { $out = []; foreach ( CB_Settings::get_services() as $svc ) { if ( empty( $svc['match_pattern'] ) || ! ( $svc['enabled'] ?? true ) ) { continue; } $out[] = [ 'id' => $svc['id'], 'name' => $svc['name'], 'match' => $svc['match_pattern'], 'recipient' => $svc['recipient'], 'third_country' => ! empty( $svc['third_country'] ), 'purpose' => $svc['purpose'], 'privacy_url' => $svc['privacy_url'] ?? '', 'placeholder' => $svc['placeholder_text'] ?? '', ]; } return $out; } /** * Shortcode: [content_blocker id="google-maps"][/content_blocker] */ public static function shortcode( array $atts, ?string $content = null ): string { $atts = shortcode_atts( [ 'id' => '' ], $atts, 'content_blocker' ); $id = sanitize_key( $atts['id'] ); if ( $id === '' ) { return ''; } $svc = CB_Settings::get_service( $id ); if ( $svc === null ) { return ''; } // Disabled blocker → let the embedded content load normally (no blocking). if ( ! ( $svc['enabled'] ?? true ) ) { return $content ?? ''; } // Extract src + dimensions from the inner iframe $src = ''; $dims = []; if ( $content !== null && $content !== '' ) { $attrs = self::extract_iframe_attrs( $content ); $src = $attrs['src']; $dims = [ 'width' => $attrs['width'], 'height' => $attrs['height'] ]; } return self::render_placeholder( $svc, $src, $dims ); } /** * Shortcode: [content_blocker_revoke] * Renders, by default, a visible text link (not a button) so it doesn't get * confused with a cookie banner's revoke control. Attributes: * text="…" custom link label * style="link|button" default "link" * note="yes|no" show the clarifying hint (default "yes") */ public static function revoke_shortcode( array|string $atts = [] ): string { $atts = shortcode_atts( [ 'text' => __( 'Einwilligung für externe Inhalte widerrufen', 'gdpr-content-blocker' ), 'style' => 'link', 'note' => 'yes', ], $atts, 'content_blocker_revoke' ); $class = $atts['style'] === 'button' ? 'cb-revoke-btn' : 'cb-revoke-link'; $out = '' . esc_html( $atts['text'] ) . ''; if ( $atts['note'] === 'yes' ) { $out .= '' . esc_html__( 'Betrifft nur die Freigabe externer Einbettungen (z. B. Karten, Videos). Cookie-Einstellungen werden separat verwaltet.', 'gdpr-content-blocker' ) . ''; } return $out; } /** * Shortcode: [content_blocker_consent id="youtube" text="…" style="button|link"] * A consent control for services that only block scripts (no visible embed * to click). Grants consent for the given service id and reloads so the * blocked scripts/embeds load. */ public static function consent_shortcode( array|string $atts = [] ): string { $atts = shortcode_atts( [ 'id' => '', 'text' => __( 'Externe Inhalte aktivieren', 'gdpr-content-blocker' ), 'style' => 'button', ], $atts, 'content_blocker_consent' ); $id = sanitize_key( $atts['id'] ); if ( $id === '' ) { return ''; } $class = $atts['style'] === 'link' ? 'cb-revoke-link' : 'cb-revoke-btn'; return '' . esc_html( $atts['text'] ) . ''; } /** * Shortcode: [content_blocker_services] * Lists every configured third-party service with the Art. 13 details * (provider, recipient, third-country note, purpose, privacy link). * Meant for embedding in the privacy policy. */ public static function services_shortcode(): string { $services = CB_Settings::get_services(); if ( empty( $services ) ) { return ''; } $out = '' . $info_text . '
' . '' . '' . esc_html__( 'Empfänger:', 'gdpr-content-blocker' ) . ' ' . $recipient . $third_note . '
' . '' . '' . esc_html__( 'Zweck:', 'gdpr-content-blocker' ) . ' ' . $purpose . '
' . ( $privacy_link !== '' ? '' . $privacy_link . '
' : '' ) . '' . '' . '