'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(); } ?>

410gone


[cmp410gone_manage_cookies label=""]
'; echo '
'; echo '

' . esc_html($section['title']) . '

'; echo '
'; if (!empty($section['callback'])) { echo '
'; call_user_func($section['callback'], $section); echo '
'; } if (!empty($wp_settings_fields[$page][$section_id])) { echo ''; do_settings_fields($page, $section_id); echo ''; } echo ''; } public static function section_design() { $s = self::get_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') . '

'; echo '

WP Rocket: ' . esc_html__('exclude', '410gone-consent-manager') . ' cmp.js ' . esc_html__('from “Delay JS execution”.', '410gone-consent-manager') . '

'; } public static function section_advanced() { echo '

' . 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']) ); ?>









self::COOKIE_NAME, 'legacyCookieName' => self::LEGACY_COOKIE_NAME, 'ttlDays' => (int)$s['ttl_days'], 'privacyUrl' => esc_url_raw($s['privacy_url']), 'cookiePolicyUrl' => esc_url_raw($s['cookie_policy_url']), 'debug' => (bool)$s['debug'], 'forceShow' => (bool)$s['force_show'], ]); } public static function render_banner_markup() { static $done = false; if ($done) { return; } $done = true; $s = self::get_settings(); if (!(int)$s['enable']) { return; } $has_cookie = self::has_consent_cookie(); $aria_hidden = $has_cookie && !(int)$s['force_show'] ? 'true' : 'false'; $privacy = !empty($s['privacy_url']) ? esc_url($s['privacy_url']) : ''; $cookies = !empty($s['cookie_policy_url']) ? esc_url($s['cookie_policy_url']) : ''; ?>
__('Manage my cookies', '410gone-consent-manager')], $atts, self::SHORTCODE); $label = esc_html($atts['label']); return '' . $label . ''; } private static function translate_settings($settings) { $translatable = [ 'banner_title', 'banner_text', 'btn_accept', 'btn_reject', 'btn_customize', 'btn_save', 'modal_title', 'modal_desc_essentials', 'modal_desc_analytics', 'modal_desc_retargeting', 'privacy_url', 'cookie_policy_url', ]; foreach ($translatable as $key) { if (!isset($settings[$key])) { continue; } $settings[$key] = self::translate_text($key, $settings[$key]); $settings[$key] = apply_filters('cmp410gone_translate_setting', $settings[$key], $key, $settings); } return $settings; } private static function register_translation_strings($settings) { $fields = [ 'banner_title' => __('Banner title', '410gone-consent-manager'), 'banner_text' => __('Banner text', '410gone-consent-manager'), 'btn_accept' => __('Accept button', '410gone-consent-manager'), 'btn_reject' => __('Reject button', '410gone-consent-manager'), 'btn_customize' => __('Customize button', '410gone-consent-manager'), 'btn_save' => __('Save button', '410gone-consent-manager'), 'modal_title' => __('Customization modal title', '410gone-consent-manager'), 'modal_desc_essentials' => __('Essentials subtitle', '410gone-consent-manager'), 'modal_desc_analytics' => __('Analytics subtitle', '410gone-consent-manager'), 'modal_desc_retargeting' => __('Retargeting subtitle', '410gone-consent-manager'), 'privacy_url' => __('Privacy policy URL', '410gone-consent-manager'), 'cookie_policy_url' => __('Cookie policy URL', '410gone-consent-manager'), ]; foreach ($fields as $key => $label) { if (!isset($settings[$key])) { continue; } if (function_exists('pll_register_string')) { pll_register_string('cmp410gone_' . $key, $settings[$key], 'CMP 410gone', false); } if (has_filter('wpml_register_single_string')) { do_action('wpml_register_single_string', 'CMP 410gone', 'cmp410gone_' . $key, $settings[$key]); } } } private static function translate_text($key, $value) { $translated = $value; if (function_exists('pll__')) { $translated = pll__($translated); } elseif (has_filter('wpml_translate_single_string')) { $translated = apply_filters('wpml_translate_single_string', $translated, 'CMP 410gone', 'cmp410gone_' . $key); } return $translated; } }