'English', 'fi' => 'Suomi', 'sv' => 'Svenska', 'da' => 'Dansk', 'no' => 'Norsk', 'de' => 'Deutsch', 'nl' => 'Nederlands', 'fr' => 'Français', 'es' => 'Español', 'it' => 'Italiano', 'pl' => 'Polski', ); } /** * Mika kielitiedosto ladataan. 'auto' seuraa sivuston kielta pyynto * kerrallaan, joten Polylang/WPML-sivustolla jokainen kieliversio saa * oman bannerinsa. Tuntematon kieli putoaa englantiin. */ public static function banner_lang( $s ) { $lang = ( isset( $s['lang'] ) && 'auto' !== $s['lang'] ) ? $s['lang'] : substr( get_locale(), 0, 2 ); $lang = strtolower( $lang ); if ( 'nb' === $lang || 'nn' === $lang ) { $lang = 'no'; } return array_key_exists( $lang, self::languages() ) ? $lang : 'en'; } public static function defaults() { return array( 'lang' => 'auto', 'categories' => array( 'analytics', 'marketing', 'preferences' ), 'policy' => '', 'remember' => 365, 'gcm' => true, 'button' => true, 'log' => true, 'gating' => true, 'gate_gtm' => false, // Advanced Consent Mode: Google-tagit latautuvat "denied"-tilassa ja // lahettavat evasteettomia pingeja, joista Google mallintaa puuttuvat // konversiot. Oletus pois: perustilassa Googlelle ei lahde mitaan // ennen suostumusta. Performance-toimistot kytkevat taman paalle. 'gcm_advanced' => false, // Upotukset (YouTube, Maps, some) pidetaan paikanpitajan takana // kunnes markkinointi on sallittu. youtube-nocookie ei riita. 'embeds' => true, // Lokin sailytysaika paivina. 0 = ikuisesti. Valvoja odottaa todistetta // prosessoinnin ajan + vanhentumisaika (3-5 v), joten oletus ei poista. 'log_days' => 0, // Ilme: tyhja = bannerin oma oletus. Kirjasinta ei aseteta koskaan, // se peritaan sivustolta. 'theme' => array( 'position' => 'bar', 'bg' => '', 'fg' => '', 'accent' => '', 'radius' => '', // Napit erikseen (7.9.2026). Tyhja = seuraa bannerin taustaa/tekstia. 'btn_bg' => '', 'btn_line' => '', 'btn_fg' => '', ), ); } /** * CSS-muuttujat bannerille asetuksista. Palauttaa tyhjan jos mitaan ei * ole asetettu, jolloin sivulle ei tulosteta yhtaan ylimaaraista tavua. */ public static function theme_css( $s ) { $t = isset( $s['theme'] ) && is_array( $s['theme'] ) ? $s['theme'] : array(); $v = array(); if ( ! empty( $t['bg'] ) ) { $v[] = '--nc-bg:' . $t['bg']; } if ( ! empty( $t['fg'] ) ) { $v[] = '--nc-fg:' . $t['fg']; $v[] = '--nc-line:' . $t['fg'] . '33'; // 20 % lapinakyva viiva samasta savysta } if ( ! empty( $t['accent'] ) ) { $v[] = '--nc-accent:' . $t['accent']; } if ( '' !== (string) ( $t['radius'] ?? '' ) ) { $v[] = '--nc-radius:' . (int) $t['radius'] . 'px'; } if ( 'card' === ( $t['position'] ?? 'bar' ) ) { $v[] = '--nc-inset:auto auto 16px 16px'; $v[] = '--nc-w:26rem'; } // Nappien omat varit: ei muuttujia ytimessa (0 tavua banneriin) vaan // suora saanto .nc-b:lle. Sama kaikille kolmelle napille. $b = array(); if ( ! empty( $t['btn_bg'] ) ) { $b[] = 'background:' . $t['btn_bg']; } if ( ! empty( $t['btn_line'] ) ) { $b[] = 'border-color:' . $t['btn_line']; } if ( ! empty( $t['btn_fg'] ) ) { $b[] = 'color:' . $t['btn_fg']; } $css = $v ? '.nc,.nc-o{' . implode( ';', $v ) . '}' : ''; // .nc .nc-b, ei .nc-b: banneri lisaa oman tyylinsa vasta latauksen // jalkeen, ja samalla tarkkuudella myohempi voittaisi (7.9.2026). if ( $b ) { $css .= '.nc .nc-b{' . implode( ';', $b ) . '}'; } return $css; } public static function get() { $saved = get_option( self::OPTION, array() ); if ( ! is_array( $saved ) ) { $saved = array(); } $s = array_merge( self::defaults(), $saved ); if ( empty( $s['policy'] ) ) { // Tietosuojasivu: WordPressin oma asetus, jos sellainen on valittu. $policy_id = (int) get_option( 'wp_page_for_privacy_policy' ); if ( $policy_id ) { $s['policy'] = get_permalink( $policy_id ); } } return $s; } public static function sanitize( $in ) { $d = self::defaults(); $out = array(); $lang = isset( $in['lang'] ) ? sanitize_key( $in['lang'] ) : 'auto'; $out['lang'] = ( 'auto' === $lang || array_key_exists( $lang, self::languages() ) ) ? $lang : 'auto'; $cats = isset( $in['categories'] ) && is_array( $in['categories'] ) ? $in['categories'] : array(); $out['categories'] = array_values( array_intersect( array( 'analytics', 'marketing', 'preferences' ), $cats ) ); $out['policy'] = isset( $in['policy'] ) ? esc_url_raw( trim( $in['policy'] ) ) : ''; $out['remember'] = max( 30, min( 730, (int) ( $in['remember'] ?? $d['remember'] ) ) ); $out['gcm'] = ! empty( $in['gcm'] ); $out['button'] = ! empty( $in['button'] ); $out['log'] = ! empty( $in['log'] ); $out['gating'] = ! empty( $in['gating'] ); $out['gate_gtm'] = ! empty( $in['gate_gtm'] ); $out['gcm_advanced'] = ! empty( $in['gcm_advanced'] ); $out['embeds'] = ! empty( $in['embeds'] ); $out['log_days'] = max( 0, min( 3650, (int) ( $in['log_days'] ?? 0 ) ) ); // Ilme. Varit vain #rrggbb-muodossa; kaikki muu hylataan tyhjaksi, // koska arvo tulostetaan CSS:aan sellaisenaan. $t = isset( $in['theme'] ) && is_array( $in['theme'] ) ? $in['theme'] : array(); $hex = function ( $v ) { $v = trim( (string) $v ); return preg_match( '/^#[0-9a-fA-F]{6}$/', $v ) ? strtolower( $v ) : ''; }; $out['theme'] = array( 'position' => ( 'card' === ( $t['position'] ?? '' ) ) ? 'card' : 'bar', 'bg' => $hex( $t['bg'] ?? '' ), 'fg' => $hex( $t['fg'] ?? '' ), 'accent' => $hex( $t['accent'] ?? '' ), 'radius' => ( '' === trim( (string) ( $t['radius'] ?? '' ) ) ) ? '' : (string) max( 0, min( 32, (int) $t['radius'] ) ), 'btn_bg' => $hex( $t['btn_bg'] ?? '' ), 'btn_line' => $hex( $t['btn_line'] ?? '' ), 'btn_fg' => $hex( $t['btn_fg'] ?? '' ), ); return $out; } }