'denied', 'ad_storage' => 'denied', 'ad_user_data' => 'denied', 'ad_personalization' => 'denied', ]; } private static function get_raw_consent_cookie() { $raw = filter_input(INPUT_COOKIE, self::COOKIE_NAME, FILTER_SANITIZE_SPECIAL_CHARS); if (empty($raw)) { $raw = filter_input(INPUT_COOKIE, self::LEGACY_COOKIE_NAME, FILTER_SANITIZE_SPECIAL_CHARS); } return $raw; } private static function has_consent_cookie() { $raw = self::get_raw_consent_cookie(); if (empty($raw)) { return false; } $raw = wp_kses(wp_unslash((string)$raw), []); $data = json_decode($raw, true); if (!is_array($data)) { return false; } $keys = array_keys(self::consent_mode_defaults()); foreach ($keys as $key) { if (isset($data[$key]) && in_array($data[$key], ['granted', 'denied'], true)) { return true; } } if (isset($data['analytics']) && is_bool($data['analytics'])) { return true; } if (isset($data['retargeting']) && is_bool($data['retargeting'])) { return true; } return false; } private static function consent_mode_from_cookie() { $defaults = self::consent_mode_defaults(); $raw = self::get_raw_consent_cookie(); if (empty($raw)) { return $defaults; } $raw = wp_kses(wp_unslash((string)$raw), []); $data = json_decode($raw, true); if (!is_array($data)) { return $defaults; } $consent = $defaults; foreach ($defaults as $key => $value) { if (isset($data[$key]) && in_array($data[$key], ['granted', 'denied'], true)) { $consent[$key] = $data[$key]; } } if (isset($data['analytics']) && is_bool($data['analytics'])) { $consent['analytics_storage'] = $data['analytics'] ? 'granted' : 'denied'; } if (isset($data['retargeting']) && is_bool($data['retargeting'])) { $value = $data['retargeting'] ? 'granted' : 'denied'; $consent['ad_storage'] = $value; $consent['ad_user_data'] = $value; $consent['ad_personalization'] = $value; } return $consent; } public static function init() { add_action('admin_menu', [__CLASS__, 'admin_menu']); add_action('admin_init', [__CLASS__, 'register_settings']); add_action('admin_enqueue_scripts', [__CLASS__, 'enqueue_admin_assets']); add_filter('plugin_action_links_' . plugin_basename(CMP410GONE_PLUGIN_FILE), [__CLASS__, 'plugin_action_links']); add_filter('plugin_row_meta', [__CLASS__, 'filter_plugin_row_meta'], 10, 2); add_action('wp_enqueue_scripts', [__CLASS__, 'enqueue_head_scripts'], 1); add_action('wp_enqueue_scripts', [__CLASS__, 'enqueue_assets']); add_action('wp_footer', [__CLASS__, 'render_banner_markup'], 30); add_shortcode(self::SHORTCODE, [__CLASS__, 'shortcode_manage_cookies']); } public static function defaults() { return [ 'enable' => 1, 'gtm_id' => '', 'consent_wait_for_update_ms' => 500, 'privacy_url' => '', 'cookie_policy_url' => '', 'banner_title' => __('🍪 Cookie preferences', '410gone-consent-manager'), 'banner_text' => __('We use essential cookies to run the site and, if you accept, cookies for analytics and advertising retargeting.', '410gone-consent-manager'), 'btn_accept' => __('Accept', '410gone-consent-manager'), 'btn_reject' => __('Reject', '410gone-consent-manager'), 'btn_customize' => __('Customize', '410gone-consent-manager'), 'btn_save' => __('Save', '410gone-consent-manager'), 'modal_title' => __('Preferences', '410gone-consent-manager'), 'modal_desc_essentials' => __('Required for the site to function (always active).', '410gone-consent-manager'), 'modal_desc_analytics' => __('Analytics measurement (e.g. Google Analytics 4).', '410gone-consent-manager'), 'modal_desc_retargeting' => __('Personalized ads (managed via GTM).', '410gone-consent-manager'), 'background_color' => '#ffffff', 'text_color' => '#0b1621', 'accept_btn_color' => '#00ceff', 'accept_btn_text_color' => '#001018', 'customize_btn_color' => '#f5f5f5', 'customize_btn_text_color' => '#111111', 'ttl_days' => 180, 'debug' => 0, 'force_show' => 0, ]; } public static function get_settings() { $opts = get_option(self::OPTION_KEY, null); if (!is_array($opts) || empty($opts)) { $legacy = get_option(self::LEGACY_OPTION_KEY, []); $opts = is_array($legacy) ? $legacy : []; } $settings = array_merge(self::defaults(), is_array($opts) ? $opts : []); return self::translate_settings($settings); } public static function plugin_action_links($links) { $settings_url = admin_url('options-general.php?page=' . self::PAGE_SLUG); return array_merge(['settings' => '' . esc_html(__('Settings', '410gone-consent-manager')) . ''], $links); } public static function filter_plugin_row_meta($links, $file) { if ($file !== plugin_basename(CMP410GONE_PLUGIN_FILE)) { return $links; } foreach ($links as $index => $link) { if (strpos($link, 'plugin-install.php') !== false || strpos($link, 'plugin-information') !== false) { unset($links[$index]); } } return $links; } public static function admin_menu() { add_options_page(__('🍪 410Gone Consent Manager — Settings', '410gone-consent-manager'), __('🍪 410Gone Consent Manager', '410gone-consent-manager'), 'manage_options', self::PAGE_SLUG, [__CLASS__, 'settings_page']); } public static function register_settings() { register_setting('cmp410gone_group', self::OPTION_KEY, [ 'type' => 'array', 'sanitize_callback' => [__CLASS__, 'sanitize_settings'], 'default' => self::defaults(), ]); add_settings_section('cmp410gone_design', __('Design', '410gone-consent-manager'), [__CLASS__, 'section_design'], self::PAGE_SLUG); add_settings_field('enable', __('Enable CMP', '410gone-consent-manager'), [__CLASS__, 'field_enable'], self::PAGE_SLUG, 'cmp410gone_design'); add_settings_field('accept_btn_color', __('Accept button color', '410gone-consent-manager'), [__CLASS__, 'field_accept_btn_color'], self::PAGE_SLUG, 'cmp410gone_design'); add_settings_field('accept_btn_text_color', __('Accept button text color', '410gone-consent-manager'), [__CLASS__, 'field_accept_btn_text_color'], self::PAGE_SLUG, 'cmp410gone_design'); add_settings_field('background_color', __('Background color', '410gone-consent-manager'), [__CLASS__, 'field_background_color'], self::PAGE_SLUG, 'cmp410gone_design'); add_settings_field('text_color', __('Text color', '410gone-consent-manager'), [__CLASS__, 'field_text_color'], self::PAGE_SLUG, 'cmp410gone_design'); add_settings_field('customize_btn_color', __('Customize button color', '410gone-consent-manager'), [__CLASS__, 'field_customize_btn_color'], self::PAGE_SLUG, 'cmp410gone_design'); add_settings_field('customize_btn_text_color', __('Customize button text color', '410gone-consent-manager'), [__CLASS__, 'field_customize_btn_text_color'], self::PAGE_SLUG, 'cmp410gone_design'); add_settings_section('cmp410gone_labels', __('Labels', '410gone-consent-manager'), [__CLASS__, 'section_labels'], self::PAGE_SLUG); add_settings_field('privacy_url', __('Privacy policy URL', '410gone-consent-manager'), [__CLASS__, 'field_privacy_url'], self::PAGE_SLUG, 'cmp410gone_labels'); add_settings_field('cookie_policy_url', __('Cookie policy URL (optional)', '410gone-consent-manager'), [__CLASS__, 'field_cookie_policy_url'], self::PAGE_SLUG, 'cmp410gone_labels'); add_settings_field('banner_title', __('Banner title', '410gone-consent-manager'), [__CLASS__, 'field_banner_title'], self::PAGE_SLUG, 'cmp410gone_labels'); add_settings_field('banner_text', __('Banner text', '410gone-consent-manager'), [__CLASS__, 'field_banner_text'], self::PAGE_SLUG, 'cmp410gone_labels'); add_settings_field('btn_labels', __('Button labels', '410gone-consent-manager'), [__CLASS__, 'field_btn_labels'], self::PAGE_SLUG, 'cmp410gone_labels'); add_settings_field('modal_labels', __('Modal labels', '410gone-consent-manager'), [__CLASS__, 'field_modal_labels'], self::PAGE_SLUG, 'cmp410gone_labels'); add_settings_section('cmp410gone_tracking', __('Tracking & configuration', '410gone-consent-manager'), [__CLASS__, 'section_tracking'], self::PAGE_SLUG); add_settings_field('gtm_id', __('GTM container ID', '410gone-consent-manager'), [__CLASS__, 'field_gtm_id'], self::PAGE_SLUG, 'cmp410gone_tracking'); add_settings_field('consent_wait_for_update_ms', __('Consent wait_for_update (ms)', '410gone-consent-manager'), [__CLASS__, 'field_wait'], self::PAGE_SLUG, 'cmp410gone_tracking'); add_settings_section('cmp410gone_advanced', __('Advanced', '410gone-consent-manager'), [__CLASS__, 'section_advanced'], self::PAGE_SLUG); add_settings_field('ttl_days', __('Consent retention (days)', '410gone-consent-manager'), [__CLASS__, 'field_ttl_days'], self::PAGE_SLUG, 'cmp410gone_advanced'); add_settings_field('debug', __('Debug console', '410gone-consent-manager'), [__CLASS__, 'field_debug'], self::PAGE_SLUG, 'cmp410gone_advanced'); add_settings_field('force_show', __('Force display (testing)', '410gone-consent-manager'), [__CLASS__, 'field_force_show'], self::PAGE_SLUG, 'cmp410gone_advanced'); } public static function sanitize_settings($in) { $d = self::defaults(); $out = []; $out['enable'] = isset($in['enable']) ? (int)!!$in['enable'] : $d['enable']; $out['debug'] = isset($in['debug']) ? (int)!!$in['debug'] : $d['debug']; $out['force_show'] = isset($in['force_show']) ? (int)!!$in['force_show'] : $d['force_show']; $gtm = isset($in['gtm_id']) ? strtoupper(trim((string)$in['gtm_id'])) : ''; if ($gtm !== '' && !preg_match('/^GTM-[A-Z0-9]+$/', $gtm)) { $gtm = ''; } $out['gtm_id'] = $gtm; $wait = isset($in['consent_wait_for_update_ms']) ? (int)$in['consent_wait_for_update_ms'] : $d['consent_wait_for_update_ms']; if ($wait < 0) { $wait = 0; } if ($wait > 5000) { $wait = 5000; } $out['consent_wait_for_update_ms'] = $wait; $out['privacy_url'] = isset($in['privacy_url']) ? esc_url_raw((string)$in['privacy_url']) : $d['privacy_url']; $out['cookie_policy_url'] = isset($in['cookie_policy_url']) ? esc_url_raw((string)$in['cookie_policy_url']) : $d['cookie_policy_url']; $out['banner_title'] = isset($in['banner_title']) ? sanitize_text_field((string)$in['banner_title']) : $d['banner_title']; $out['banner_text'] = isset($in['banner_text']) ? wp_kses_post((string)$in['banner_text']) : $d['banner_text']; $out['btn_accept'] = isset($in['btn_accept']) ? sanitize_text_field((string)$in['btn_accept']) : $d['btn_accept']; $out['btn_reject'] = isset($in['btn_reject']) ? sanitize_text_field((string)$in['btn_reject']) : $d['btn_reject']; $out['btn_customize'] = isset($in['btn_customize']) ? sanitize_text_field((string)$in['btn_customize']) : $d['btn_customize']; $out['btn_save'] = isset($in['btn_save']) ? sanitize_text_field((string)$in['btn_save']) : $d['btn_save']; $out['modal_title'] = isset($in['modal_title']) ? sanitize_text_field((string)$in['modal_title']) : $d['modal_title']; $out['modal_desc_essentials'] = isset($in['modal_desc_essentials']) ? sanitize_text_field((string)$in['modal_desc_essentials']) : $d['modal_desc_essentials']; $out['modal_desc_analytics'] = isset($in['modal_desc_analytics']) ? sanitize_text_field((string)$in['modal_desc_analytics']) : $d['modal_desc_analytics']; $out['modal_desc_retargeting'] = isset($in['modal_desc_retargeting']) ? sanitize_text_field((string)$in['modal_desc_retargeting']) : $d['modal_desc_retargeting']; $bg = isset($in['background_color']) ? trim((string)$in['background_color']) : $d['background_color']; if (!preg_match('/^#([A-Fa-f0-9]{6})$/', $bg)) { $bg = $d['background_color']; } $out['background_color'] = $bg; $text = isset($in['text_color']) ? trim((string)$in['text_color']) : $d['text_color']; if (!preg_match('/^#([A-Fa-f0-9]{6})$/', $text)) { $text = $d['text_color']; } $out['text_color'] = $text; $col = isset($in['accept_btn_color']) ? trim((string)$in['accept_btn_color']) : $d['accept_btn_color']; if (!preg_match('/^#([A-Fa-f0-9]{6})$/', $col)) { $col = $d['accept_btn_color']; } $out['accept_btn_color'] = $col; $tcol = isset($in['accept_btn_text_color']) ? trim((string)$in['accept_btn_text_color']) : $d['accept_btn_text_color']; if (!preg_match('/^#([A-Fa-f0-9]{6})$/', $tcol)) { $tcol = $d['accept_btn_text_color']; } $out['accept_btn_text_color'] = $tcol; $custom_col = isset($in['customize_btn_color']) ? trim((string)$in['customize_btn_color']) : $d['customize_btn_color']; if (!preg_match('/^#([A-Fa-f0-9]{6})$/', $custom_col)) { $custom_col = $d['customize_btn_color']; } $out['customize_btn_color'] = $custom_col; $custom_tcol = isset($in['customize_btn_text_color']) ? trim((string)$in['customize_btn_text_color']) : $d['customize_btn_text_color']; if (!preg_match('/^#([A-Fa-f0-9]{6})$/', $custom_tcol)) { $custom_tcol = $d['customize_btn_text_color']; } $out['customize_btn_text_color'] = $custom_tcol; $ttl = isset($in['ttl_days']) ? (int)$in['ttl_days'] : $d['ttl_days']; if ($ttl < 1) { $ttl = 1; } if ($ttl > 3650) { $ttl = 3650; } $out['ttl_days'] = $ttl; self::register_translation_strings($out); return $out; } public static function enqueue_admin_assets($hook) { if ($hook !== 'settings_page_' . self::PAGE_SLUG) { return; } $base = plugin_dir_path(CMP410GONE_PLUGIN_FILE); $url = plugin_dir_url(CMP410GONE_PLUGIN_FILE); $css_ver = file_exists($base . 'assets/admin.css') ? (string)filemtime($base . 'assets/admin.css') : '1.0.0'; $js_ver = file_exists($base . 'assets/admin.js') ? (string)filemtime($base . 'assets/admin.js') : '1.0.0'; wp_enqueue_style(self::ADMIN_STYLE_HANDLE, $url . 'assets/admin.css', [], $css_ver); wp_enqueue_script('cmp410gone-admin', $url . 'assets/admin.js', [], $js_ver, true); } public static function settings_page() { if (!current_user_can('manage_options')) { return; } $page = self::PAGE_SLUG; // Fallback in case hooks didn’t register sections (e.g., custom admin flows). if (empty($GLOBALS['wp_settings_sections'][$page])) { self::register_settings(); } ?>
'; echo '' . esc_html__('Customize banner colors and preview desktop/mobile rendering.', '410gone-consent-manager') . '
'; self::render_preview_block($s, 'design'); } public static function section_labels() { $s = self::get_settings(); echo '' . esc_html__('Adjust texts and links. Labels remain compatible with Polylang/WPML and custom filters.', '410gone-consent-manager') . '
'; self::render_preview_block($s, 'labels'); } public static function section_tracking() { echo '' . esc_html__('GTM can load early, but Consent Mode v2 starts as', '410gone-consent-manager') . ' denied ' . esc_html__('and updates based on the user choice.', '410gone-consent-manager') . '
WP Rocket: ' . esc_html__('exclude', '410gone-consent-manager') . ' cmp.js ' . esc_html__('from “Delay JS execution”.', '410gone-consent-manager') . '
' . esc_html__('Options for debugging, forced tests, and consent retention.', '410gone-consent-manager') . '
'; } private static function render_preview_block($settings, $context) { $style = sprintf( '--cmp410-accept-bg:%1$s;--cmp410-accept-fg:%2$s;--cmp410-customize-bg:%3$s;--cmp410-customize-fg:%4$s;--cmp410-background:%5$s;--cmp410-foreground:%6$s;', esc_attr($settings['accept_btn_color']), esc_attr($settings['accept_btn_text_color']), esc_attr($settings['customize_btn_color']), esc_attr($settings['customize_btn_text_color']), esc_attr($settings['background_color']), esc_attr($settings['text_color']) ); ?>