self::get_page_url(), 'text' => __( 'Set AdSimple ID', 'adsimple-cookie-manager-for-wp' ), ] ); } } /** * @since 2.0.6 */ public static function save_adsimple_id_after_install() { $field = static::get_fields( 'adsimple_id' ); if ( ! isset( $_REQUEST[ $field['name'] ] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- nonce verified in save_fields() return; } // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- nonce verified in save_fields() $id = isset( $_REQUEST[ $field['name'] ] ) ? sanitize_text_field( wp_unslash( $_REQUEST[ $field['name'] ] ) ) : ''; $result = static::update_adsimple_id( $id ); if ( is_wp_error( $result ) ) { $error_data = $result->get_error_data( 'invalid_adsimple_id' ); AS_CM_Services_Notice::add_notice( 'status-save-adsimple-id', $result->get_error_message(), [ AS_CM_Manager::$action ], isset( $error_data['link'] ) ? $error_data['link'] : false ); return; } AS_CM_Services_Notice::add_notice( 'status-save-adsimple-id', __( "We successfully saved your AdSimple ID.", 'adsimple-cookie-manager-for-wp' ) ); } /** * @since 2.0.6 */ public static function save_cache_options_fields() { if ( ! AS_CM_Controllers_Options::is_configured() ) { return; } $field = static::get_fields( 'cache' ); $data = $field['default']; foreach ( array_keys( $data ) as $key ) { $name = AS_CM_Helpers_General::prepare_name( $field['key'] . '_' . $key ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- nonce verified in save_fields() if ( isset( $_REQUEST[ $name ] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- nonce verified in save_fields() $data[ $key ] = sanitize_text_field( wp_unslash( $_REQUEST[ $name ] ) ); } } static::update_cache_settings( $data ); AS_CM_Services_Notice::add_notice( 'status-save-cache-options', __( "We successfully saved cache options.", 'adsimple-cookie-manager-for-wp' ) ); } /** * @since 1.0.0 * @since 2.0.6 added hook _save_options */ public static function save_fields() { global $pagenow; if ( $pagenow != 'admin.php' ) { return; } // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- page check only, no data processing if ( ! isset( $_GET['page'] ) ) { return; } // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- page check only, no data processing if ( sanitize_text_field( wp_unslash( $_GET['page'] ) ) !== static::get_settings_page_key() ) { return; } if ( ! current_user_can( 'administrator' ) ) { AS_CM_Services_Notice::add_notice( 'status-save-adsimple-id', __( "You don't have access to make this.", 'adsimple-cookie-manager-for-wp' ) ); return; } do_action( AS_CM_Manager::$action . '_options_page' ); // phpcs:ignore WordPress.Security.NonceVerification.Missing -- nonce checked via do_action callbacks if ( empty( $_POST ) ) { return; } do_action( AS_CM_Manager::$action . '_save_options' ); } /** * init options */ public static function init_options_page() { add_menu_page( __( 'Consent Manager', 'adsimple-cookie-manager-for-wp' ), __( 'Consent Manager', 'adsimple-cookie-manager-for-wp' ), 'manage_options', AS_CM_Controllers_Options::get_settings_page_key(), [ __CLASS__, 'render_options_page_content' ], AS_CM_Helpers_General::get_full_assets_url( 'images/icon', 'png' ), 65 ); } /** * Ensure admin menu icon keeps original sizing and positioning. */ public static function print_menu_icon_styles() { $page_key = sanitize_html_class( static::get_settings_page_key() ); ?> static::get_fields( 'adsimple_id' ) ] ); } /** * action on deactivate plugin * * @since 1.0.0 * */ public static function deactivate() { delete_option( static::get_options_name() ); } /** * get full option name * * @param string $option * * @return string * * @since 1.0.0 * */ public static function get_full_option_name( $option ) { return AS_CM_Helpers_General::prepare_name( $option ); } /** * get full name of options * * @return string * * @since 1.0.0 * */ public static function get_options_name() { return static::get_full_option_name( static::OPTION_NAME ); } /** * get embed code * * @return string * * @since 1.0.0 * */ public static function get_option_embed_code() { $embed_code = static::get_option( 'embed_code' ); if ( ! is_string( $embed_code ) ) { return ''; } return $embed_code; } /** * get option embed url * * @return array * * @since 2.0.2 * @since 2.0.5 changed to array */ public static function get_option_embed_url() { $count = preg_match_all( '/src=(["\'])(.*?)\1/', static::get_option_embed_code(), $match ); return $count === false ? [] : ( isset( $match[2] ) ? $match[2] : [] ); } /** * get embed code * * @return string * * @since 1.0.0 * */ public static function get_option_adsimple_id() { return (string) static::get_option( 'adsimple_id' ); } /** * @return boolean * * @since 2.0.6 */ public static function is_configured() { $key = static::get_option_adsimple_id(); $code = static::get_option_embed_code(); return ! empty( $key ) && ! empty( $code ); } /** * get dashboard slug * * @param string $name * * @return string * * @since 1.0.0 * */ public static function get_slug( $name = '' ) { return AS_CM_Helpers_General::prepare_name( static::ADMIN_PAGE . ( ! empty( $name ) ? '_' . $name : '' ), false ); } /** * get dashboard settings page key * * @param string $name * * @return string * * @since 2.0.14 * */ public static function get_settings_page_key( $name = '' ) { return 'as_cm_settings' . ( $name !== '' ? ('-' . $name) : ''); } /** * get page url * * @param string $name * @param array $args * * @return string * * @since 1.0.0 * */ public static function get_page_url( $name = '', $args = [] ) { return AS_CM_Helpers_Transfer::get_link_with_params( array_merge( [ 'page' => static::get_settings_page_key( $name ), ], $args ), admin_url( 'admin.php' ) ); } /** * get option value from DB * * @param string $name * * @return string|mixed * * @since 1.0.0 * */ public static function get_option( $name = '' ) { static::load_options_values(); if ( empty( $name ) ) { return static::$values; } return apply_filters( AS_CM_Manager::$action . '_option_value', isset( static::$values[ $name ] ) ? static::$values[ $name ] : static::get_default_value( $name ), $name ); } /** * load all options values for OPTION_NAME from DB * * @param boolean $reset * * @since 1.0.0 * */ protected static function load_options_values( $reset = false ) { if ( static::$values === null || $reset === true ) { static::$values = get_option( static::get_options_name(), [] ); } } /** * get default value of field * * @param string $name * * @return mixed|null */ public static function get_default_value( $name ) { foreach ( static::get_fields() as $field ) { if ( $field['key'] == $name && isset( $field['default'] ) ) { return $field['default']; } } return null; } /** * get fields * * @param string $key * * @return array|null * * @since 1.0.0 * */ public static function get_fields( $key = '' ) { $fields = [ [ 'key' => 'adsimple_id', 'label' => __( 'AdSimple ID', 'adsimple-cookie-manager-for-wp' ), 'attr' => [ 'type' => 'text', ], 'default' => '', ], [ 'key' => 'cache', 'label' => '', 'attr' => [], 'default' => [ 'available' => false, 'period_type' => 'HOUR_IN_SECONDS', 'period_value' => 24, 'timestamp' => 0 ], ], [ 'key' => 'local_banner', 'label' => '', 'attr' => [], 'default' => static::get_local_banner_defaults(), ], [ 'key' => 'embed_code', 'label' => __( 'Embed code', 'adsimple-cookie-manager-for-wp' ), 'attr' => [ 'type' => 'textarea', ], 'default' => '', ], ]; foreach ( $fields as $index => $field ) { $field['name'] = AS_CM_Helpers_General::prepare_name( $field['key'] ); $fields[ $index ] = $field; if ( ! empty( $key ) && $field['key'] == $key ) { return $field; } } return empty( $key ) ? $fields : null; } private function __clone() {} /** * update options in DB * * @param array $options * * @since 1.0.0 * */ public static function update_options( $options ) { self::$values = $options; update_option( static::get_options_name(), $options ); } /** * @return array * * @since 1.0.0 */ public static function get_available_period_types() { return [ 'DAY_IN_SECONDS' => __( 'days', 'adsimple-cookie-manager-for-wp' ), 'HOUR_IN_SECONDS' => __( 'hours', 'adsimple-cookie-manager-for-wp' ), 'MINUTE_IN_SECONDS' => __( 'minutes', 'adsimple-cookie-manager-for-wp' ), ]; } /** * Update AdSimple ID and embed code * * @param string $raw_id * * @return true|WP_Error */ public static function update_adsimple_id( $raw_id ) { $field = static::get_fields( 'adsimple_id' ); $id = AS_CM_Helpers_General::esc_sql( trim( (string) $raw_id ) ); if ( $id === '' ) { return new \WP_Error( 'as_cm_empty_id', __( 'AdSimple ID can not be empty.', 'adsimple-cookie-manager-for-wp' ) ); } $answer = AS_CM_Services_REST::get_embed_code( $id, get_bloginfo( 'url' ) ); if ( is_wp_error( $answer ) ) { return $answer; } $options = (array) static::get_option(); $options[ $field['key'] ] = $id; $options['embed_code'] = $answer['result']; static::update_options( $options ); return true; } /** * Update cache settings * * @param array $data */ public static function update_cache_settings( $data ) { $field = static::get_fields( 'cache' ); $defaults = isset( $field['default'] ) ? $field['default'] : [ 'available' => false, 'period_type' => 'HOUR_IN_SECONDS', 'period_value' => 24, 'timestamp' => 0 ]; $sanitized = array_merge( $defaults, is_array( $data ) ? $data : [] ); $sanitized['available'] = ! empty( $sanitized['available'] ); $sanitized['period_type'] = isset( $sanitized['period_type'] ) && array_key_exists( $sanitized['period_type'], static::get_available_period_types() ) ? $sanitized['period_type'] : $defaults['period_type']; $sanitized['period_value'] = isset( $sanitized['period_value'] ) ? absint( $sanitized['period_value'] ) : $defaults['period_value']; $sanitized['timestamp'] = 0; $options = (array) static::get_option(); $options['cache'] = $sanitized; static::update_options( $options ); AS_CM_Services_Cache_Manager::delete_cache(); do_action( AS_CM_Manager::$action . '_after_save_cache_options' ); } /** * Sanitize local banner input array * * @param array $input * * @return array */ public static function sanitize_local_banner_input( $input ) { $defaults = static::get_local_banner_defaults(); $data = array_replace_recursive( $defaults, is_array( $input ) ? $input : [] ); $allowed_positions = [ 'bottom', 'bottom-left', 'top', 'bottom-right', 'top-push', 'popup' ]; $allowed_layouts = [ 'classic', 'block', 'wire' ]; $allowed_themes = array_map( function ( $index ) { return 'theme' . $index; }, range( 1, 16 ) ); $hex_pattern = '/^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/'; $sanitize_color = static function ( $value, $fallback ) use ( $hex_pattern ) { $normalize = static function ( $color ) { $color = strtoupper( $color ); $length = strlen( $color ); if ( 4 === $length ) { // #RGB return sprintf( '#%1$s%1$s%2$s%2$s%3$s%3$s', $color[1], $color[2], $color[3] ); } if ( 5 === $length ) { // #RGBA -> drop alpha return sprintf( '#%1$s%1$s%2$s%2$s%3$s%3$s', $color[1], $color[2], $color[3] ); } if ( 9 === $length ) { // #RRGGBBAA -> drop alpha return substr( $color, 0, 7 ); } return $color; }; $color = is_string( $value ) ? trim( $value ) : ''; if ( preg_match( $hex_pattern, $color ) ) { return $normalize( $color ); } return $normalize( $fallback ); }; $data['enabled'] = ! empty( $data['enabled'] ); $data['position'] = in_array( $data['position'], $allowed_positions, true ) ? $data['position'] : $defaults['position']; $data['layout'] = in_array( $data['layout'], $allowed_layouts, true ) ? $data['layout'] : $defaults['layout']; $data['theme'] = in_array( $data['theme'], $allowed_themes, true ) ? $data['theme'] : $defaults['theme']; $data['consent_ttl_days'] = isset( $data['consent_ttl_days'] ) ? absint( $data['consent_ttl_days'] ) : $defaults['consent_ttl_days']; if ( $data['consent_ttl_days'] < 1 ) { $data['consent_ttl_days'] = $defaults['consent_ttl_days']; } if ( $data['consent_ttl_days'] > 730 ) { $data['consent_ttl_days'] = 730; } $sanitized_texts = []; foreach ( $defaults['texts'] as $key => $default ) { $value = isset( $data['texts'][ $key ] ) ? $data['texts'][ $key ] : ''; $sanitized_texts[ $key ] = ( $key === 'message' || $key === 'welcome_message' ) && function_exists( 'sanitize_textarea_field' ) ? sanitize_textarea_field( $value ) : sanitize_text_field( $value ); } $sanitized_links = []; foreach ( $defaults['links'] as $key => $default ) { $value = isset( $data['links'][ $key ] ) ? $data['links'][ $key ] : ''; if ( strpos( $key, '_page_id' ) !== false ) { $sanitized_links[ $key ] = absint( $value ); continue; } if ( in_array( $key, [ 'privacy', 'imprint' ], true ) ) { $sanitized_links[ $key ] = esc_url_raw( $value ); } else { $sanitized_links[ $key ] = sanitize_text_field( $value ); } } $data['texts'] = AS_CM_Helpers_General::esc_sql( $sanitized_texts ); $data['links'] = AS_CM_Helpers_General::esc_sql( $sanitized_links ); $colors = []; foreach ( $defaults['custom_colors'] as $key => $default_color ) { $incoming = isset( $data['custom_colors'][ $key ] ) ? $data['custom_colors'][ $key ] : $default_color; $colors[ $key ] = $sanitize_color( $incoming, $default_color ); } $data['custom_colors'] = $colors; $popup_effects = isset( $data['popup_effects'] ) && is_array( $data['popup_effects'] ) ? array_merge( $defaults['popup_effects'], $data['popup_effects'] ) : $defaults['popup_effects']; $popup_effects['popup_shadow'] = isset( $popup_effects['popup_shadow'] ) && '0' === (string) $popup_effects['popup_shadow'] ? '0' : '1'; $popup_effects['popup_overlay_color'] = $sanitize_color( $popup_effects['popup_overlay_color'], $defaults['popup_effects']['popup_overlay_color'] ); $popup_effects['popup_overlay_opacity'] = isset( $popup_effects['popup_overlay_opacity'] ) ? absint( $popup_effects['popup_overlay_opacity'] ) : $defaults['popup_effects']['popup_overlay_opacity']; if ( $popup_effects['popup_overlay_opacity'] > 100 ) { $popup_effects['popup_overlay_opacity'] = 100; } $data['popup_effects'] = $popup_effects; $settings_button = isset( $data['settings_button'] ) && is_array( $data['settings_button'] ) ? array_merge( $defaults['settings_button'], $data['settings_button'] ) : $defaults['settings_button']; $settings_button['label'] = sanitize_text_field( isset( $settings_button['label'] ) ? $settings_button['label'] : $defaults['settings_button']['label'] ); $settings_button['iconColor'] = $sanitize_color( $settings_button['iconColor'], $defaults['settings_button']['iconColor'] ); $settings_button['iconBackground'] = $sanitize_color( $settings_button['iconBackground'], $defaults['settings_button']['iconBackground'] ); $settings_button['iconDesktopShow'] = isset( $settings_button['iconDesktopShow'] ) && '0' === (string) $settings_button['iconDesktopShow'] ? '0' : '1'; $settings_button['offsetSettingsTabPosition'] = isset( $settings_button['offsetSettingsTabPosition'] ) ? absint( $settings_button['offsetSettingsTabPosition'] ) : $defaults['settings_button']['offsetSettingsTabPosition']; if ( $settings_button['offsetSettingsTabPosition'] > 90 ) { $settings_button['offsetSettingsTabPosition'] = 90; } $data['settings_button'] = $settings_button; $available_categories = isset( $data['cookie_categories']['availableCategories'] ) && is_array( $data['cookie_categories']['availableCategories'] ) ? array_values( array_filter( array_unique( array_map( 'sanitize_key', $data['cookie_categories']['availableCategories'] ) ) ) ) : $defaults['cookie_categories']['availableCategories']; $available_categories = array_values( array_diff( $available_categories, [ 'socialmedia' ] ) ); if ( empty( $available_categories ) ) { $available_categories = $defaults['cookie_categories']['availableCategories']; } $states_input = isset( $data['cookie_categories']['categoryStates'] ) && is_array( $data['cookie_categories']['categoryStates'] ) ? $data['cookie_categories']['categoryStates'] : []; $category_states = []; foreach ( $available_categories as $category ) { $category_state = isset( $states_input[ $category ] ) && is_array( $states_input[ $category ] ) ? $states_input[ $category ] : []; $category_states[ $category ] = [ 'activated' => ! empty( $category_state['activated'] ), 'locked' => ! empty( $category_state['locked'] ), 'visible' => array_key_exists( 'visible', $category_state ) ? (bool) $category_state['visible'] : true, ]; } $data['cookie_categories'] = [ 'availableCategories' => $available_categories, 'categoryStates' => $category_states, ]; $exclude_paths = isset( $data['visibility']['exclude_paths'] ) ? $data['visibility']['exclude_paths'] : ''; $data['visibility']['exclude_paths'] = function_exists( 'sanitize_textarea_field' ) ? sanitize_textarea_field( $exclude_paths ) : sanitize_text_field( $exclude_paths ); $gcm_input = isset( $data['features']['google_consent_mode'] ) && is_array( $data['features']['google_consent_mode'] ) ? $data['features']['google_consent_mode'] : []; $allowed_consent = [ 'denied', 'granted' ]; $gcm_sanitized = [ 'enabled' => ! empty( $gcm_input['enabled'] ), 'default_consent' => in_array( isset( $gcm_input['default_consent'] ) ? $gcm_input['default_consent'] : '', $allowed_consent, true ) ? $gcm_input['default_consent'] : $defaults['features']['google_consent_mode']['default_consent'], ]; // GPC: per W3C spec the signal is a single binary opt-out — enabling it implies // auto-rejecting non-essential cookies and hiding the banner. Sub-flags are // kept in the schema for forward-compat but always stored as true. $gpc_input = isset( $data['features']['gpc_support'] ) && is_array( $data['features']['gpc_support'] ) ? $data['features']['gpc_support'] : []; $gpc_sanitized = [ 'enabled' => ! empty( $gpc_input['enabled'] ), 'auto_reject' => true, 'hide_banner' => true, ]; $data['features'] = [ 'google_consent_mode' => $gcm_sanitized, 'gpc_support' => $gpc_sanitized, ]; return array_replace_recursive( $defaults, $data ); } /** * Update local banner settings * * @param array $input */ public static function update_local_banner( $input ) { $options = (array) static::get_option(); $options['local_banner'] = static::sanitize_local_banner_input( $input ); static::update_options( $options ); } /** * Register REST routes for admin SPA */ public static function register_rest_routes() { register_rest_route( 'as-cm/v1', '/options', [ [ 'methods' => \WP_REST_Server::READABLE, 'callback' => [ __CLASS__, 'rest_get_options' ], 'permission_callback' => function () { return current_user_can( 'manage_options' ); }, ], [ 'methods' => \WP_REST_Server::EDITABLE, 'callback' => [ __CLASS__, 'rest_update_options' ], 'permission_callback' => function () { return current_user_can( 'manage_options' ); }, ], ] ); register_rest_route( 'as-cm/v1', '/disconnect', [ [ 'methods' => \WP_REST_Server::EDITABLE, 'callback' => [ __CLASS__, 'rest_disconnect' ], 'permission_callback' => function () { return current_user_can( 'manage_options' ); }, ], ] ); } /** * REST callback: return current options * * @return WP_REST_Response */ public static function rest_get_options() { return rest_ensure_response( static::prepare_rest_options_response() ); } /** * REST callback: persist options * * @param \WP_REST_Request $request * * @return WP_REST_Response|WP_Error */ public static function rest_update_options( \WP_REST_Request $request ) { $params = $request->get_json_params(); // Only update adsimple_id if it's provided AND not empty (Local Setup can work without it) if ( isset( $params['adsimple_id'] ) && trim( $params['adsimple_id'] ) !== '' ) { $result = static::update_adsimple_id( $params['adsimple_id'] ); if ( is_wp_error( $result ) ) { return $result; } } if ( isset( $params['cache'] ) && static::is_configured() ) { static::update_cache_settings( $params['cache'] ); } if ( isset( $params['local_banner'] ) ) { static::update_local_banner( $params['local_banner'] ); } return rest_ensure_response( static::prepare_rest_options_response() ); } /** * REST callback: disconnect AdSimple ID and remove embed code * * @return WP_REST_Response */ public static function rest_disconnect() { $field = static::get_fields( 'adsimple_id' ); $options = (array) static::get_option(); $options[ $field['key'] ] = ''; $options['embed_code'] = ''; static::update_options( $options ); AS_CM_Services_Cache_Manager::delete_cache(); return rest_ensure_response( static::prepare_rest_options_response() ); } /** * Prepare response payload for REST requests * * @return array */ protected static function prepare_rest_options_response() { $local_banner = static::get_option_local_banner(); return [ 'options' => [ 'adsimple_id' => static::get_option_adsimple_id(), 'cache' => static::get_option( 'cache' ), 'local_banner' => $local_banner, 'local_banner_css_variables' => static::resolve_local_banner_css_variables( $local_banner ), ], 'is_configured' => static::is_configured(), 'cache_clear_url' => AS_CM_Services_Cache_Manager::get_clear_cache_url(), 'pages' => static::get_available_pages(), ]; } protected static function ensure_svg_painter_fallback() { if ( self::$svg_painter_stub_registered ) { return; } self::$svg_painter_stub_registered = true; add_action( 'admin_head', [ __CLASS__, 'print_svg_painter_stub' ], - 999 ); } public static function print_svg_painter_stub() { echo "\n"; } /** * Add type="module" attribute to the admin-app script tag. * * Uses the script_loader_tag filter which is reliable across all * WordPress versions (4.1+), unlike wp_script_add_data('type','module') * which only works in WordPress 6.3+. * * @param string $tag Script HTML tag. * @param string $handle Script handle. * @return string */ public static function add_module_type_attribute( $tag, $handle ) { $app_handle = AS_CM_Helpers_General::prepare_name( 'admin-app', false ); if ( $handle !== $app_handle ) { return $tag; } if ( strpos( $tag, 'type="module"' ) !== false ) { return $tag; } $tag = str_replace( ' src=', ' type="module" src=', $tag ); return $tag; } /** * Enqueue admin SPA assets * * Uses the $hook parameter (page hook suffix) for the page check instead of * get_current_screen()->id because some plugins (WPML, dark-mode, snippet * managers) can modify or delay the WP_Screen object, causing the screen ID * check to fail silently and leaving the admin app un-loaded. */ public static function enqueue_admin_app( $hook ) { $settings_key = static::get_settings_page_key(); $allowed_hooks = [ $settings_key, 'toplevel_page_' . $settings_key, ]; if ( ! in_array( $hook, $allowed_hooks, true ) ) { return; } $entry = static::get_admin_manifest_entry(); if ( empty( $entry ) || empty( $entry['file'] ) ) { return; } $handle = AS_CM_Helpers_General::prepare_name( 'admin-app', false ); $base_url = trailingslashit( AS_CM_Manager::$url . '/assets/admin' ); $base_path = trailingslashit( AS_CM_Manager::$path . 'assets/admin' ); $script_url = $base_url . $entry['file']; self::ensure_svg_painter_fallback(); if ( wp_script_is( 'svg-painter', 'registered' ) ) { wp_add_inline_script( 'svg-painter', '(function(){if(typeof window.svgPainter==="undefined"){window.svgPainter={init:function(){}};}})();', 'before' ); } wp_enqueue_script( $handle, $script_url, [], AS_CM_Manager::$version, true ); add_filter( 'script_loader_tag', [ __CLASS__, 'add_module_type_attribute' ], 10, 2 ); // Load CSS from entry chunk if available if ( ! empty( $entry['css'] ) && is_array( $entry['css'] ) ) { foreach ( $entry['css'] as $index => $css_file ) { $style_handle = $handle . '-style-' . $index; wp_enqueue_style( $style_handle, $base_url . $css_file, [], AS_CM_Manager::$version ); } } else { // Fallback: Load CSS from manifest's style.css entry or directly $manifest = static::get_admin_manifest(); $css_file = null; if ( isset( $manifest['style.css']['file'] ) ) { $css_file = $manifest['style.css']['file']; } elseif ( file_exists( $base_path . 'css/main.css' ) ) { $css_file = 'css/main.css'; } if ( $css_file ) { wp_enqueue_style( $handle . '-style', $base_url . $css_file, [], AS_CM_Manager::$version ); } } $preload = [ 'rootId' => 'as-cm-admin-app', 'restUrl' => esc_url_raw( rest_url( 'as-cm/v1/options' ) ), 'scanRestBase' => esc_url_raw( rest_url( 'adsimple-consent/v1' ) ), 'siteUrl' => home_url( '/' ), 'pluginUrl' => esc_url_raw( AS_CM_Manager::$url ), 'pluginVersion' => AS_CM_Manager::$version, 'nonce' => wp_create_nonce( 'wp_rest' ), 'initialState' => static::prepare_rest_options_response(), 'cssVariables' => static::resolve_local_banner_css_variables( static::get_option_local_banner() ), 'pages' => static::get_available_pages(), 'i18n' => [ // Global 'app_title' => __( 'Consent Manager', 'adsimple-cookie-manager-for-wp' ), 'app_subtitle' => __( 'Configure your cookie consent banner', 'adsimple-cookie-manager-for-wp' ), 'loading' => __( 'Loading...', 'adsimple-cookie-manager-for-wp' ), 'loading_error' => __( 'Unable to load settings. Please refresh the page.', 'adsimple-cookie-manager-for-wp' ), 'no_options' => __( 'No configuration found.', 'adsimple-cookie-manager-for-wp' ), 'save' => __( 'Save', 'adsimple-cookie-manager-for-wp' ), 'save_success' => __( 'Settings saved successfully.', 'adsimple-cookie-manager-for-wp' ), 'save_error' => __( 'There was an error while saving. Please try again.', 'adsimple-cookie-manager-for-wp' ), 'button_save' => __( 'Save changes', 'adsimple-cookie-manager-for-wp' ), 'cancel' => __( 'Cancel', 'adsimple-cookie-manager-for-wp' ), 'close' => __( 'Close', 'adsimple-cookie-manager-for-wp' ), 'enabled' => __( 'Enabled', 'adsimple-cookie-manager-for-wp' ), 'disabled' => __( 'Disabled', 'adsimple-cookie-manager-for-wp' ), 'unsaved' => __( 'Unsaved', 'adsimple-cookie-manager-for-wp' ), 'saved' => __( 'Saved', 'adsimple-cookie-manager-for-wp' ), 'change' => __( 'Change', 'adsimple-cookie-manager-for-wp' ), 'period_days' => __( 'days', 'adsimple-cookie-manager-for-wp' ), 'period_hours' => __( 'hours', 'adsimple-cookie-manager-for-wp' ), 'period_minutes' => __( 'minutes', 'adsimple-cookie-manager-for-wp' ), // Connection / Connected view 'connection_active' => __( 'AdSimple connected', 'adsimple-cookie-manager-for-wp' ), 'connection_inactive' => __( 'AdSimple not connected', 'adsimple-cookie-manager-for-wp' ), 'connection_hint' => __( 'Connect an AdSimple ID to load the banner from AdSimple servers', 'adsimple-cookie-manager-for-wp' ), 'connection_active_info' => __( 'The AdSimple banner is active. The local banner below serves as a fallback if the AdSimple server is unreachable.', 'adsimple-cookie-manager-for-wp' ), 'connection_update' => __( 'Update', 'adsimple-cookie-manager-for-wp' ), 'connection_connect' => __( 'Connect', 'adsimple-cookie-manager-for-wp' ), 'connected_title' => __( 'Connected with AdSimple', 'adsimple-cookie-manager-for-wp' ), 'connected_description' => __( 'Your cookie consent banner is managed by AdSimple. The banner is loaded from the AdSimple servers.', 'adsimple-cookie-manager-for-wp' ), 'connected_local_setup' => __( 'Configure local fallback banner', 'adsimple-cookie-manager-for-wp' ), 'tab_connection' => __( 'Connection', 'adsimple-cookie-manager-for-wp' ), 'label_adsimple_id' => __( 'AdSimple ID', 'adsimple-cookie-manager-for-wp' ), 'helper_adsimple_id' => __( 'You can find your AdSimple ID in the AdSimple dashboard.', 'adsimple-cookie-manager-for-wp' ), 'sidebar_status' => __( 'Status', 'adsimple-cookie-manager-for-wp' ), 'status_connected' => __( 'Connected', 'adsimple-cookie-manager-for-wp' ), 'plugin_version' => __( 'Plugin version', 'adsimple-cookie-manager-for-wp' ), // Cache 'tab_cache' => __( 'Local Cache', 'adsimple-cookie-manager-for-wp' ), 'cache_enable' => __( 'Save a local copy of the script', 'adsimple-cookie-manager-for-wp' ), 'cache_hint' => __( 'Caching stores a copy of the banner script locally for faster delivery. Clear the cache after changing design or text in the AdSimple dashboard.', 'adsimple-cookie-manager-for-wp' ), 'cache_clear_every' => __( 'Clear every', 'adsimple-cookie-manager-for-wp' ), 'cache_clear' => __( 'Clear cache now', 'adsimple-cookie-manager-for-wp' ), // Information 'info_heading' => __( 'Information', 'adsimple-cookie-manager-for-wp' ), 'cookie_overview' => __( 'Cookie Overview', 'adsimple-cookie-manager-for-wp' ), 'shortcode_info' => __( 'Use the shortcode', 'adsimple-cookie-manager-for-wp' ), 'shortcode_info_2' => __( 'to show an ordered list of all cookies on a subpage of your website.', 'adsimple-cookie-manager-for-wp' ), 'wp_head_info' => __( 'The popup is embedded using the', 'adsimple-cookie-manager-for-wp' ), 'wp_head_info_2' => __( 'hook. Your theme should support this hook.', 'adsimple-cookie-manager-for-wp' ), 'publish_view_site' => __( 'View site', 'adsimple-cookie-manager-for-wp' ), // Disconnect 'disconnect_link' => __( 'Disconnect from AdSimple', 'adsimple-cookie-manager-for-wp' ), 'disconnect_title' => __( 'Disconnect AdSimple?', 'adsimple-cookie-manager-for-wp' ), 'disconnect_warning' => __( 'This will remove the AdSimple ID and the embedded banner script. Your site will no longer show the AdSimple consent banner. If you have configured a local fallback banner, it will be used instead.', 'adsimple-cookie-manager-for-wp' ), 'disconnect_confirm' => __( 'Yes, disconnect', 'adsimple-cookie-manager-for-wp' ), // Sidebar 'sidebar_help' => __( 'Need Help?', 'adsimple-cookie-manager-for-wp' ), 'sidebar_help_description' => __( 'Visit our support page for help and setup guides.', 'adsimple-cookie-manager-for-wp' ), 'sidebar_docs' => __( 'Support', 'adsimple-cookie-manager-for-wp' ), // Publish success 'publish_success_title' => __( 'Banner Published!', 'adsimple-cookie-manager-for-wp' ), 'publish_success_message' => __( 'Your cookie consent banner is now live on your website.', 'adsimple-cookie-manager-for-wp' ), // Decision screen 'decision_branding' => __( 'AdSimple Compliance', 'adsimple-cookie-manager-for-wp' ), 'decision_title' => __( 'Welcome to Consent Manager', 'adsimple-cookie-manager-for-wp' ), 'decision_subtitle' => __( 'Choose how you want to set up your cookie consent banner. You can always change this later.', 'adsimple-cookie-manager-for-wp' ), 'decision_connect_title' => __( 'Connect with AdSimple', 'adsimple-cookie-manager-for-wp' ), 'decision_connect_description' => __( 'Link your existing AdSimple account for automatic updates, remote scanning, and premium features.', 'adsimple-cookie-manager-for-wp' ), 'decision_connect_feature_1' => __( 'Automatic legal text updates', 'adsimple-cookie-manager-for-wp' ), 'decision_connect_feature_2' => __( 'Remote cookie scanning', 'adsimple-cookie-manager-for-wp' ), 'decision_connect_feature_3' => __( 'Google Consent Mode v2', 'adsimple-cookie-manager-for-wp' ), 'decision_id_label' => __( 'AdSimple ID', 'adsimple-cookie-manager-for-wp' ), 'decision_id_hint' => __( 'Find your ID in the AdSimple dashboard.', 'adsimple-cookie-manager-for-wp' ), 'decision_connect_button' => __( 'Connect & Continue', 'adsimple-cookie-manager-for-wp' ), 'decision_local_title' => __( 'Local Setup', 'adsimple-cookie-manager-for-wp' ), 'decision_local_description' => __( 'Configure your consent banner manually. Perfect for getting started or testing.', 'adsimple-cookie-manager-for-wp' ), 'decision_local_feature_1' => __( 'Full design customization', 'adsimple-cookie-manager-for-wp' ), 'decision_local_feature_2' => __( 'Browser-based quick scan', 'adsimple-cookie-manager-for-wp' ), 'decision_local_feature_3' => __( 'No account required', 'adsimple-cookie-manager-for-wp' ), 'decision_local_info' => __( 'You can connect your AdSimple account at any time later to unlock premium features.', 'adsimple-cookie-manager-for-wp' ), 'decision_local_button' => __( 'Start Local Setup', 'adsimple-cookie-manager-for-wp' ), 'decision_footer' => __( 'Both options provide GDPR-compliant cookie consent management. Premium features require an AdSimple subscription.', 'adsimple-cookie-manager-for-wp' ), // Wizard steps 'step_design' => __( 'Design', 'adsimple-cookie-manager-for-wp' ), 'step_texts' => __( 'Texts', 'adsimple-cookie-manager-for-wp' ), 'step_cookies' => __( 'Cookies', 'adsimple-cookie-manager-for-wp' ), 'step_settings' => __( 'Settings', 'adsimple-cookie-manager-for-wp' ), 'step_features' => __( 'Features', 'adsimple-cookie-manager-for-wp' ), 'step_review' => __( 'Review', 'adsimple-cookie-manager-for-wp' ), // Design tab 'design_position_title' => __( 'Position & Layout', 'adsimple-cookie-manager-for-wp' ), 'design_position_description' => __( 'Choose where and how the banner appears on your website.', 'adsimple-cookie-manager-for-wp' ), 'design_position' => __( 'Banner Position', 'adsimple-cookie-manager-for-wp' ), 'design_layout' => __( 'Layout Style', 'adsimple-cookie-manager-for-wp' ), 'design_theme_title' => __( 'Color Theme', 'adsimple-cookie-manager-for-wp' ), 'design_theme_description' => __( 'Select a pre-defined color scheme or customize your own.', 'adsimple-cookie-manager-for-wp' ), 'design_custom_active' => __( 'Custom colors active', 'adsimple-cookie-manager-for-wp' ), 'design_preset_active' => __( 'Using preset colors', 'adsimple-cookie-manager-for-wp' ), 'design_custom_colors' => __( 'Custom Colors', 'adsimple-cookie-manager-for-wp' ), 'design_custom_colors_description' => __( 'Override the theme with your own colors', 'adsimple-cookie-manager-for-wp' ), 'design_effects_title' => __( 'Popup Effects', 'adsimple-cookie-manager-for-wp' ), 'design_effects_description' => __( 'Customize the visual effects of the consent popup.', 'adsimple-cookie-manager-for-wp' ), 'design_shadow' => __( 'Drop shadow', 'adsimple-cookie-manager-for-wp' ), 'design_shadow_description' => __( 'Add a shadow effect to the popup', 'adsimple-cookie-manager-for-wp' ), 'design_overlay_color' => __( 'Overlay color', 'adsimple-cookie-manager-for-wp' ), 'design_overlay_opacity' => __( 'Overlay opacity', 'adsimple-cookie-manager-for-wp' ), 'design_button_title' => __( 'Settings Button', 'adsimple-cookie-manager-for-wp' ), 'design_button_description' => __( 'Configure the floating settings button that allows users to reopen consent settings.', 'adsimple-cookie-manager-for-wp' ), 'design_button_label' => __( 'Button label', 'adsimple-cookie-manager-for-wp' ), 'design_button_desktop' => __( 'Show on desktop', 'adsimple-cookie-manager-for-wp' ), 'design_button_desktop_description' => __( 'Display the settings button on desktop devices', 'adsimple-cookie-manager-for-wp' ), 'design_button_icon_color' => __( 'Icon color', 'adsimple-cookie-manager-for-wp' ), 'design_button_icon_bg' => __( 'Icon background', 'adsimple-cookie-manager-for-wp' ), 'design_button_offset' => __( 'Position offset (%)', 'adsimple-cookie-manager-for-wp' ), // Texts tab 'texts_banner_title' => __( 'Banner Texts', 'adsimple-cookie-manager-for-wp' ), 'texts_banner_description' => __( 'Customize the text content of your cookie consent banner.', 'adsimple-cookie-manager-for-wp' ), 'texts_links_title' => __( 'Legal Links', 'adsimple-cookie-manager-for-wp' ), 'texts_links_description' => __( 'Configure links to your privacy policy and legal notice pages.', 'adsimple-cookie-manager-for-wp' ), 'texts_privacy_title' => __( 'Privacy Policy', 'adsimple-cookie-manager-for-wp' ), 'texts_select_page' => __( 'Select from WordPress pages', 'adsimple-cookie-manager-for-wp' ), 'texts_manual_url' => __( 'Enter URL manually', 'adsimple-cookie-manager-for-wp' ), 'texts_imprint_title' => __( 'Legal Notice / Imprint', 'adsimple-cookie-manager-for-wp' ), // Cookies tab 'cookies_categories_title' => __( 'Cookie Categories', 'adsimple-cookie-manager-for-wp' ), 'cookies_categories_description' => __( 'Configure how each cookie category behaves in the consent banner.', 'adsimple-cookie-manager-for-wp' ), 'cookies_required' => __( 'Required', 'adsimple-cookie-manager-for-wp' ), 'scan_results_pending' => __( 'Complete a scan to see results here.', 'adsimple-cookie-manager-for-wp' ), // Position options 'position_popup' => __( 'Popup (center)', 'adsimple-cookie-manager-for-wp' ), 'position_bottom' => __( 'Bottom bar', 'adsimple-cookie-manager-for-wp' ), 'position_bottom_left' => __( 'Bottom left', 'adsimple-cookie-manager-for-wp' ), 'position_bottom_right' => __( 'Bottom right', 'adsimple-cookie-manager-for-wp' ), 'position_top' => __( 'Top bar', 'adsimple-cookie-manager-for-wp' ), 'position_top_push' => __( 'Top fixed', 'adsimple-cookie-manager-for-wp' ), // Layout options 'layout_classic' => __( 'Classic', 'adsimple-cookie-manager-for-wp' ), 'layout_block' => __( 'Block', 'adsimple-cookie-manager-for-wp' ), 'layout_wire' => __( 'Wireframe', 'adsimple-cookie-manager-for-wp' ), // Banner text field labels 'text_field_welcome_title' => __( 'Banner title', 'adsimple-cookie-manager-for-wp' ), 'text_field_welcome_message' => __( 'Banner text', 'adsimple-cookie-manager-for-wp' ), 'text_field_welcome_message_helper' => __( 'Supported placeholders: {cookie-einstellungen}…{/cookie-einstellungen} or {cookie-settings}…{/cookie-settings}, {erforderliche-cookies}…{/erforderliche-cookies} or {necessary-cookies}…{/necessary-cookies}', 'adsimple-cookie-manager-for-wp' ), 'text_field_allow' => __( 'Button "Allow all"', 'adsimple-cookie-manager-for-wp' ), 'text_field_necessary_only' => __( 'Button "Necessary only"', 'adsimple-cookie-manager-for-wp' ), 'text_field_policy' => __( 'Button "Privacy settings"', 'adsimple-cookie-manager-for-wp' ), 'text_field_save_settings' => __( 'Button "Save settings"', 'adsimple-cookie-manager-for-wp' ), 'text_field_settings_title' => __( 'Settings title', 'adsimple-cookie-manager-for-wp' ), 'text_field_settings_text' => __( 'Settings text', 'adsimple-cookie-manager-for-wp' ), 'text_field_close' => __( 'Button "Close"', 'adsimple-cookie-manager-for-wp' ), // Link field labels 'link_field_privacy_url' => __( 'Privacy policy URL', 'adsimple-cookie-manager-for-wp' ), 'link_field_privacy_label' => __( 'Privacy policy label', 'adsimple-cookie-manager-for-wp' ), 'link_field_imprint_url' => __( 'Legal notice URL', 'adsimple-cookie-manager-for-wp' ), 'link_field_imprint_label' => __( 'Legal notice label', 'adsimple-cookie-manager-for-wp' ), // Category state labels 'category_state_activated' => __( 'Activated by default', 'adsimple-cookie-manager-for-wp' ), 'category_state_locked' => __( 'Locked', 'adsimple-cookie-manager-for-wp' ), 'category_state_visible' => __( 'Visible', 'adsimple-cookie-manager-for-wp' ), // Category names and descriptions 'category_unclassified' => __( 'Unclassified', 'adsimple-cookie-manager-for-wp' ), 'category_unclassified_desc' => __( 'Cookies that have not yet been categorized.', 'adsimple-cookie-manager-for-wp' ), 'category_required' => __( 'Required', 'adsimple-cookie-manager-for-wp' ), 'category_required_desc' => __( 'Essential cookies required for the website to function properly.', 'adsimple-cookie-manager-for-wp' ), 'category_statistics' => __( 'Statistics', 'adsimple-cookie-manager-for-wp' ), 'category_statistics_desc' => __( 'Cookies used to understand how visitors interact with the website.', 'adsimple-cookie-manager-for-wp' ), 'category_marketing' => __( 'Marketing', 'adsimple-cookie-manager-for-wp' ), 'category_marketing_desc' => __( 'Cookies used to track visitors across websites for advertising.', 'adsimple-cookie-manager-for-wp' ), 'category_statistics_anon' => __( 'Statistics (anonymous)', 'adsimple-cookie-manager-for-wp' ), 'category_statistics_anon_desc' => __( 'Anonymized statistics cookies that do not track individual users.', 'adsimple-cookie-manager-for-wp' ), 'category_preferences' => __( 'Preferences', 'adsimple-cookie-manager-for-wp' ), 'category_preferences_desc' => __( 'Cookies that remember user preferences and personalization settings.', 'adsimple-cookie-manager-for-wp' ), // Settings tab 'settings_consent_title' => __( 'Consent Settings', 'adsimple-cookie-manager-for-wp' ), 'settings_consent_description' => __( 'Configure how long consent is stored and general behavior.', 'adsimple-cookie-manager-for-wp' ), 'settings_consent_ttl' => __( 'Consent validity (days)', 'adsimple-cookie-manager-for-wp' ), 'settings_visibility_title' => __( 'Visibility Rules', 'adsimple-cookie-manager-for-wp' ), 'settings_visibility_description' => __( 'Control where the banner appears or is hidden.', 'adsimple-cookie-manager-for-wp' ), 'settings_exclude_paths' => __( 'Exclude paths (one per line)', 'adsimple-cookie-manager-for-wp' ), 'settings_exclude_paths_hint' => __( 'Enter URL paths where the banner should not appear. E.g.: /checkout, /my-account/*', 'adsimple-cookie-manager-for-wp' ), 'settings_visibility_blocking_warning' => __( 'On excluded paths the banner is not displayed and automatic script blocking will not work either. Third-party scripts may load without consent on these pages.', 'adsimple-cookie-manager-for-wp' ), // Features tab 'features_gcm_title' => __( 'Google Consent Mode v2', 'adsimple-cookie-manager-for-wp' ), 'features_recommended' => __( 'Recommended', 'adsimple-cookie-manager-for-wp' ), 'features_gcm_description' => __( 'Enable Google Consent Mode to ensure proper integration with Google services like Analytics, Ads, and Tag Manager.', 'adsimple-cookie-manager-for-wp' ), 'features_gcm_enable' => __( 'Enable Google Consent Mode', 'adsimple-cookie-manager-for-wp' ), 'features_gcm_enable_description' => __( 'Automatically signal consent to Google services', 'adsimple-cookie-manager-for-wp' ), 'features_gcm_default' => __( 'Default consent state', 'adsimple-cookie-manager-for-wp' ), 'features_gcm_denied' => __( 'Denied (recommended)', 'adsimple-cookie-manager-for-wp' ), 'features_gcm_denied_description' => __( 'No tracking until user gives consent', 'adsimple-cookie-manager-for-wp' ), 'features_gcm_granted' => __( 'Granted', 'adsimple-cookie-manager-for-wp' ), 'features_gcm_granted_description' => __( 'Tracking enabled by default until user opts out', 'adsimple-cookie-manager-for-wp' ), // GPC (Global Privacy Control) 'features_gpc_title' => __( 'Global Privacy Control (GPC)', 'adsimple-cookie-manager-for-wp' ), 'features_gpc_description' => __( 'Respect the W3C Global Privacy Control signal. When a visitor\'s browser sends the GPC opt-out signal, non-essential cookies are automatically rejected and the consent banner is skipped — the settings badge stays visible so visitors can change their preferences.', 'adsimple-cookie-manager-for-wp' ), 'features_gpc_enable' => __( 'Enable GPC support', 'adsimple-cookie-manager-for-wp' ), 'features_gpc_enable_description' => __( 'Detect the GPC signal, auto-reject non-essential cookies and skip the banner', 'adsimple-cookie-manager-for-wp' ), 'features_gpc_learn_more' => __( 'Learn more about Global Privacy Control', 'adsimple-cookie-manager-for-wp' ), // Review tab 'review_status_title' => __( 'Banner Status', 'adsimple-cookie-manager-for-wp' ), 'review_status_description' => __( 'Overview of your consent banner configuration.', 'adsimple-cookie-manager-for-wp' ), 'review_enabled' => __( 'Banner is enabled', 'adsimple-cookie-manager-for-wp' ), 'review_enabled_description' => __( 'Your cookie consent banner is active and visible to visitors.', 'adsimple-cookie-manager-for-wp' ), 'review_disabled' => __( 'Banner is disabled', 'adsimple-cookie-manager-for-wp' ), 'review_disabled_description' => __( 'Enable the banner in the Design tab to show it to visitors.', 'adsimple-cookie-manager-for-wp' ), 'review_summary_title' => __( 'Configuration Summary', 'adsimple-cookie-manager-for-wp' ), 'review_custom_active' => __( 'Custom colors active', 'adsimple-cookie-manager-for-wp' ), 'review_preset_active' => __( 'Using preset colors', 'adsimple-cookie-manager-for-wp' ), 'review_position' => __( 'Position', 'adsimple-cookie-manager-for-wp' ), 'review_layout' => __( 'Layout', 'adsimple-cookie-manager-for-wp' ), 'review_privacy' => __( 'Privacy Policy', 'adsimple-cookie-manager-for-wp' ), 'review_configured' => __( 'Configured', 'adsimple-cookie-manager-for-wp' ), 'review_missing' => __( 'Missing', 'adsimple-cookie-manager-for-wp' ), 'review_imprint' => __( 'Legal Notice', 'adsimple-cookie-manager-for-wp' ), 'review_consent_ttl' => __( 'Consent Validity', 'adsimple-cookie-manager-for-wp' ), 'review_days' => __( 'days', 'adsimple-cookie-manager-for-wp' ), 'review_gcm' => __( 'Google Consent Mode', 'adsimple-cookie-manager-for-wp' ), 'review_gpc' => __( 'Global Privacy Control', 'adsimple-cookie-manager-for-wp' ), 'review_enabled_short' => __( 'Enabled', 'adsimple-cookie-manager-for-wp' ), 'review_disabled_short' => __( 'Disabled', 'adsimple-cookie-manager-for-wp' ), 'review_actions_title' => __( 'Save & Publish', 'adsimple-cookie-manager-for-wp' ), 'review_actions_description' => __( 'Save your changes and publish the banner to your website.', 'adsimple-cookie-manager-for-wp' ), 'review_unsaved' => __( 'You have unsaved changes. Save before publishing to apply them.', 'adsimple-cookie-manager-for-wp' ), 'review_save' => __( 'Save Changes', 'adsimple-cookie-manager-for-wp' ), 'review_publish' => __( 'Publish Banner', 'adsimple-cookie-manager-for-wp' ), // Quick scan 'quick_scan_title' => __( 'Quick Website Scan', 'adsimple-cookie-manager-for-wp' ), 'quick_scan_description' => __( 'Launch a live browser scan to capture cookies, storage writes, and third-party requests exactly as visitors experience them.', 'adsimple-cookie-manager-for-wp' ), 'quick_scan_creating' => __( 'Creating...', 'adsimple-cookie-manager-for-wp' ), 'quick_scan_stop' => __( 'Stop', 'adsimple-cookie-manager-for-wp' ), 'quick_scan_start' => __( 'Start Scan', 'adsimple-cookie-manager-for-wp' ), 'scan_progress' => __( 'Progress', 'adsimple-cookie-manager-for-wp' ), 'scan_pages' => __( 'pages', 'adsimple-cookie-manager-for-wp' ), 'scan_stats_pages' => __( 'Pages', 'adsimple-cookie-manager-for-wp' ), 'scan_stats_cookies' => __( 'Cookies', 'adsimple-cookie-manager-for-wp' ), 'scan_stats_hosts' => __( 'External Hosts', 'adsimple-cookie-manager-for-wp' ), 'quick_scan_injecting' => __( 'Loading website and injecting scanner...', 'adsimple-cookie-manager-for-wp' ), 'quick_scan_completing' => __( 'Finalizing scan results...', 'adsimple-cookie-manager-for-wp' ), 'quick_scan_completed' => __( 'Scan completed successfully!', 'adsimple-cookie-manager-for-wp' ), 'quick_scan_missing_endpoint' => __( 'Scan endpoint not configured.', 'adsimple-cookie-manager-for-wp' ), 'quick_scan_last_job' => __( 'Last scan:', 'adsimple-cookie-manager-for-wp' ), 'quick_scan_scanned_urls' => __( 'Scanned URLs', 'adsimple-cookie-manager-for-wp' ), 'quick_scan_no_urls' => __( 'URL details not available. Run a new scan to see details.', 'adsimple-cookie-manager-for-wp' ), 'quick_scan_dialog_title' => __( 'Start Multi-Page Scan?', 'adsimple-cookie-manager-for-wp' ), 'quick_scan_dialog_description' => __( 'The scanner will crawl all public pages of your website and capture cookies and external resources.', 'adsimple-cookie-manager-for-wp' ), 'quick_scan_dialog_cancel' => __( 'Cancel', 'adsimple-cookie-manager-for-wp' ), // Scan results 'scan_results_title' => __( 'Scan Results', 'adsimple-cookie-manager-for-wp' ), 'scan_results_no_job' => __( 'No scan job selected. Start a scan to see results.', 'adsimple-cookie-manager-for-wp' ), 'scan_results_description' => __( 'Review detected services and assign them to cookie categories.', 'adsimple-cookie-manager-for-wp' ), 'scan_results_refresh' => __( 'Refresh', 'adsimple-cookie-manager-for-wp' ), 'scan_results_save' => __( 'Save', 'adsimple-cookie-manager-for-wp' ), 'scan_tab_cookies' => __( 'Cookies', 'adsimple-cookie-manager-for-wp' ), 'scan_tab_hosts' => __( 'External Hosts', 'adsimple-cookie-manager-for-wp' ), 'scan_results_no_cookies' => __( 'No cookies detected. WordPress admin cookies are automatically filtered.', 'adsimple-cookie-manager-for-wp' ), 'scan_select_category' => __( 'Category...', 'adsimple-cookie-manager-for-wp' ), 'scan_category_unassigned' => __( 'Unassigned', 'adsimple-cookie-manager-for-wp' ), 'scan_category_none' => __( 'None (blocked)', 'adsimple-cookie-manager-for-wp' ), 'scan_cookie_provider' => __( 'Provider', 'adsimple-cookie-manager-for-wp' ), 'scan_cookie_domain' => __( 'Domain', 'adsimple-cookie-manager-for-wp' ), 'scan_cookie_expires' => __( 'Expires', 'adsimple-cookie-manager-for-wp' ), 'scan_cookie_type' => __( 'Type', 'adsimple-cookie-manager-for-wp' ), 'scan_cookie_purpose' => __( 'Purpose / Description', 'adsimple-cookie-manager-for-wp' ), 'scan_cookie_purpose_placeholder' => __( 'Describe what this cookie is used for...', 'adsimple-cookie-manager-for-wp' ), 'scan_filter' => __( 'Filter', 'adsimple-cookie-manager-for-wp' ), 'scan_filter_all' => __( 'All', 'adsimple-cookie-manager-for-wp' ), 'scan_filter_unassigned' => __( 'Unassigned', 'adsimple-cookie-manager-for-wp' ), 'scan_col_host' => __( 'Host', 'adsimple-cookie-manager-for-wp' ), 'scan_col_count' => __( 'Count', 'adsimple-cookie-manager-for-wp' ), 'scan_col_category' => __( 'Category', 'adsimple-cookie-manager-for-wp' ), 'scan_col_categories' => __( 'Categories', 'adsimple-cookie-manager-for-wp' ), 'scan_add_host' => __( 'Add Host', 'adsimple-cookie-manager-for-wp' ), 'scan_manual' => __( 'manual', 'adsimple-cookie-manager-for-wp' ), 'scan_remove_host' => __( 'Remove', 'adsimple-cookie-manager-for-wp' ), 'scan_no_categories' => __( 'None (blocked)', 'adsimple-cookie-manager-for-wp' ), 'scan_results_all_hosts_are_cookies' => __( 'All external hosts are already associated with cookies.', 'adsimple-cookie-manager-for-wp' ), 'scan_results_no_hosts' => __( 'No external hosts detected.', 'adsimple-cookie-manager-for-wp' ), 'scan_summary_refresh_error' => __( 'Unable to fetch scan results.', 'adsimple-cookie-manager-for-wp' ), 'scan_summary_saved' => __( 'Changes saved.', 'adsimple-cookie-manager-for-wp' ), 'scan_summary_save_error' => __( 'Unable to save.', 'adsimple-cookie-manager-for-wp' ), 'scan_hosts_filtered_info' => __( 'Note: Domains already used for cookies are hidden here.', 'adsimple-cookie-manager-for-wp' ), 'scan_quickscan_warning' => __( 'This is a local quick scan. It is not guaranteed that all cookies and external resources will be detected. Third-party scripts may set additional cookies dynamically that cannot be captured by a single page scan.', 'adsimple-cookie-manager-for-wp' ), // Preview 'preview_loading' => __( 'Loading...', 'adsimple-cookie-manager-for-wp' ), 'preview_hide' => __( 'Hide Preview', 'adsimple-cookie-manager-for-wp' ), 'preview_show' => __( 'Show Preview', 'adsimple-cookie-manager-for-wp' ), ], ]; wp_add_inline_script( $handle, 'window.AS_CM_ADMIN_APP = ' . wp_json_encode( $preload ) . ';', 'before' ); } /** * Load Vite manifest entry * * @return array */ protected static function get_admin_manifest_entry() { $manifest = static::get_admin_manifest(); $entry_key = 'src/main.tsx'; return isset( $manifest[ $entry_key ] ) ? $manifest[ $entry_key ] : []; } /** * Read Vite manifest file * * @return array */ protected static function get_admin_manifest() { static $manifest = null; if ( $manifest !== null ) { return $manifest; } $manifest_path = AS_CM_Manager::$path . 'assets/admin/manifest.json'; if ( ! file_exists( $manifest_path ) ) { $manifest = []; return $manifest; } $contents = file_get_contents( $manifest_path ); $data = json_decode( $contents, true ); $manifest = is_array( $data ) ? $data : []; return $manifest; } /** * Local banner defaults * * @return array */ public static function get_local_banner_defaults() { return [ 'enabled' => true, 'position' => 'popup', 'layout' => 'classic', 'theme' => 'theme1', 'consent_ttl_days' => 180, 'custom_colors_enabled' => false, 'custom_colors' => static::get_local_banner_custom_color_defaults(), 'popup_effects' => [ 'popup_shadow' => '1', 'popup_overlay_color' => '', 'popup_overlay_opacity'=> 50, ], 'settings_button' => [ 'label' => __( 'Privacy settings', 'adsimple-cookie-manager-for-wp' ), 'iconColor' => '', 'iconBackground' => '', 'iconDesktopShow' => '1', 'offsetSettingsTabPosition' => 1, ], 'cookie_categories' => [ 'availableCategories' => [ 'unclassified', 'required', 'statistics', 'statistics-anonymous', 'marketing', 'preferences', ], 'categoryStates' => [ 'unclassified' => [ 'activated' => false, 'locked' => false, 'visible' => true ], 'required' => [ 'activated' => true, 'locked' => true, 'visible' => true ], 'statistics' => [ 'activated' => false, 'locked' => false, 'visible' => true ], 'statistics-anonymous' => [ 'activated' => false, 'locked' => false, 'visible' => true ], 'marketing' => [ 'activated' => false, 'locked' => false, 'visible' => true ], 'preferences' => [ 'activated' => false, 'locked' => false, 'visible' => true ], ], ], 'visibility' => [ 'exclude_paths' => '', ], 'features' => [ 'google_consent_mode' => [ 'enabled' => false, 'default_consent' => 'denied', ], 'gpc_support' => [ 'enabled' => false, 'auto_reject' => true, 'hide_banner' => true, ], ], 'texts' => [ 'welcome_title' => __( 'Notice on data processing', 'adsimple-cookie-manager-for-wp' ), 'welcome_message' => __( "If you want to use our website without restrictions, please click «Accept all». Data processing from third parties that we have classified as not necessary can be {necessary-cookies}rejected{/necessary-cookies}. You can change your {cookie-settings}Privacy Settings{/cookie-settings} at any time.", 'adsimple-cookie-manager-for-wp' ), 'allow' => __( 'Accept all', 'adsimple-cookie-manager-for-wp' ), 'necessary_cookies_only' => __( 'Necessary only', 'adsimple-cookie-manager-for-wp' ), 'allow_selected' => __( 'Save selection', 'adsimple-cookie-manager-for-wp' ), 'policy' => __( 'Privacy settings', 'adsimple-cookie-manager-for-wp' ), 'title' => __( 'Settings', 'adsimple-cookie-manager-for-wp' ), 'message' => __( 'Below you have the option to set your own preferences.', 'adsimple-cookie-manager-for-wp' ), 'close' => __( 'Close', 'adsimple-cookie-manager-for-wp' ), 'heading_notice' => __( 'Notice', 'adsimple-cookie-manager-for-wp' ), 'heading_settings' => __( 'Settings', 'adsimple-cookie-manager-for-wp' ), 'select_all_categories' => __( 'Allow all categories', 'adsimple-cookie-manager-for-wp' ), 'cookie_name' => __( 'NAME', 'adsimple-cookie-manager-for-wp' ), 'cookie_provider' => __( 'PROVIDER', 'adsimple-cookie-manager-for-wp' ), 'cookie_purpose' => __( 'PURPOSE', 'adsimple-cookie-manager-for-wp' ), 'cookie_expires' => __( 'EXPIRES', 'adsimple-cookie-manager-for-wp' ), 'cookie_type' => __( 'TYPE', 'adsimple-cookie-manager-for-wp' ), 'cookie_session' => __( 'Session', 'adsimple-cookie-manager-for-wp' ), 'external_hosts_title' => __( 'External Resource Domains', 'adsimple-cookie-manager-for-wp' ), 'external_hosts_description' => __( 'Below is a list of external resource domains used on our website that may process personal data.', 'adsimple-cookie-manager-for-wp' ), 'required_label' => __( 'Necessary', 'adsimple-cookie-manager-for-wp' ), 'required_description' => '', 'statistics_label' => __( 'Statistics', 'adsimple-cookie-manager-for-wp' ), 'statistics_description' => '', 'marketing_label' => __( 'Marketing', 'adsimple-cookie-manager-for-wp' ), 'marketing_description' => '', ], 'links' => [ 'privacy' => '', 'privacy_label' => '', 'privacy_page_id' => 0, 'imprint' => '', 'imprint_label' => '', 'imprint_page_id' => 0, ], ]; } /** * Get local banner options merged with defaults * * @return array */ public static function get_option_local_banner() { $current = static::get_option( 'local_banner' ); $defaults = static::get_local_banner_defaults(); $base = is_array( $current ) ? self::normalize_local_banner_structure( $current ) : []; $merged = array_replace_recursive( $defaults, $base ); $merged['enabled'] = ! empty( $merged['enabled'] ); $merged['consent_ttl_days'] = isset( $merged['consent_ttl_days'] ) ? absint( $merged['consent_ttl_days'] ) : $defaults['consent_ttl_days']; $merged['texts'] = isset( $merged['texts'] ) ? AS_CM_Helpers_General::stripcslashes( $merged['texts'] ) : $defaults['texts']; // Fill empty text values with defaults so fields are never blank foreach ( $defaults['texts'] as $text_key => $text_default ) { if ( ! isset( $merged['texts'][ $text_key ] ) || '' === trim( $merged['texts'][ $text_key ] ) ) { $merged['texts'][ $text_key ] = $text_default; } } $merged['links'] = isset( $merged['links'] ) ? AS_CM_Helpers_General::stripcslashes( $merged['links'] ) : $defaults['links']; $allowed_positions = [ 'bottom', 'bottom-left', 'top', 'bottom-right', 'top-push', 'popup' ]; $merged['position'] = isset( $merged['position'] ) && in_array( $merged['position'], $allowed_positions, true ) ? $merged['position'] : $defaults['position']; $allowed_layouts = [ 'classic', 'block', 'wire' ]; $allowed_themes = array_map( function ( $index ) { return 'theme' . $index; }, range( 1, 16 ) ); $merged['layout'] = isset( $merged['layout'] ) && in_array( $merged['layout'], $allowed_layouts, true ) ? $merged['layout'] : $defaults['layout']; $merged['theme'] = isset( $merged['theme'] ) && in_array( $merged['theme'], $allowed_themes, true ) ? $merged['theme'] : $defaults['theme']; $merged['custom_colors'] = isset( $merged['custom_colors'] ) && is_array( $merged['custom_colors'] ) ? array_replace_recursive( $defaults['custom_colors'], $merged['custom_colors'] ) : $defaults['custom_colors']; foreach ( $merged['custom_colors'] as $color_key => $color_value ) { if ( is_string( $color_value ) && '' === trim( $color_value ) && isset( $defaults['custom_colors'][ $color_key ] ) ) { $merged['custom_colors'][ $color_key ] = $defaults['custom_colors'][ $color_key ]; } } $merged['popup_effects'] = isset( $merged['popup_effects'] ) && is_array( $merged['popup_effects'] ) ? array_replace_recursive( $defaults['popup_effects'], $merged['popup_effects'] ) : $defaults['popup_effects']; $merged['popup_effects']['popup_shadow'] = isset( $merged['popup_effects']['popup_shadow'] ) && '0' === (string) $merged['popup_effects']['popup_shadow'] ? '0' : '1'; $merged['popup_effects']['popup_overlay_opacity'] = isset( $merged['popup_effects']['popup_overlay_opacity'] ) ? min( 100, max( 0, absint( $merged['popup_effects']['popup_overlay_opacity'] ) ) ) : $defaults['popup_effects']['popup_overlay_opacity']; $merged['settings_button'] = isset( $merged['settings_button'] ) && is_array( $merged['settings_button'] ) ? array_replace_recursive( $defaults['settings_button'], $merged['settings_button'] ) : $defaults['settings_button']; $merged['settings_button']['label'] = isset( $merged['settings_button']['label'] ) ? sanitize_text_field( $merged['settings_button']['label'] ) : $defaults['settings_button']['label']; $merged['settings_button']['iconDesktopShow'] = isset( $merged['settings_button']['iconDesktopShow'] ) && '0' === (string) $merged['settings_button']['iconDesktopShow'] ? '0' : '1'; $merged['settings_button']['offsetSettingsTabPosition'] = isset( $merged['settings_button']['offsetSettingsTabPosition'] ) ? min( 90, max( 0, absint( $merged['settings_button']['offsetSettingsTabPosition'] ) ) ) : $defaults['settings_button']['offsetSettingsTabPosition']; $merged['cookie_categories'] = isset( $merged['cookie_categories'] ) && is_array( $merged['cookie_categories'] ) ? array_replace_recursive( $defaults['cookie_categories'], $merged['cookie_categories'] ) : $defaults['cookie_categories']; $available_categories = isset( $merged['cookie_categories']['availableCategories'] ) && is_array( $merged['cookie_categories']['availableCategories'] ) ? array_values( array_filter( array_unique( array_map( 'sanitize_key', $merged['cookie_categories']['availableCategories'] ) ) ) ) : $defaults['cookie_categories']['availableCategories']; $available_categories = array_values( array_diff( $available_categories, [ 'socialmedia' ] ) ); if ( empty( $available_categories ) ) { $available_categories = $defaults['cookie_categories']['availableCategories']; } $category_states = []; foreach ( $available_categories as $category ) { $incoming = isset( $merged['cookie_categories']['categoryStates'][ $category ] ) && is_array( $merged['cookie_categories']['categoryStates'][ $category ] ) ? $merged['cookie_categories']['categoryStates'][ $category ] : [ 'activated' => false, 'locked' => false, 'visible' => true ]; $category_states[ $category ] = [ 'activated' => ! empty( $incoming['activated'] ), 'locked' => ! empty( $incoming['locked'] ), 'visible' => array_key_exists( 'visible', $incoming ) ? (bool) $incoming['visible'] : true, ]; } $merged['cookie_categories']['availableCategories'] = $available_categories; $merged['cookie_categories']['categoryStates'] = $category_states; $merged['visibility']['exclude_paths'] = isset( $merged['visibility']['exclude_paths'] ) ? (string) $merged['visibility']['exclude_paths'] : ''; $merged['features'] = isset( $merged['features'] ) && is_array( $merged['features'] ) ? array_replace_recursive( $defaults['features'], $merged['features'] ) : $defaults['features']; unset( $merged['features']['tcf'] ); $merged['features']['google_consent_mode']['enabled'] = ! empty( $merged['features']['google_consent_mode']['enabled'] ); $merged['features']['google_consent_mode']['default_consent'] = in_array( isset( $merged['features']['google_consent_mode']['default_consent'] ) ? $merged['features']['google_consent_mode']['default_consent'] : '', [ 'denied', 'granted' ], true ) ? $merged['features']['google_consent_mode']['default_consent'] : $defaults['features']['google_consent_mode']['default_consent']; if ( ! isset( $merged['features']['gpc_support'] ) || ! is_array( $merged['features']['gpc_support'] ) ) { $merged['features']['gpc_support'] = $defaults['features']['gpc_support']; } // GPC is a single binary signal per W3C spec: enabling it implies // auto-rejecting non-essential cookies and hiding the banner. // Sub-flags are kept in the schema for forward-compat but always // coerced to true when enabled to avoid useless / broken combinations. $merged['features']['gpc_support']['enabled'] = ! empty( $merged['features']['gpc_support']['enabled'] ); $merged['features']['gpc_support']['auto_reject'] = true; $merged['features']['gpc_support']['hide_banner'] = true; $merged['custom_colors_enabled'] = ! empty( $merged['custom_colors_enabled'] ); return $merged; } public static function get_option_local_banner_css_variables() { return static::resolve_local_banner_css_variables( static::get_option_local_banner() ); } /** * Save local fallback banner settings */ public static function save_local_banner_settings() { $field = static::get_fields( 'local_banner' ); if ( empty( $field ) ) { return; } $name = function ( $suffix ) { return AS_CM_Helpers_General::prepare_name( 'local_banner_' . $suffix ); }; // phpcs:disable WordPress.Security.NonceVerification.Recommended -- nonce verified in save_fields() $payload = [ 'enabled' => isset( $_REQUEST[ $name( 'enabled' ) ] ) ? 1 : 0, 'position' => isset( $_REQUEST[ $name( 'position' ) ] ) ? sanitize_text_field( wp_unslash( $_REQUEST[ $name( 'position' ) ] ) ) : null, 'consent_ttl_days' => isset( $_REQUEST[ $name( 'consent_ttl_days' ) ] ) ? absint( wp_unslash( $_REQUEST[ $name( 'consent_ttl_days' ) ] ) ) : null, 'texts' => [], 'links' => [ 'privacy' => isset( $_REQUEST[ $name( 'link_privacy' ) ] ) ? esc_url_raw( wp_unslash( $_REQUEST[ $name( 'link_privacy' ) ] ) ) : '', 'privacy_label' => isset( $_REQUEST[ $name( 'link_privacy_label' ) ] ) ? sanitize_text_field( wp_unslash( $_REQUEST[ $name( 'link_privacy_label' ) ] ) ) : '', 'privacy_page_id' => isset( $_REQUEST[ $name( 'link_privacy_page_id' ) ] ) ? absint( wp_unslash( $_REQUEST[ $name( 'link_privacy_page_id' ) ] ) ) : 0, 'imprint' => isset( $_REQUEST[ $name( 'link_imprint' ) ] ) ? esc_url_raw( wp_unslash( $_REQUEST[ $name( 'link_imprint' ) ] ) ) : '', 'imprint_label' => isset( $_REQUEST[ $name( 'link_imprint_label' ) ] ) ? sanitize_text_field( wp_unslash( $_REQUEST[ $name( 'link_imprint_label' ) ] ) ) : '', 'imprint_page_id' => isset( $_REQUEST[ $name( 'link_imprint_page_id' ) ] ) ? absint( wp_unslash( $_REQUEST[ $name( 'link_imprint_page_id' ) ] ) ) : 0, ], 'settings_button' => [ 'label' => isset( $_REQUEST[ $name( 'settings_button_label' ) ] ) ? sanitize_text_field( wp_unslash( $_REQUEST[ $name( 'settings_button_label' ) ] ) ) : '', ], ]; foreach ( [ 'welcome_title', 'welcome_message', 'allow', 'necessary_cookies_only', 'allow_selected', 'policy', 'title', 'message', 'close' ] as $text_key ) { $payload['texts'][ $text_key ] = isset( $_REQUEST[ $name( 'text_' . $text_key ) ] ) ? sanitize_textarea_field( wp_unslash( $_REQUEST[ $name( 'text_' . $text_key ) ] ) ) : ''; } // phpcs:enable WordPress.Security.NonceVerification.Recommended static::update_local_banner( $payload ); AS_CM_Services_Notice::add_notice( 'status-save-local-banner', __( 'Local banner settings saved.', 'adsimple-cookie-manager-for-wp' ) ); } /** * Get list of published pages for link selectors * * @return array */ protected static function get_available_pages() { $pages = get_pages( [ 'post_status' => 'publish' ] ); if ( empty( $pages ) ) { return []; } return array_map( function ( $page ) { return [ 'id' => (int) $page->ID, 'title' => get_the_title( $page ), 'url' => get_permalink( $page ), ]; }, $pages ); } public static function get_local_banner_theme_presets() { return [ 'theme1' => [ 'popup' => [ 'background' => '#ffffff', 'text' => '#333333', 'elements' => '#57ca85', 'link' => '#57ca85', 'checkbox' => '#ffffff', ], 'button' => [ 'background' => '#57ca85', 'text' => '#ffffff', ], 'button_necessary_cookies_only' => [ 'background' => '#fcb100', 'text' => '#ffffff', ], ], 'theme2' => [ 'popup' => [ 'background' => '#eaf7f7', 'text' => '#5c7291', 'elements' => '#56cbdb', 'link' => '#56cbdb', 'checkbox' => '#ffffff', ], 'button' => [ 'background' => '#56cbdb', 'text' => '#ffffff', ], 'button_necessary_cookies_only' => [ 'background' => '#fcb100', 'text' => '#ffffff', ], ], 'theme3' => [ 'popup' => [ 'background' => '#252e39', 'text' => '#ffffff', 'elements' => '#14a7d0', 'link' => '#14a7d0', 'checkbox' => '#ffffff', ], 'button' => [ 'background' => '#14a7d0', 'text' => '#ffffff', ], 'button_necessary_cookies_only' => [ 'background' => '#fcb100', 'text' => '#ffffff', ], ], 'theme4' => [ 'popup' => [ 'background' => '#000000', 'text' => '#00ff00', 'elements' => '#00ff00', 'link' => '#008000', 'checkbox' => '#000000', ], 'button' => [ 'background' => '#0f0', 'text' => '#000000', ], 'button_necessary_cookies_only' => [ 'background' => '#edf8f8', 'text' => '#000000', ], ], 'theme5' => [ 'popup' => [ 'background' => '#3937a3', 'text' => '#ffffff', 'elements' => '#e62576', 'link' => '#e62576', 'checkbox' => '#ffffff', ], 'button' => [ 'background' => '#e62576', 'text' => '#ffffff', ], 'button_necessary_cookies_only' => [ 'background' => '#7677ff', 'text' => '#ffffff', ], ], 'theme6' => [ 'popup' => [ 'background' => '#64386b', 'text' => '#ffcdfd', 'elements' => '#f8a8ff', 'link' => '#f8a8ff', 'checkbox' => '#000000', ], 'button' => [ 'background' => '#f8a8ff', 'text' => '#3f0045', ], 'button_necessary_cookies_only' => [ 'background' => '#ffffff', 'text' => '#585858', ], ], 'theme7' => [ 'popup' => [ 'background' => '#237afc', 'text' => '#ffffff', 'elements' => '#ffffff', 'link' => '#113c7d', 'checkbox' => '#237afc', ], 'button' => [ 'background' => '#ffffff', 'text' => '#237afc', ], 'button_necessary_cookies_only' => [ 'background' => '#89b8ff', 'text' => '#ffffff', ], ], 'theme8' => [ 'popup' => [ 'background' => '#aa0000', 'text' => '#ffdddd', 'elements' => '#ffffff', 'link' => '#ff0000', 'checkbox' => '#ff0000', ], 'button' => [ 'background' => '#ff0000', 'text' => '#ffdddd', ], 'button_necessary_cookies_only' => [ 'background' => '#d33039', 'text' => '#ffffff', ], ], 'theme9' => [ 'popup' => [ 'background' => '#383b75', 'text' => '#ffffff', 'elements' => '#f1d600', 'link' => '#f1d600', 'checkbox' => '#ffffff', ], 'button' => [ 'background' => '#f1d600', 'text' => '#ffffff', ], 'button_necessary_cookies_only' => [ 'background' => '#6b73c6', 'text' => '#ffffff', ], ], 'theme10' => [ 'popup' => [ 'background' => '#1d8a8a', 'text' => '#ffffff', 'elements' => '#62ffaa', 'link' => '#62ffaa', 'checkbox' => '#ffffff', ], 'button' => [ 'background' => '#62ffaa', 'text' => '#ffffff', ], 'button_necessary_cookies_only' => [ 'background' => '#ffffff', 'text' => '#585858', ], ], 'theme11' => [ 'popup' => [ 'background' => '#edeff5', 'text' => '#838391', 'elements' => '#4b81e8', 'link' => '#4b81e8', 'checkbox' => '#ffffff', ], 'button' => [ 'background' => '#4b81e8', 'text' => '#ffffff', ], 'button_necessary_cookies_only' => [ 'background' => '#fcb100', 'text' => '#ffffff', ], ], 'theme12' => [ 'popup' => [ 'background' => '#343c66', 'text' => '#cfcfe8', 'elements' => '#f71559', 'link' => '#f71559', 'checkbox' => '#ffffff', ], 'button' => [ 'background' => '#f71559', 'text' => '#ffffff', ], 'button_necessary_cookies_only' => [ 'background' => '#48548a', 'text' => '#ffffff', ], ], 'theme13' => [ 'popup' => [ 'background' => '#216942', 'text' => '#b2d192', 'elements' => '#afed71', 'link' => '#afed71', 'checkbox' => '#000000', ], 'button' => [ 'background' => '#afed71', 'text' => '#000000', ], 'button_necessary_cookies_only' => [ 'background' => '#ffffff', 'text' => '#585858', ], ], 'theme14' => [ 'popup' => [ 'background' => '#3c404d', 'text' => '#d6d6d6', 'elements' => '#8bed4f', 'link' => '#8bed4f', 'checkbox' => '#000000', ], 'button' => [ 'background' => '#8bed4f', 'text' => '#000000', 'border' => '#8bed4f', ], 'button_necessary_cookies_only' => [ 'background' => '#ffffff', 'text' => '#585858', ], ], 'theme15' => [ 'popup' => [ 'background' => '#eb6c44', 'text' => '#ffffff', 'elements' => '#f5d948', 'link' => '#f5d948', 'checkbox' => '#000000', ], 'button' => [ 'background' => '#f5d948', 'text' => '#000000', ], 'button_necessary_cookies_only' => [ 'background' => '#ffffff', 'text' => '#585858', ], ], 'theme16' => [ 'popup' => [ 'background' => '#efefef', 'text' => '#404040', 'elements' => '#8ec760', 'link' => '#8ec760', 'checkbox' => '#ffffff', ], 'button' => [ 'background' => '#8ec760', 'text' => '#ffffff', ], 'button_necessary_cookies_only' => [ 'background' => '#fcb100', 'text' => '#ffffff', ], ], ]; } protected static function get_local_banner_custom_color_defaults( $theme_key = 'theme1' ) { $themes = static::get_local_banner_theme_presets(); if ( ! isset( $themes[ $theme_key ] ) ) { $theme_key = 'theme1'; } $preset = $themes[ $theme_key ]; $popup_bg = static::normalize_hex_color_value( $preset['popup']['background'], '#ffffff' ); $popup_text = static::normalize_hex_color_value( $preset['popup']['text'], '#333333' ); $popup_elements = static::normalize_hex_color_value( $preset['popup']['elements'], '#57ca85' ); $popup_link = static::normalize_hex_color_value( $preset['popup']['link'], $popup_elements ); $popup_link_hover = isset( $preset['popup']['link_hover'] ) ? static::normalize_hex_color_value( $preset['popup']['link_hover'], $popup_link ) : static::normalize_hex_color_value( static::mix_hex_colors( $popup_link, '#000000', 0.12 ), $popup_link ); $checkbox_color = static::normalize_hex_color_value( $preset['popup']['checkbox'] ?? $popup_elements, $popup_elements ); $button_bg = static::normalize_hex_color_value( $preset['button']['background'], '#10b8ca' ); $button_text = static::normalize_hex_color_value( $preset['button']['text'], '#ffffff' ); $button_border = static::normalize_hex_color_value( $preset['button']['border'] ?? $button_bg, $button_bg ); $button_hover = static::normalize_hex_color_value( static::mix_hex_colors( $button_bg, '#000000', 0.15 ), $button_bg ); $button_text_hover = $button_text; $button_border_hover = $button_border; $secondary_bg = static::normalize_hex_color_value( $preset['button_necessary_cookies_only']['background'], '#fcb100' ); $secondary_text = static::normalize_hex_color_value( $preset['button_necessary_cookies_only']['text'], '#ffffff' ); $secondary_border = static::normalize_hex_color_value( $preset['button_necessary_cookies_only']['border'] ?? $secondary_bg, $secondary_bg ); $secondary_hover = static::normalize_hex_color_value( static::mix_hex_colors( $secondary_bg, '#ffffff', 0.2 ), $secondary_bg ); $secondary_text_hover = $secondary_text; $secondary_border_hover = $secondary_border; return [ 'popup' => $popup_bg, 'popupText' => $popup_text, 'popupElements' => $popup_elements, 'popupLink' => $popup_link, 'popupLinkHover' => $popup_link_hover, 'checkboxColor' => $checkbox_color, 'button' => $button_bg, 'buttonHover' => $button_hover, 'buttonText' => $button_text, 'buttonTextHover' => $button_text_hover, 'buttonBorder' => $button_border, 'buttonBorderHover' => $button_border_hover, 'necessaryCookiesOnlyButton' => $secondary_bg, 'necessaryCookiesOnlyButtonHover' => $secondary_hover, 'necessaryCookiesOnlyButtonText' => $secondary_text, 'necessaryCookiesOnlyButtonTextHover'=> $secondary_text_hover, 'necessaryCookiesOnlyButtonBorder' => $secondary_border, 'necessaryCookiesOnlyButtonBorderHover' => $secondary_border_hover, ]; } protected static function resolve_local_banner_css_variables( $local_options ) { $themes = static::get_local_banner_theme_presets(); $theme_key = isset( $local_options['theme'] ) ? sanitize_key( $local_options['theme'] ) : 'theme1'; if ( ! isset( $themes[ $theme_key ] ) ) { $theme_key = 'theme1'; } $custom_colors_enabled = ! empty( $local_options['custom_colors_enabled'] ); if ( $custom_colors_enabled ) { $theme_key = 'theme1'; } $preset = $themes[ $theme_key ]; $css = [ '--ascm-popup-bg' => static::normalize_hex_color_value( $preset['popup']['background'], '#ffffff' ), '--ascm-popup-text' => static::normalize_hex_color_value( $preset['popup']['text'], '#1f2937' ), '--ascm-popup-elements' => static::normalize_hex_color_value( $preset['popup']['elements'], '#57ca85' ), '--ascm-popup-link' => static::normalize_hex_color_value( $preset['popup']['link'], $preset['popup']['elements'] ), '--ascm-popup-link-hover' => static::normalize_hex_color_value( $preset['popup']['link_hover'] ?? $preset['popup']['link'], $preset['popup']['link'] ), '--ascm-checkbox-color' => static::normalize_hex_color_value( $preset['popup']['checkbox'] ?? $preset['popup']['elements'], $preset['popup']['elements'] ), '--ascm-button-primary-bg' => static::normalize_hex_color_value( $preset['button']['background'], '#10b8ca' ), '--ascm-button-primary-text' => static::normalize_hex_color_value( $preset['button']['text'], '#ffffff' ), '--ascm-button-primary-border' => static::normalize_hex_color_value( $preset['button']['border'] ?? $preset['button']['background'], $preset['button']['background'] ), '--ascm-button-secondary-bg' => static::normalize_hex_color_value( $preset['button_necessary_cookies_only']['background'], '#fcb100' ), '--ascm-button-secondary-text' => static::normalize_hex_color_value( $preset['button_necessary_cookies_only']['text'], '#ffffff' ), '--ascm-button-secondary-border' => static::normalize_hex_color_value( $preset['button_necessary_cookies_only']['border'] ?? $preset['button_necessary_cookies_only']['background'], $preset['button_necessary_cookies_only']['background'] ), ]; $custom_colors = isset( $local_options['custom_colors'] ) && is_array( $local_options['custom_colors'] ) ? $local_options['custom_colors'] : []; if ( $custom_colors_enabled ) { $custom_defaults = static::get_local_banner_custom_color_defaults( 'theme1' ); $custom_map = [ 'popup' => [ '--ascm-popup-bg' ], 'popupText' => [ '--ascm-popup-text' ], 'popupElements' => [ '--ascm-popup-elements' ], 'popupLink' => [ '--ascm-popup-link' ], 'popupLinkHover' => [ '--ascm-popup-link-hover' ], 'checkboxColor' => [ '--ascm-checkbox-color' ], 'button' => [ '--ascm-button-primary-bg' ], 'buttonHover' => [ '--ascm-button-primary-hover' ], 'buttonText' => [ '--ascm-button-primary-text' ], 'buttonTextHover' => [ '--ascm-button-primary-text-hover' ], 'buttonBorder' => [ '--ascm-button-primary-border' ], 'buttonBorderHover' => [ '--ascm-button-primary-border-hover' ], 'necessaryCookiesOnlyButton' => [ '--ascm-button-secondary-bg' ], 'necessaryCookiesOnlyButtonHover' => [ '--ascm-button-secondary-hover' ], 'necessaryCookiesOnlyButtonText' => [ '--ascm-button-secondary-text' ], 'necessaryCookiesOnlyButtonTextHover' => [ '--ascm-button-secondary-text-hover' ], 'necessaryCookiesOnlyButtonBorder' => [ '--ascm-button-secondary-border' ], 'necessaryCookiesOnlyButtonBorderHover' => [ '--ascm-button-secondary-border-hover' ], ]; foreach ( $custom_map as $custom_key => $variables ) { $raw_value = isset( $custom_colors[ $custom_key ] ) ? $custom_colors[ $custom_key ] : ''; if ( '' === trim( (string) $raw_value ) ) { $raw_value = isset( $custom_defaults[ $custom_key ] ) ? $custom_defaults[ $custom_key ] : ''; } if ( '' === trim( (string) $raw_value ) ) { continue; } $default_value = isset( $custom_defaults[ $custom_key ] ) ? $custom_defaults[ $custom_key ] : '#000000'; $value = static::normalize_hex_color_value( $raw_value, $default_value ); foreach ( (array) $variables as $variable ) { $css[ $variable ] = $value; } } } if ( empty( $custom_colors['popupLinkHover'] ) && empty( $preset['popup']['link_hover'] ) ) { $css['--ascm-popup-link-hover'] = static::mix_hex_colors( $css['--ascm-popup-link'], '#000000', 0.12 ); } $css['--ascm-popup-muted'] = static::mix_hex_colors( $css['--ascm-popup-text'], $css['--ascm-popup-bg'], 0.45 ); $css['--ascm-button-primary-border'] = $css['--ascm-button-primary-border'] ?? $css['--ascm-button-primary-bg']; $css['--ascm-button-primary-border-hover'] = $css['--ascm-button-primary-border-hover'] ?? $css['--ascm-button-primary-border']; $css['--ascm-button-primary-hover'] = $css['--ascm-button-primary-hover'] ?? static::mix_hex_colors( $css['--ascm-button-primary-bg'], '#000000', 0.15 ); $css['--ascm-button-primary-text-hover'] = $css['--ascm-button-primary-text-hover'] ?? $css['--ascm-button-primary-text']; $css['--ascm-button-secondary-border'] = $css['--ascm-button-secondary-border'] ?? $css['--ascm-button-secondary-bg']; $css['--ascm-button-secondary-border-hover'] = $css['--ascm-button-secondary-border-hover'] ?? $css['--ascm-button-secondary-border']; $css['--ascm-button-secondary-hover'] = $css['--ascm-button-secondary-hover'] ?? static::mix_hex_colors( $css['--ascm-button-secondary-bg'], '#ffffff', 0.2 ); $css['--ascm-button-secondary-text-hover'] = $css['--ascm-button-secondary-text-hover'] ?? $css['--ascm-button-secondary-text']; $css['--ascm-checkbox-color'] = $css['--ascm-checkbox-color'] ?? $css['--ascm-popup-elements']; $css['--ascm-border-color'] = static::mix_hex_colors( $css['--ascm-popup-bg'], $css['--ascm-popup-text'], 0.18 ); $css['--ascm-switch-track'] = static::mix_hex_colors( $css['--ascm-popup-bg'], $css['--ascm-popup-text'], 0.25 ); $css['--ascm-switch-track-active'] = $css['--ascm-popup-elements']; $css['--ascm-switch-thumb'] = '#FFFFFF'; $css['--ascm-badge-bg'] = $css['--ascm-popup-bg']; $css['--ascm-badge-text'] = $css['--ascm-button-secondary-text']; $css['--ascm-badge-icon-bg'] = $css['--ascm-popup-elements']; $css['--ascm-badge-icon-color'] = '#FFFFFF'; return $css; } protected static function normalize_hex_color_value( $value, $fallback ) { $color = sanitize_hex_color( $value ); if ( ! $color ) { $color = sanitize_hex_color( $fallback ); } if ( ! $color ) { $color = '#000000'; } if ( strlen( $color ) === 4 ) { $color = '#' . strtoupper( $color[1] . $color[1] . $color[2] . $color[2] . $color[3] . $color[3] ); } else { $color = strtoupper( $color ); } return $color; } protected static function mix_hex_colors( $color_one, $color_two, $ratio ) { $color_one = static::normalize_hex_color_value( $color_one, '#000000' ); $color_two = static::normalize_hex_color_value( $color_two, '#000000' ); $ratio = max( 0, min( 1, (float) $ratio ) ); $rgb_one = static::hex_to_rgb( $color_one ); $rgb_two = static::hex_to_rgb( $color_two ); $r = (int) round( $rgb_one['r'] * ( 1 - $ratio ) + $rgb_two['r'] * $ratio ); $g = (int) round( $rgb_one['g'] * ( 1 - $ratio ) + $rgb_two['g'] * $ratio ); $b = (int) round( $rgb_one['b'] * ( 1 - $ratio ) + $rgb_two['b'] * $ratio ); return sprintf( '#%02X%02X%02X', $r, $g, $b ); } protected static function hex_to_rgb( $hex ) { $hex = ltrim( $hex, '#' ); return [ 'r' => hexdec( substr( $hex, 0, 2 ) ), 'g' => hexdec( substr( $hex, 2, 2 ) ), 'b' => hexdec( substr( $hex, 4, 2 ) ), ]; } protected static function normalize_local_banner_structure( $data ) { if ( ! is_array( $data ) ) { return []; } // Ensure arrays if ( ! isset( $data['texts'] ) || ! is_array( $data['texts'] ) ) { $data['texts'] = []; } if ( ! isset( $data['links'] ) || ! is_array( $data['links'] ) ) { $data['links'] = []; } if ( ! isset( $data['links']['privacy_page_id'] ) ) { $data['links']['privacy_page_id'] = 0; } if ( ! isset( $data['links']['imprint_page_id'] ) ) { $data['links']['imprint_page_id'] = 0; } // Guard nested arrays that might be missing if ( isset( $data['custom_colors'] ) && ! is_array( $data['custom_colors'] ) ) { $data['custom_colors'] = []; } if ( isset( $data['popup_effects'] ) && ! is_array( $data['popup_effects'] ) ) { $data['popup_effects'] = []; } if ( ! isset( $data['settings_button'] ) || ! is_array( $data['settings_button'] ) ) { $data['settings_button'] = []; } if ( ! isset( $data['settings_button']['label'] ) ) { $data['settings_button']['label'] = ''; } if ( ! isset( $data['settings_button']['iconColor'] ) ) { $data['settings_button']['iconColor'] = ''; } if ( ! isset( $data['settings_button']['iconBackground'] ) ) { $data['settings_button']['iconBackground'] = ''; } if ( ! isset( $data['settings_button']['iconDesktopShow'] ) ) { $data['settings_button']['iconDesktopShow'] = '1'; } if ( ! isset( $data['settings_button']['offsetSettingsTabPosition'] ) ) { $data['settings_button']['offsetSettingsTabPosition'] = 0; } if ( ! isset( $data['cookie_categories'] ) || ! is_array( $data['cookie_categories'] ) ) { $data['cookie_categories'] = []; } if ( ! isset( $data['visibility'] ) || ! is_array( $data['visibility'] ) ) { $data['visibility'] = []; } if ( ! isset( $data['features'] ) || ! is_array( $data['features'] ) ) { $data['features'] = []; } if ( ! isset( $data['custom_colors_enabled'] ) ) { $data['custom_colors_enabled'] = false; } return $data; } }