init(); } static function this() { return self::$_this; } /** * Get list of documents, based on selected regions * @return array */ public function get_available_documents(){ $documents = COMPLIANZ::$config->pages; $output = array(); foreach( $documents as $region => $region_documents ){ foreach( $region_documents as $type => $data ){ if (!in_array( $type, $output )) { $output[] = $type; } } } return $output; } /** * Check if current locale supports formal * * @return bool */ public function locale_has_formal_variant() { $locale = get_locale(); if ( in_array( $locale, COMPLIANZ::$config->formal_languages) ) { return true; } return false; } /** * Get list of documents from the field list * @return array */ public function get_document_types(){ $fields = COMPLIANZ::$config->fields(); $documents = array(); foreach( $fields as $fieldname => $field ){ if ( isset($field['type']) && $field['type'] === 'document') { $documents[] = $fieldname; } } return $documents; } /** * If a document is loaded with the autoredirect parameter, we redirect automatically */ public function maybe_autoredirect() { //if the autoredirect parameter is used, we look for the region of the passed type, and if necessary redirect to the redirect region if ( isset( $_GET['cmplz_region_redirect'] ) && isset( $_GET['cmplz-region'] ) ) { //get region from current page. global $post; $type = false; if ( $post ) { if ( preg_match( $this->get_shortcode_pattern( "gutenberg" ), $post->post_content, $matches ) ) { $type = $matches[1]; } elseif ( preg_match( $this->get_shortcode_pattern( "classic" ), $post->post_content, $matches ) ) { $type = $matches[1]; } } if ( !$type ){ $slug = esc_url_raw($_SERVER['REQUEST_URI']); $documents = $this->get_available_documents(); foreach($documents as $doc_type){ if (strpos($slug, $doc_type)!==FALSE){ $type = $doc_type; } } } $current_region = false; if ( substr( $type, - 3, 1 ) === '-' ) { $current_region = cmplz_get_region_from_legacy_type($type); $type = str_replace("-$current_region", '', $type); } elseif (isset($matches[2])) { $current_region = $matches[2]; } if ($current_region) $type = str_replace("-$current_region", '', $type); $new_region = sanitize_title( $_GET['cmplz-region'] ); //if region is "other", get the default region if ( $new_region === 'other') { $new_region = COMPLIANZ::$company->get_default_region(); } if ( ! isset( COMPLIANZ::$config->pages[ $new_region ][ $type ] ) ) { return; } if ( array_key_exists( $new_region, cmplz_get_regions() ) && $current_region !== $new_region ) { //get the URL of the new document $new_url = COMPLIANZ::$document->get_permalink( $type, $new_region ); wp_redirect( $new_url ); exit; } } } /** * Enqueue assets */ public function enqueue_assets() { $min = ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ) ? '' : '.min'; if ( $this->is_complianz_page() ) { $load_css = cmplz_get_value( 'use_document_css' ); if ( $load_css ) { wp_register_style( 'cmplz-document', cmplz_url . "assets/css/document$min.css", false, cmplz_version ); wp_enqueue_style( 'cmplz-document' ); } else { wp_register_style( 'cmplz-document-grid', cmplz_url . "assets/css/document-grid$min.css", false, cmplz_version ); wp_enqueue_style( 'cmplz-document-grid' ); } add_action( 'wp_head', array( $this, 'inline_styles' ), 100 ); } if ( cmplz_get_value( 'safe_mode' ) !== 1 ) { wp_register_style( 'cmplz-general', cmplz_url . "assets/css/cookieblocker$min.css", false, cmplz_version ); wp_enqueue_style( 'cmplz-general' ); } } /** * Get custom CSS for documents * * */ public function inline_styles() { //basic color style for revoke button $custom_css = ''; if ( cmplz_get_value( 'use_custom_document_css' ) ) { $custom_css .= cmplz_get_value( 'custom_document_css' ); } $custom_css = apply_filters( 'cmplz_custom_document_css', $custom_css ); if ( empty( $custom_css ) ) { return; } echo ''; } /** * Check if the page is public * * @param string $type * @param string $region * * @return bool */ public function is_public_page( $type, $region ) { if ( ! isset( COMPLIANZ::$config->pages[ $region ][ $type ] ) ) { return false; } if ( isset( COMPLIANZ::$config->pages[ $region ][ $type ]['public'] ) && COMPLIANZ::$config->pages[ $region ][ $type ]['public'] ) { return true; } return false; } /** * period in seconds the wizard wasn't updated * * @param int $period * * @return bool not_updated_in * */ public function not_updated_in( $period ) { //if the wizard is never completed, we don't want any update warnings. if ( ! get_option( 'cmplz_wizard_completed_once' ) ) { return false; } $date = get_option( 'cmplz_documents_update_date' ); if ( ! $date ) { return false; } $time_passed = time() - $date; if ( $time_passed > $period ) { return true; } return false; } /** * Check if a page is required. If no condition is set, return true. * condition is "AND", all conditions need to be met. * * @param array|string $page * @param string $region * * @return bool */ public function page_required( $page, $region ) { if ( ! is_array( $page ) ) { if ( ! isset( COMPLIANZ::$config->pages[ $region ][ $page ] ) ) { return false; } $page = COMPLIANZ::$config->pages[ $region ][ $page ]; } //if it's not public, it's not required if ( isset( $page['public'] ) && $page['public'] == false ) { return false; } //if there's no condition, we set it as required if ( ! isset( $page['condition'] ) ) { return true; } if ( isset( $page['condition'] ) ) { $conditions = $page['condition']; $condition_met = true; foreach ( $conditions as $condition_question => $condition_answer ) { $value = cmplz_get_value( $condition_question, false, false, $use_default = false ); $invert = false; if ( ! is_array( $condition_answer ) && strpos( $condition_answer, 'NOT ' ) !== false ) { $condition_answer = str_replace( 'NOT ', '', $condition_answer ); $invert = true; } $condition_answer = is_array( $condition_answer ) ? $condition_answer : array( $condition_answer ); foreach ( $condition_answer as $answer_item ) { if ( is_array( $value ) ) { if ( ! isset( $value[ $answer_item ] ) || ! $value[ $answer_item ] ) { $condition_met = false; } else { $condition_met = true; } } else { $condition_met = ( $value == $answer_item ); } //if one condition is met, we break with this condition, so it will return true. if ( $condition_met ) { break; } } //if one condition is not met, we break with this condition, so it will return false. if ( ! $condition_met ) { break; } } $condition_met = $invert ? ! $condition_met : $condition_met; return $condition_met; } return false; } /** * Check if an element should be inserted. AND implementation s * * * */ public function insert_element( $element, $post_id ) { if ( $this->callback_condition_applies( $element ) && $this->condition_applies( $element, $post_id ) ) { return true; } return false; } /** * @param $element * * @return bool */ public function callback_condition_applies( $element ) { if ( isset( $element['callback_condition'] ) ) { $conditions = is_array( $element['callback_condition'] ) ? $element['callback_condition'] : array( $element['callback_condition'] ); foreach ( $conditions as $func ) { $invert = false; if ( strpos( $func, 'NOT ' ) !== false ) { $invert = true; $func = str_replace( 'NOT ', '', $func ); } if ( ! function_exists( $func ) ) { break; } $show_field = $func(); if ( $invert ) { $show_field = ! $show_field; } if ( ! $show_field ) { return false; } } } return true; } /** * Check if the passed condition applies * * @param array $element * @param int $post_id * * @return bool */ public function condition_applies( $element, $post_id ) { if ( isset( $element['condition'] ) ) { $fields = COMPLIANZ::$config->fields; $condition_met = true; foreach ( $element['condition'] as $question => $condition_answer ) { $invert = false; if ( $condition_answer === 'loop' ) { continue; } if ( ! isset( $fields[ $question ]['type'] ) ) { return false; } $type = $fields[ $question ]['type']; $value = cmplz_get_value( $question, $post_id ); if ( strpos( $condition_answer, 'NOT ' ) !== false ) { $condition_answer = str_replace( 'NOT ', '', $condition_answer ); $invert = true; } //check for emptiness af a value. in case of arrays, it is also empty if all values are 0. if ($condition_answer === 'EMPTY') { if (!empty($value) && is_array($value)){ $is_empty = true; foreach($value as $key => $arr_val ) { if ($arr_val==1) { $is_empty = false; break; } } } else { $is_empty = empty($value); } $current_condition_met = $is_empty; } else if ( $type === 'multicheckbox' ) { if ( ! isset( $value[ $condition_answer ] ) || ! $value[ $condition_answer ] ) { $current_condition_met = false; } else { $current_condition_met = true; } } else { $current_condition_met = $value == $condition_answer ; } $current_condition_met = $invert ? !$current_condition_met : $current_condition_met; $condition_met = $condition_met && $current_condition_met; } return $condition_met; } return true; } /** * Check if this element should loop through dynamic multiple values * * @param array $element * * @return bool * */ public function is_loop_element( $element ) { if ( isset( $element['condition'] ) ) { foreach ( $element['condition'] as $question => $condition_answer ) { if ( $condition_answer === 'loop' ) { return true; } } } return false; } /** * Build a legal document by type * * @param string $type * @param $region * @param bool|int $post_id * * @return string */ public function get_document_html( $type, $region = false, $post_id = false ) { //legacy, if region is not passed, we get it from the type string if ( ! $region ) { $region = cmplz_get_region_from_legacy_type( $type ); $type = str_replace( '-' . $region, '', $type ); } if ( ! cmplz_has_region( $region ) || ! isset( COMPLIANZ::$config->pages[ $region ][ $type ] ) ) { return cmplz_sprintf( __( 'Region %s not activated for %s.', 'complianz-gdpr' ), strtoupper( $region ), $type ); } $elements = COMPLIANZ::$config->pages[ $region ][ $type ]["document_elements"]; $elements = is_array($elements) ? $elements : []; $html = ""; $paragraph = 0; $sub_paragraph = 0; $annex = 0; $annex_arr = array(); $paragraph_id_arr = array(); foreach ( $elements as $id => $element ) { //count paragraphs if ( $this->insert_element( $element, $post_id ) || $this->is_loop_element( $element ) ) { if ( isset( $element['title'] ) && ( ! isset( $element['numbering'] ) || $element['numbering'] ) ) { $sub_paragraph = 0; $paragraph ++; $paragraph_id_arr[ $id ]['main'] = $paragraph; } //count subparagraphs if ( isset( $element['subtitle'] ) && $paragraph > 0 && ( ! isset( $element['numbering'] ) || $element['numbering'] ) ) { $sub_paragraph++; $paragraph_id_arr[ $id ]['main'] = $paragraph; $paragraph_id_arr[ $id ]['sub'] = $sub_paragraph; } //count dropdowns as sub parapgraphs if ( isset( $element['dropdown-open'] ) && $paragraph > 0 && ( ! isset( $element['numbering'] ) || $element['numbering'] ) ) { $sub_paragraph ++; $paragraph_id_arr[ $id ]['main'] = $paragraph; $paragraph_id_arr[ $id ]['sub'] = $sub_paragraph; } //count annexes if ( isset( $element['annex'] ) ) { $annex ++; $annex_arr[ $id ] = $annex; } } if ( $this->is_loop_element( $element ) && $this->insert_element( $element, $post_id ) ) { $fieldname = key( $element['condition'] ); $values = cmplz_get_value( $fieldname, $post_id ); $loop_content = ''; if ( ! empty( $values ) ) { foreach ( $values as $value ) { if ( ! is_array( $value ) ) { $value = array( $value ); } $fieldnames = array_keys( $value ); if ( count( $fieldnames ) == 1 && $fieldnames[0] == 'key' ) { continue; } $loop_section = $element['content']; foreach ( $fieldnames as $c_fieldname ) { $field_value = ( isset( $value[ $c_fieldname ] ) ) ? $value[ $c_fieldname ] : ''; if ( ! empty( $field_value ) && is_array( $field_value ) ) { $field_value = implode( ', ', $field_value ); } $loop_section = str_replace( '[' . $c_fieldname . ']', $field_value, $loop_section ); } $loop_content .= $loop_section; } $html .= $this->wrap_header( $element, $paragraph, $sub_paragraph, $annex ); $html .= $this->wrap_content( $loop_content ); } } elseif ( $this->insert_element( $element, $post_id ) ) { $html .= $this->wrap_header( $element, $paragraph, $sub_paragraph, $annex ); if ( isset( $element['content'] ) ) { $html .= $this->wrap_content( $element['content'], $element ); } } if ( isset( $element['callback'] ) && function_exists( $element['callback'] ) ) { $func = $element['callback']; $html .= $func(); } } $html = $this->replace_fields( $html, $paragraph_id_arr, $annex_arr, $post_id, $type, $region ); $comment = apply_filters( "cmplz_document_comment", "\n" . "" . "\n" ); $html = $comment . '
' . esc_html( $nr ) . esc_html( $element['subtitle'] ) . '
'; } } if ( isset( $element['title'] ) ) { if ( empty( $element['title'] ) ) { return ""; } $nr = ''; if ( $paragraph > 0 && $this->is_numbered_element( $element ) ) { $nr = $paragraph; $index_char = apply_filters( 'cmplz_index_char', '.' ); $nr = $nr . $index_char . ' '; } return '' . esc_html( $nr ) . esc_html( $element['subtitle'] ) . '
'; } // Adds a dropdown to the Privacy Statement. Opens a div and should be closed with dropdown-close if ( isset( $element['dropdown-open'] ) ) { if ( $paragraph > 0 && $sub_paragraph > 0 && $this->is_numbered_element( $element ) ) { $nr = $paragraph . "." . $sub_paragraph . " "; } $dp_class = isset($element['dropdown-class']) ? $element['dropdown-class'] : ''; //we need a unique key here, because otherwise the react in Gutenberg has an issue with this. $html .= '' . $content . "
"; } /** * Replace all fields in the resulting output * * @param string $html * @param array $paragraph_id_arr * @param array $annex_arr * @param int $post_id * @param string $type * @param string $region * * @return string $html */ private function replace_fields( $html, $paragraph_id_arr, $annex_arr, $post_id, $type, $region ) { //replace references foreach ( $paragraph_id_arr as $id => $paragraph ) { $html = str_replace( "[article-$id]", cmplz_sprintf( __( '(See paragraph %s)', 'complianz-gdpr' ), esc_html( $paragraph['main'] ) ), $html ); } foreach ( $annex_arr as $id => $annex ) { $html = str_replace( "[annex-$id]", cmplz_sprintf( __( '(See annex %s)', 'complianz-gdpr' ), esc_html( $annex ) ), $html ); } $active_cookiebanner_id = apply_filters( 'cmplz_user_banner_id', cmplz_get_default_banner_id() ); $banner = new CMPLZ_COOKIEBANNER($active_cookiebanner_id); //some custom elements $html = str_replace( "[cookie_accept_text]", $banner->accept_x, $html ); $html = str_replace( "[cookie_save_preferences_text]", $banner->save_preferences_x, $html ); $html = str_replace( "[domain]", '' . esc_url_raw( get_home_url() ) . '', $html ); $html = str_replace( "[cookie-statement-url]", cmplz_get_document_url( 'cookie-statement', $region ), $html ); $html = str_replace( "[privacy-statement-url]", $this->get_page_url( 'privacy-statement', $region ), $html ); $html = str_replace( "[privacy-statement-children-url]", $this->get_page_url( 'privacy-statement-children', $region ), $html ); $html = str_replace( "[site_url]", site_url(), $html ); //us can have two types of titles $cookie_policy_title = esc_html( $this->get_document_title( 'cookie-statement', $region ) ); $html = str_replace( '[cookie-statement-title]', $cookie_policy_title, $html ); $date = $post_id ? strtotime(get_the_date( 'd F Y', $post_id )) : get_option( 'cmplz_publish_date' );//use default date format, to ensure that strtotime works. $date = cmplz_localize_date( $date ); $html = str_replace( "[publish_date]", esc_html( $date ), $html ); $html = str_replace( "[sync_date]", esc_html( COMPLIANZ::$cookie_admin->get_last_cookie_sync_date() ), $html ); $checked_date = cmplz_localize_date( get_option( 'cmplz_documents_update_date' ) ); $html = str_replace( "[checked_date]", esc_html( $checked_date ), $html ); //because the phonenumber is not required, we need to allow for an empty phonenr, making a dynamic string necessary. $contact_dpo = cmplz_get_value( 'email_dpo' ); $phone_dpo = cmplz_get_value( 'phone_dpo' ); if ( !empty( $phone_dpo ) ) { $contact_dpo .= " " . cmplz_sprintf( _x( "or by telephone on %s", 'if phonenumber is entered, this string is part of the sentence "you may contact %s, via %s or by telephone via %s"', "complianz-gdpr" ), $phone_dpo ); } $html = str_replace( "[email_dpo]", $contact_dpo, $html ); $contact_dpo_uk = cmplz_get_value( 'email_dpo_uk' ); $phone_dpo_uk = cmplz_get_value( 'phone_dpo_uk' ); if ( !empty( $phone_dpo ) ) { $contact_dpo_uk .= " " . cmplz_sprintf( _x( "or by telephone on %s", 'if phonenumber is entered, this string is part of the sentence "you may contact %s, via %s or by telephone via %s"', "complianz-gdpr" ), $phone_dpo_uk ); } $html = str_replace( "[email_dpo_uk]", $contact_dpo_uk, $html ); //replace all fields. foreach ( COMPLIANZ::$config->fields() as $fieldname => $field ) { if ( strpos( $html, "[$fieldname]" ) !== false ) { $html = str_replace( "[$fieldname]", $this->get_plain_text_value( $fieldname, $post_id , true, $type ), $html ); //when there's a closing shortcode it's always a link $html = str_replace( "[/$fieldname]", "", $html ); } if ( strpos( $html, "[comma_$fieldname]" ) !== false ) { $html = str_replace( "[comma_$fieldname]", $this->get_plain_text_value( $fieldname, $post_id, false , $type ), $html ); } } return $html; } /** * * Get the plain text value of an option * * @param string $fieldname * @param int $post_id * @param bool $list_style * @param string $type * * @return string */ private function get_plain_text_value( $fieldname, $post_id, $list_style, $type ) { $value = cmplz_get_value( $fieldname, $post_id ); $front_end_label = isset( COMPLIANZ::$config->fields[ $fieldname ]['document_label'] ) ? COMPLIANZ::$config->fields[ $fieldname ]['document_label'] : false; if ( COMPLIANZ::$config->fields[ $fieldname ]['type'] === 'url' ) { $value = ''; } elseif ( COMPLIANZ::$config->fields[ $fieldname ]['type'] === 'email' ) { $value = apply_filters( 'cmplz_document_email', $value ); } elseif ( COMPLIANZ::$config->fields[ $fieldname ]['type'] === 'radio' ) { $options = COMPLIANZ::$config->fields[ $fieldname ]['options']; $value = isset( $options[ $value ] ) ? $options[ $value ] : ''; } elseif ( COMPLIANZ::$config->fields[ $fieldname ]['type'] === 'textarea' ) { //preserve linebreaks $value = nl2br( $value ); } elseif ( is_array( $value ) ) { $options = COMPLIANZ::$config->fields[ $fieldname ]['options']; //array('3' => 1 ); $value = array_filter( $value, function ( $item ) {return $item == 1;} ); $value = array_keys( $value ); //array (1, 4, 6) $labels = ""; foreach ( $value as $index ) { //trying to fix strange issue where index is not set if ( ! isset( $options[ $index ] ) ) { continue; } if ( $list_style ) { $labels .= "'.__("The pages marked with X should be added to your website. You can create these pages with a shortcode, a Gutenberg block or use the below \"Create missing pages\" button.","complianz-gdpr").'
'; } else { echo ''.__("All necessary pages have been created already. You can update the page titles here if you want, then click the \"Update pages\" button.","complianz-gdpr").'
'; } ?>