hooks(); } /** * Hooks. * * @return void */ public function hooks() { add_action( 'wp_footer', array( $this, 'maybe_output_banner' ) ); } /** * Check if the banner should be hidden. * * @return bool */ protected function should_hide_banner() { return false; } /** * Output the banner if enabled. * * @return void */ public function maybe_output_banner() { if ( ! $this->is_enabled() ) { return; } // Don't load in legacy widget preview in the block editor. if ( defined( 'REST_REQUEST' ) && REST_REQUEST ) { return; } // Don't load in the customizer preview. if ( is_customize_preview() ) { return; } // Filter to control whether the banner should be output. Child classes can override should_hide_banner(). $should_output = ! $this->should_hide_banner(); if ( ! apply_filters( 'wpconsent_banner_output', $should_output ) ) { return; } $this->output_banner(); } /** * Check if the banner is enabled. * * @return bool */ public function is_enabled() { return wpconsent()->settings->get_option( 'enable_consent_banner' ); } /** * Output the banner with proper escaping. * * @return void */ public function output_banner() { // Allowed tags we start with the ones from wp_kses_post. $allowed_tags = wp_kses_allowed_html( 'post' ); // Add the SVG tags from our icons. $allowed_tags = array_merge( $allowed_tags, wpconsent_get_icon_allowed_tags() ); // Let's allow tabindex attribute. $allowed_tags['div']['tabindex'] = true; $allowed_tags['div']['part'] = true; $allowed_tags['button']['part'] = true; $allowed_tags['h2']['part'] = true; $allowed_tags['label']['part'] = true; $allowed_tags['span']['part'] = true; $allowed_tags['input']['part'] = true; $allowed_tags['p']['part'] = true; $allowed_tags['img']['part'] = true; // Get colors and create CSS variables. $colors = $this->get_color_settings(); $css_vars = $this->get_css_variables( $colors ); // Create the Shadow DOM container with CSS variables. echo '
'; echo ''; // Create a template that contains both styles and HTML. echo ''; echo '
'; } /** * Get CSS variables string from colors array. * * @param array $colors Color settings. * * @return string */ public function get_css_variables( $colors ) { $vars = array( '--wpconsent-z-index: 900000;', '--wpconsent-background: ' . $colors['background'] . ';', '--wpconsent-text: ' . $colors['text'] . ';', '--wpconsent-outline-color: ' . $this->hex_to_rgba( $colors['text'], 0.2 ) . ';', '--wpconsent-accept-bg: ' . $colors['accept_bg'] . ';', '--wpconsent-cancel-bg: ' . $colors['cancel_bg'] . ';', '--wpconsent-preferences-bg: ' . $colors['preferences_bg'] . ';', '--wpconsent-accept-color: ' . $colors['accept_color'] . ';', '--wpconsent-cancel-color: ' . $colors['cancel_color'] . ';', '--wpconsent-preferences-color: ' . $colors['preferences_color'] . ';', '--wpconsent-font-size: ' . $colors['font_size'] . ';', ); return implode( ' ', $vars ); } /** * Convert hex color to rgba. * * @param string $hex Hex color code. * @param float $opacity Opacity value. * * @return string */ private function hex_to_rgba( $hex, $opacity ) { $hex = str_replace( '#', '', $hex ); // Convert shorthand hex to full hex. if ( strlen( $hex ) === 3 ) { $hex = $hex[0] . $hex[0] . $hex[1] . $hex[1] . $hex[2] . $hex[2]; } // Convert hex to rgb. $r = hexdec( substr( $hex, 0, 2 ) ); $g = hexdec( substr( $hex, 2, 2 ) ); $b = hexdec( substr( $hex, 4, 2 ) ); return "rgba({$r}, {$g}, {$b}, {$opacity})"; } /** * Get the banner markup. * * @return string */ public function get_banner() { $font_size = wpconsent()->settings->get_option( 'banner_font_size', '16px' ); $button_size = wpconsent()->settings->get_option( 'banner_button_size', 'regular' ); $button_corner = wpconsent()->settings->get_option( 'banner_button_corner', 'slightly-rounded' ); $button_type = wpconsent()->settings->get_option( 'banner_button_type', 'filled' ); $button_order = wpconsent()->settings->get_option( 'button_order', array( 'accept', 'cancel', 'preferences', ) ); $banner_layout = wpconsent()->settings->get_option( 'banner_layout', 'long' ); $banner_position = wpconsent()->settings->get_option( 'banner_position', 'top' ); $position_class = ! empty( $banner_position ) ? 'wpconsent-banner-' . esc_attr( $banner_layout ) . '-' . esc_attr( $banner_position ) : ''; $logo = wpconsent()->settings->get_option( 'banner_logo', '' ); $banner_classes = apply_filters( 'wpconsent_banner_classes', array( 'wpconsent-banner-holder', 'wpconsent-banner-' . $banner_layout, $position_class, ) ); $html = '';// .wpconsent-banner-holder return $html; } /** * Get the top buttons for the banner. * * @return string */ public function get_banner_top_buttons() { // Check if close button is disabled in settings. if ( wpconsent()->settings->get_option( 'disable_close_button' ) ) { return ''; } $close_text = esc_attr__( 'Close', 'wpconsent-cookies-banner-privacy-suite' ); return ''; } /** * Get the color settings. * * @return array */ public function get_color_settings() { return array( 'background' => wpconsent()->settings->get_option( 'banner_background_color', '#FFFFFF' ), 'text' => wpconsent()->settings->get_option( 'banner_text_color', '#000000' ), 'button_text' => wpconsent()->settings->get_option( 'banner_button_text_color', '#FFFFFF' ), 'accept_bg' => wpconsent()->settings->get_option( 'banner_accept_bg', '#0073AA' ), 'cancel_bg' => wpconsent()->settings->get_option( 'banner_cancel_bg', '#0073AA' ), 'preferences_bg' => wpconsent()->settings->get_option( 'banner_preferences_bg', '#0073AA' ), 'accept_color' => wpconsent()->settings->get_option( 'banner_accept_color', '#FFFFFF' ), 'cancel_color' => wpconsent()->settings->get_option( 'banner_cancel_color', '#FFFFFF' ), 'preferences_color' => wpconsent()->settings->get_option( 'banner_preferences_color', '#FFFFFF' ), 'font_size' => wpconsent()->settings->get_option( 'banner_font_size', '16px' ), ); } /** * Get the preferences modal. * * @return string */ public function get_preferences_modal() { $categories = wpconsent()->cookies->get_categories(); $accept_button_text = wpconsent()->settings->get_option( 'accept_button_text', wpconsent()->strings->get_string( 'accept_button_text' ) ); $logo = wpconsent()->settings->get_option( 'banner_logo', '' ); $cookie_policy_title = wpconsent()->settings->get_option( 'cookie_policy_title', wpconsent()->strings->get_string( 'cookie_policy_title' ) ); $preferences_panel_title = wpconsent()->settings->get_option( 'preferences_panel_title', wpconsent()->strings->get_string( 'preferences_panel_title' ) ); $default_allow = wpconsent()->settings->get_option( 'default_allow', 0 ); $preferences_classes = apply_filters( 'wpconsent_preferences_modal_classes', array( 'wpconsent-preferences-modal', ) ); $html = ''; // #wpconsent-preferences-modal return $html; } /** * Add GPC override acknowledgment to preference panel * * @return string HTML for the GPC override toggle. */ public function add_gpc_override_toggle() { // Only add if respect_gpc is enabled. if ( ! wpconsent()->settings->get_option( 'respect_gpc', 0 ) ) { return; } $gpc_message = wpconsent()->settings->get_option( 'gpc_override_message', wpconsent()->strings->get_string( 'gpc_override_message' ) ); $content = ''; $content .= ''; // .wpconsent-gpc-override-container. return $content; } /** * Add GPC toast notification to preference panel * * @return void. */ public function add_gpc_toast_notification() { // Only add if respect_gpc is enabled. if ( ! wpconsent()->settings->get_option( 'respect_gpc', 0 ) ) { return; } $gpc_toast_message = wpconsent()->settings->get_option( 'gpc_toast_message', wpconsent()->strings->get_string( 'gpc_toast_message' ) ); echo ''; // .wpconsent-gpc-toast. } /** * Get cookies from cache or database * * @return array */ private function get_cookies_from_cache() { $cache_key = 'wpconsent_preference_cookies'; // Allow cache key to be filtered (e.g., for multilanguage support). $cache_key = apply_filters( 'wpconsent_preference_cookies_cache_key', $cache_key ); $cookies = get_transient( $cache_key ); if ( false === $cookies ) { $categories = wpconsent()->cookies->get_categories(); $cookies = array(); foreach ( $categories as $category_slug => $category ) { $category_id = $category['id']; $cookies[ $category_id ] = array( 'cookies' => array(), 'services' => array(), ); $category_cookies = wpconsent()->cookies->get_cookies_by_category( $category_id ); $services = wpconsent()->cookies->get_services_by_category( $category_id ); if ( ! empty( $category_cookies ) ) { foreach ( $category_cookies as $cookie ) { // Let's skip here the cookies that are not associated with this category directly and are associated with a service. if ( ! in_array( $category_id, $cookie['categories'], true ) ) { continue; } // Add cookie to the category's cookie array. $cookies[ $category_id ]['cookies'][] = $cookie; } } // Process services and their cookies. if ( ! empty( $services ) ) { foreach ( $services as $service ) { $service_slug = sanitize_title( $service['name'] ); $cookies[ $category_id ]['services'][ $service_slug ] = array( 'name' => $service['name'], 'description' => $service['description'], 'service_url' => $service['service_url'], 'cookies' => array(), ); // We already loaded all the cookies for this category so we need to simply add the ones for this service. if ( ! empty( $category_cookies ) ) { foreach ( $category_cookies as $cookie_for_service ) { if ( ! in_array( $service['id'], $cookie_for_service['categories'], true ) ) { continue; } $cookies[ $category_id ]['services'][ $service_slug ]['cookies'][] = $cookie_for_service; } } } } } // Cache for 24 hours. set_transient( $cache_key, $cookies, DAY_IN_SECONDS ); } return apply_filters( 'wpconsent_get_cookies_from_cache', $cookies ); } /** * Render a single category item in the preferences modal. * * @param string $category_slug The category slug. * @param array $category The category data. * @param array $all_cookies All cookies data. * @param bool $default_allow Default allow setting. * * @return string HTML for the category item. */ private function render_category_item( $category_slug, $category, $all_cookies, $default_allow ) { $cookies = isset( $all_cookies[ $category['id'] ] ) ? $all_cookies[ $category['id'] ] : array(); $html = ''; // .wpconsent-cookie-category return $html; } /** * Generate the cookies accordioncontent for a category * * @param array $cookies The cookies array for each category to display. * @param string $category_name The name of the category. * @param string $category_slug The slug of the category. * * @return string */ private function get_cookies_content_by_category( $cookies, $category_name = '', $category_slug = '' ) { if ( empty( $cookies ) ) { return ''; } $html = ''; $default_allow = wpconsent()->settings->get_option( 'default_allow', false ); if ( ! empty( $cookies['cookies'] ) ) { $html .= $this->get_cookies_table_by_category( $cookies['cookies'] ); } // First display services and their cookies. if ( ! empty( $cookies['services'] ) ) { foreach ( $cookies['services'] as $service_slug => $service ) { $html .= ''; // .wpconsent-cookie-service } else { // Regular service rendering with accordion and checkbox. $html .= ''; // .wpconsent-cookie-category-text $html .= ''; // .wpconsent-cookie-category-checkbox $html .= ''; // .wpconsent-preferences-accordion-header $html .= '
'; if ( ! empty( $service['description'] ) ) { $html .= '

' . wp_kses_post( $service['description'] ) . '

'; } // Add service URL to description if it exists. if ( ! empty( $service['service_url'] ) ) { $service_url_label = wpconsent()->settings->get_option( 'cookie_table_header_service_url', wpconsent()->strings->get_string( 'cookie_table_header_service_url' ) ); $html .= '

' . sprintf( /* translators: %1$s: Service URL label, %2$s: Service URL */ esc_html__( '%1$s: %2$s', 'wpconsent-cookies-banner-privacy-suite' ), esc_html( $service_url_label ), '' . esc_html( wp_parse_url( $service['service_url'], PHP_URL_HOST ) ) . ' ' . esc_html__( '(opens in a new window)', 'wpconsent-cookies-banner-privacy-suite' ) . '' ) . '

'; } $html .= $this->get_cookies_table_by_category( $service['cookies'] ); $html .= '
'; // .wpconsent-preferences-accordion-content $html .= ''; // .wpconsent-cookie-service } } } return $html; } /** * Generate the cookies table for a category * * @param array $cookies The cookies to display. * * @return string */ private function get_cookies_table_by_category( $cookies ) { if ( empty( $cookies ) ) { return ''; } $html = '
'; $html .= '
'; $html .= ''; $html .= ''; $html .= ''; $html .= '
'; // .wpconsent-preferences-list-header foreach ( $cookies as $cookie ) { $html .= '
'; $html .= ''; $html .= ''; $html .= ''; $html .= '
'; // .wpconsent-preferences-list-item } $html .= '
'; // .wpconsent-preferences-cookies-list return $html; } /** * Output the powered by WPConsent logo. * * @return string */ public function powered_by() { if ( wpconsent()->settings->get_option( 'hide_powered_by' ) ) { return ''; } $url = wpconsent_utm_url( 'https://wpconsent.com/powered-by/', 'poweredby' ); $html = '
'; $colors = $this->get_color_settings(); $html .= ''; $html .= sprintf( /* translators: %1$s and %2$s add a tag used for hiding the text on small screens and %3$s is the WPConsent logo svg */ esc_html__( '%1$sPowered by%2$s %3$s', 'wpconsent-cookies-banner-privacy-suite' ), '', '', wpconsent_get_icon( 'logo-mono', 80, 12, '0 0 57 9', $colors['text'] ) ); $html .= ' ' . esc_html__( '(opens in a new window)', 'wpconsent-cookies-banner-privacy-suite' ) . ''; $html .= ''; $html .= '
'; // .wpconsent-powered-by return $html; } /** * Output the floating consent button. * * @return void */ public function floating_consent_button() { if ( is_admin() ) { return; } $colors = $this->get_color_settings(); $style = 'background-color: ' . esc_attr( $colors['background'] ) . '; color: ' . esc_attr( $colors['text'] ) . ';'; echo ''; } /** * Replace smart tags for the cookie policy text. * * @param string $text The text to replace smart tags in. * @param string $locale The locale to use for the replacement. * * @return string */ public function maybe_replace_smart_tags( $text, $locale = '' ) { $cookie_policy_page_id = apply_filters( 'wpconsent_get_cookie_policy_id', wpconsent()->settings->get_option( 'cookie_policy_page', 0 ), $locale ); $privacy_policy_page_id = apply_filters( 'wpconsent_get_privacy_policy_id', get_option( 'wp_page_for_privacy_policy' ), $locale ); // Get the URLs and titles. $cookie_policy_page_url = $cookie_policy_page_id ? get_permalink( $cookie_policy_page_id ) : ''; $cookie_policy_page_title = $cookie_policy_page_id ? get_the_title( $cookie_policy_page_id ) : ''; $privacy_policy_url = $privacy_policy_page_id ? get_permalink( $privacy_policy_page_id ) : ''; $privacy_policy_page_title = $privacy_policy_page_id ? get_the_title( $privacy_policy_page_id ) : ''; // Replace {cookie_policy} with a link to the cookie policy where the text of the link is the page title. if ( $cookie_policy_page_url && $cookie_policy_page_title ) { $text = str_replace( '{cookie_policy}', '' . esc_html( $cookie_policy_page_title ) . '', $text ); } else { $text = str_replace( '{cookie_policy}', '', $text ); } // Replace {privacy_policy} with a link to the privacy policy where the text of the link is the page title. if ( $privacy_policy_url && $privacy_policy_page_title ) { $text = str_replace( '{privacy_policy}', '' . esc_html( $privacy_policy_page_title ) . '', $text ); } else { // If there is no privacy policy page, remove the {privacy_policy} tag. $text = str_replace( '{privacy_policy}', '', $text ); } return $text; } }