%PDF- %PDF-
Direktori : /home/t/r/a/tradesc/www/relax/wp-content/plugins/complianz-gdpr/ |
Current File : /home/t/r/a/tradesc/www/relax/wp-content/plugins/complianz-gdpr/class-document.php |
<?php defined( 'ABSPATH' ) or die( "you do not have access to this page!" ); if ( ! class_exists( "cmplz_document" ) ) { class cmplz_document { private static $_this; function __construct() { if ( isset( self::$_this ) ) { wp_die( sprintf( '%s is a singleton class and you cannot create a second instance.', get_class( $this ) ) ); } self::$_this = $this; $this->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 '<style>' . $custom_css . '</style>'; } /** * 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" . "<!-- Legal document generated by Complianz | GDPR/CCPA Cookie Consent https://wordpress.org/plugins/complianz-gdpr -->" . "\n" ); $html = $comment . '<div id="cmplz-document" class="cmplz-document '.$type.' cmplz-document-'.$region.'">' . $html . '</div>'; $html = wp_kses( $html, cmplz_allowed_html() ); //in case we still have an unprocessed shortcode //this may happen when a shortcode is inserted in combination with gutenberg $html = do_shortcode($html); return apply_filters( 'cmplz_document_html', $html, $type, $post_id ); } /** * Wrap the header for a paragraph * * @param array $element * @param int $paragraph * @param int $sub_paragraph * @param int $annex * * @return string */ public function wrap_header( $element, $paragraph, $sub_paragraph, $annex ) { $nr = ""; $html = ""; if ( isset( $element['annex'] ) ) { $nr = __( "Annex", 'complianz-gdpr' ) . " " . $annex . ": "; if ( isset( $element['title'] ) ) { return '<h2 class="annex">' . esc_html( $nr ) . esc_html( $element['title'] ) . '</h2>'; } if ( isset( $element['subtitle'] ) ) { return '<p class="cmplz-subtitle annex">' . esc_html( $nr ) . esc_html( $element['subtitle'] ) . '</p>'; } } 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 '<h2>' . esc_html( $nr ) . esc_html( $element['title'] ) . '</h2>'; } if ( isset( $element['subtitle'] ) ) { if ( $paragraph > 0 && $sub_paragraph > 0 && $this->is_numbered_element( $element ) ) { $nr = $paragraph . "." . $sub_paragraph . " "; } return '<p class="cmplz-subtitle">' . esc_html( $nr ) . esc_html( $element['subtitle'] ) . '</p>'; } // 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 .= '<details class="cmplz-dropdown '.$dp_class.'">'; if ( isset( $element['dropdown-title'] ) ) { $html .= '<summary><div><h3>'. esc_html( $nr ) . esc_html( $element['dropdown-title'] ) . '</h3></div></summary>'; } return $html; } if ( isset( $element['dropdown-close'] ) ) { return '</details>'; } } /** * Check if this element should be numbered * if no key is set, default is true * * @param array $element * * @return bool */ public function is_numbered_element( $element ) { if ( ! isset( $element['numbering'] ) ) { return true; } return $element['numbering']; } /** * Wrap subheader in html * * @param string $header * @param int $paragraph * @param int $subparagraph * * @return string $html */ public function wrap_sub_header( $header, $paragraph, $subparagraph ) { if ( empty( $header ) ) { return ""; } return '<b>' . esc_html( $header ) . '</b><br />'; } /** * Wrap content in html * * @param string $content * @param bool $element * * @return string */ public function wrap_content( $content, $element = false ) { if ( empty( $content ) ) { return ""; } $class = isset( $element['class'] ) ? 'class="' . esc_attr( $element['class'] ) . '"' : ''; if (isset($element['p']) && !$element['p']) { return $content; } return '<p '.$class.'>' . $content . "</p>"; } /** * 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]", '<a href="' . esc_url_raw( get_home_url() ) . '">' . esc_url_raw( get_home_url() ) . '</a>', $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]", "</a>", $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 = '<a href="' . $value . '" target="_blank">'; } 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 .= "<li>" . esc_html( $options[ $index ] ) . '</li>'; } else { $labels .= $options[ $index ] . ', '; } } //if (empty($labels)) $labels = __('None','complianz-gdpr'); if ( $list_style ) { $labels = "<ul>" . $labels . "</ul>"; } else { $labels = esc_html( rtrim( $labels, ', ' ) ); $labels = strrev( implode( strrev( ' ' . __( 'and', 'complianz-gdpr' ) ), explode( strrev( ',' ), strrev( $labels ), 2 ) ) ); } $value = $labels; } else { if ( isset( COMPLIANZ::$config->fields[ $fieldname ]['options'] ) ) { $options = COMPLIANZ::$config->fields[ $fieldname ]['options']; if ( isset( $options[ $value ] ) ) { $value = $options[ $value ]; } } } if ( $front_end_label && ! empty( $value ) ) { $value = $front_end_label . $value; } return $value; } /** * Get list of cookie statement snapshots * @param array $args * * @return array|false */ public function get_cookie_snapshot_list( $args = array() ) { $defaults = array( 'number' => 10, 'offset' => 0, 'order' => 'DESC', 'start_date' => 0, 'end_date' => 9999999999999, ); $args = wp_parse_args( $args, $defaults ); $path = cmplz_upload_dir('snapshots'); $url = cmplz_upload_url('snapshots'); $filelist = array(); $extensions = array( "pdf" ); $index = 0; if ( file_exists( $path ) && $handle = opendir( $path ) ) { while ( false !== ( $file = readdir( $handle ) ) ) { if ( $file != "." && $file != ".." ) { $file = $path . $file; $ext = strtolower( pathinfo( $file, PATHINFO_EXTENSION ) ); if ( is_file( $file ) && in_array( $ext, $extensions ) ) { $index++; if ( empty( $args['search'] ) || strpos( $file, $args['search'] ) !== false) { if ($args['start_date'] < filemtime( $file ) && filemtime( $file ) < $args['end_date'] ) { $filelist[filemtime($file) . $index]["path"] = $file; $filelist[filemtime($file) . $index]["url"] = trailingslashit($url).basename($file); $filelist[filemtime($file) . $index]["file"] = basename($file); $filelist[filemtime($file) . $index]["time"] = filemtime($file); } } } } } closedir( $handle ); } if ( $args['order'] === 'DESC' ) { krsort( $filelist ); } else { ksort( $filelist ); } if ( empty( $filelist ) ) { return array(); } $page = (int) $args['offset']; $total = count( $filelist ); //total items in array $limit = $args['number']; $totalPages = ceil( $total / $limit ); //calculate total pages $page = max( $page, 1 ); //get 1 page when $_GET['page'] <= 0 $page = min( $page, $totalPages ); //get last page when $_GET['page'] > $totalPages $offset = ( $page - 1 ) * $limit; if ( $offset < 0 ) { $offset = 0; } $filelist = array_slice( $filelist, $offset, $limit ); if ( empty( $filelist ) ) { return array(); } return $filelist; } /** * Add some text to the privacy statement suggested texts in free. */ public function add_privacy_info() { if ( ! function_exists( 'wp_add_privacy_policy_content' ) ) { return; } $content = __( "This website uses the Privacy Suite for WordPress by Complianz to collect and record Browser and Device-based Consent. For this functionality, your IP address is anonymized and stored in our database.", 'complianz-gdpr' ) .' ' . __( "This service does not process any personally identifiable information and does not share any data with the service provider.", 'complianz-gdpr' ) .' ' . cmplz_sprintf( __( "For more information, see the Complianz %sPrivacy Statement%s.", 'complianz-gdpr' ), '<a href="https://complianz.io/legal/privacy-statement/">', '</a>' ); $content = apply_filters( 'cmplz_privacy_info', $content ); wp_add_privacy_policy_content( 'Complianz | The Privacy Suite for WordPress', wp_kses_post( wpautop( $content, false ) ) ); } /** * Get the region for a post id, based on the post type. * * @param int|array $post_id * * @return string|bool $region * */ public function get_region( $post_id ) { if ( ! is_numeric( $post_id ) ) { if ( isset( $post_id['source'] )) { return substr( $post_id['source'], - 2 ); } else if (strpos($post_id, 'cmplz-') !== false ) { return substr( $post_id, - 2 ); } } if ( $post_id ) { $term = wp_get_post_terms( $post_id, 'cmplz-region' ); if ( is_wp_error( $term ) ) { return false; } if ( isset( $term[0] ) ) { return $term[0]->slug; } return false; } return false; } /** * Set the region in a post * * @param $post_id * @param bool $region */ public function set_region( $post_id, $region = false ) { if ( ! $region ) { $region = $this->get_region( $post_id ); } if ( ! $region ) { $regions = cmplz_get_regions(); if ( isset( $_GET['page'] ) ) { $page = sanitize_title( $_GET['page'] ); foreach ( $regions as $r => $label ) { if ( strpos( $page, '-' . $r ) !== false ) { $region = $r; } } } } $term = get_term_by( 'slug', $region, 'cmplz-region' ); if ( ! $term ) { wp_insert_term( COMPLIANZ::$config->regions[ $region ]['label'], 'cmplz-region', array( 'slug' => $region, ) ); $term = get_term_by( 'slug', $region, 'cmplz-region' ); } if ( empty( $term ) ) { return; } $term_id = $term->term_id; wp_set_object_terms( $post_id, array( $term_id ), 'cmplz-region' ); } public function get_dataleak_type( $post_id = false ){ if (!$post_id) return; $region = $this->get_region($post_id); $regions = COMPLIANZ::$config->regions; return $regions[$region]['dataleak_type']; } /** * Check if legal documents should be updated * * @return bool */ public function documents_need_updating() { if ( cmplz_has_region('us') && $this->not_updated_in( MONTH_IN_SECONDS * 12 ) ) { return true; } return false; } /** * Check if legal documents should be updated, and send mail to admin if so */ public function cron_check_last_updated_status() { if ( $this->documents_need_updating() && ! get_option( 'cmplz_update_legal_documents_mail_sent' ) ) { update_option( 'cmplz_update_legal_documents_mail_sent', true ); $to = get_option( 'admin_email' ); $headers = array(); if ( empty( $subject ) ) { $subject = cmplz_sprintf( _x( 'Your legal documents on %s need to be updated.', 'Subject in notification email', 'complianz-gdpr' ), home_url() ); } $link = '<a href="'.add_query_arg( array('page' => 'cmplz-wizard'), admin_url('admin.php?page=cmplz-wizard') ).'">'; $message = cmplz_sprintf( _x( 'Your legal documents on %s have not been updated in 12 months. Please log in and run the %swizard%s in the Complianz plugin to check if everything is up to date.', 'notification email', 'complianz-gdpr' ), home_url(), $link, "</a>" ); $message .= '<br /><br />'.__("This message was generated by Complianz GDPR/CCPA.", "complianz-gdpr"); add_filter( 'wp_mail_content_type', function ( $content_type ) { return 'text/html'; } ); wp_mail( $to, $subject, $message, $headers ); // Reset content-type to avoid conflicts -- http://core.trac.wordpress.org/ticket/23578 remove_filter( 'wp_mail_content_type', 'set_html_content_type' ); } } /** * Render html for the manage consent shortcode * @param array $atts * @param null $content * @param string $tag * * @return string */ public function manage_consent_html( $atts = array(), $content = null, $tag = '' ) { $html = '<div id="cmplz-manage-consent-container-nojavascript">'. _x( "You have loaded the Cookie Policy without javascript support.", "cookie policy", "complianz-gdpr" ).' '. _x( "On AMP, you can use the manage consent button on the bottom of the page.", "cookie policy", "complianz-gdpr" ). '</div>'; $html .= '<div id="cmplz-manage-consent-container" name="cmplz-manage-consent-container" class="cmplz-manage-consent-container"></div>'; return $html; } public function revoke_link( $atts = array(), $content = null, $tag = '' ) { // normalize attribute keys, lowercase $atts = array_change_key_case( (array) $atts, CASE_LOWER ); ob_start(); // override default attributes with user attributes $atts = shortcode_atts( array( 'text' => false ), $atts, $tag ); echo cmplz_revoke_link($atts['text']); return ob_get_clean(); } /** * Display an accept hyperlink * * @param array $atts * @param null $content * @param string $tag * * @return string */ public function accept_link( $atts = array(), $content = null, $tag = '' ) { // normalize attribute keys, lowercase $atts = array_change_key_case( (array) $atts, CASE_LOWER ); ob_start(); // override default attributes with user attributes $atts = shortcode_atts( array( 'text' => false ), $atts, $tag ); $accept_text = sanitize_text_field($atts['text']) ?: __("Click to accept marketing cookies", "complianz-gdpr"); $html = '<div class="cmplz-custom-accept-btn cmplz-accept"><a href="#">' . esc_html($accept_text) . '</a></div>'; echo $html; return ob_get_clean(); } /** * This class is extended with pro functions, so init is called also from the pro extension. * */ public function init() { //this shortcode is also available as gutenberg block add_shortcode( 'cmplz-document', array( $this, 'load_document' ) ); add_shortcode( 'cmplz-consent-area', array( $this, 'show_consent_area' ) ); add_shortcode( 'cmplz-cookies', array( $this, 'cookies' ) ); add_filter( 'display_post_states', array( $this, 'add_post_state') , 10, 2); add_shortcode( 'cmplz-manage-consent', array( $this, 'manage_consent_html' ) ); add_shortcode( 'cmplz-revoke-link', array( $this, 'revoke_link' ) ); add_shortcode( 'cmplz-accept-link', array( $this, 'accept_link' ) ); //clear shortcode transients after post update add_action( 'save_post', array( $this, 'clear_shortcode_transients' ), 10, 1 ); add_action( 'cmplz_wizard_add_pages_to_menu', array( $this, 'wizard_add_pages_to_menu' ), 10, 1 ); add_action( 'cmplz_wizard_add_pages_to_menu_region_redirected', array( $this, 'wizard_add_pages_to_menu_region_redirected' ), 10, 1 ); add_action( 'cmplz_wizard_add_pages', array( $this, 'callback_wizard_add_pages' ), 10, 1 ); add_action( 'admin_init', array( $this, 'assign_documents_to_menu' ) ); add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_assets' ) ); add_action( 'admin_init', array( $this, 'add_privacy_info' ) ); add_filter( 'cmplz_document_email', array( $this, 'obfuscate_email' ) ); add_filter( 'body_class', array( $this, 'add_body_class_for_complianz_documents' ) ); //unlinking documents add_action( 'add_meta_boxes', array( $this, 'add_meta_box' ) ); add_action( 'save_post', array( $this, 'save_metabox_data' ) ); add_action( 'wp', array( $this, 'maybe_autoredirect' ) ); add_action( 'wp_ajax_cmplz_create_pages', array( $this, 'ajax_create_pages' ) ); add_action('save_post', array($this, 'register_document_title_for_translations'), 10, 3); add_filter( 'the_content', array( $this, 'revert_divs_to_summary' ) ); } /** * Make sure the document title can be translated * @param int $post_ID * @param WP_POST $post * @param bool $update */ public function register_document_title_for_translations($post_ID, $post, $update) { if ( is_admin() && $this->is_complianz_page($post_ID)) { $pattern = '/type="(.*?)"/i'; if ( preg_match( $pattern, $post->post_content, $matches ) ) { $type = $matches[1]; cmplz_register_translation( $post->post_title, 'cmplz_link_title_'.$type ); } } } /** * Add document post state * @param array $post_states * @param WP_Post $post * @return array */ public function add_post_state($post_states, $post) { if ( $post && $this->is_complianz_page( $post->ID ) ) { $post_states['page_for_privacy_policy'] = __("Legal Document", "complianz-gdpr"); } return $post_states; } public function add_meta_box( $post_type ) { global $post; if ( ! $post ) { return; } if ( $this->is_complianz_page( $post->ID ) && ! cmplz_uses_gutenberg() ) { add_meta_box( 'cmplz_edit_meta_box', __( 'Document status', 'complianz-gdpr' ), array( $this, 'metabox_unlink_from_complianz' ), null, 'side', 'high', array() ); } } /** * Unlink a page from the shortcode, and use the html instead * */ function metabox_unlink_from_complianz() { if ( ! cmplz_user_can_manage() ) { return; } wp_nonce_field( 'cmplz_unlink_nonce', 'cmplz_unlink_nonce' ); global $post; $sync = $this->syncStatus( $post->ID ); ?> <select name="cmplz_document_status"> <option value="sync" <?php echo $sync === 'sync' ? 'selected="selected"' : '' ?>><?php _e( "Synchronize document with Complianz", "complianz-gdpr" ); ?></option> <option value="unlink" <?php echo $sync === 'unlink' ? 'selected="selected"' : '' ?>><?php _e( "Edit document and stop synchronization", "complianz-gdpr" ); ?></option> </select> <?php } /** * Get sync status of post * * @param $post_id * * @return string */ public function syncStatus( $post_id ) { $post = get_post( $post_id ); $sync = 'unlink'; if ( ! $post ) { return $sync; } $shortcode = 'cmplz-document'; $block = 'complianz/document'; $html = $post->post_content; if ( cmplz_uses_gutenberg() && has_block( $block, $html ) ) { $elements = parse_blocks( $html ); foreach ( $elements as $element ) { if ( $element['blockName'] === $block ) { if ( isset( $element['attrs']['documentSyncStatus'] ) && $element['attrs']['documentSyncStatus'] === 'unlink' ) { $sync = 'unlink'; } else { $sync = 'sync'; } } } } elseif ( has_shortcode( $post->post_content, $shortcode ) ) { $sync = get_post_meta( $post_id, 'cmplz_document_status', true ); if ( ! $sync ) { $sync = 'sync'; } } //default return $sync; } /** * Save data posted from the metabox */ public function save_metabox_data() { if ( ! cmplz_user_can_manage() ) { return; } // check if this isn't an auto save if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) { return; } // security check if ( ! isset( $_POST['cmplz_unlink_nonce'] ) || ! wp_verify_nonce( $_POST['cmplz_unlink_nonce'], 'cmplz_unlink_nonce' ) ) { return; } if ( ! isset( $_POST['cmplz_document_status'] ) ) { return; } global $post; if ( ! $post ) { return; } //prevent looping remove_action( 'save_post', array( $this, 'save_metabox_data' ) ); $sync = sanitize_text_field( $_POST['cmplz_document_status'] ) == 'unlink' ? 'unlink' : 'sync'; //save the document's shortcode in a meta field if ( $sync === 'unlink' ) { //get shortcode from page $shortcode = false; if ( preg_match( $this->get_shortcode_pattern( "gutenberg" ), $post->post_content, $matches ) ) { $shortcode = $matches[0]; $type = $matches[1]; $region = cmplz_get_region_from_legacy_type( $type ); $type = str_replace( '-' . $region, '', $type ); } elseif ( preg_match( $this->get_shortcode_pattern( "classic" ), $post->post_content, $matches ) ) { $shortcode = $matches[0]; $type = $matches[1]; $region = $matches[2]; } elseif ( preg_match( $this->get_shortcode_pattern( "classic", $legacy = true ), $post->post_content, $matches ) ) { $shortcode = $matches[0]; $type = $matches[1]; $region = cmplz_get_region_from_legacy_type( $type ); $type = str_replace( '-' . $region, '', $type ); } if ( $shortcode ) { //store shortcode update_post_meta( $post->ID, 'cmplz_shortcode', $post->post_content ); $document_html = COMPLIANZ::$document->get_document_html( $type, $region ); $args = array( 'post_content' => $this->convert_summary_to_div($document_html, $post->ID), 'ID' => $post->ID, ); wp_update_post( $args ); } } else { $shortcode = get_post_meta( $post->ID, 'cmplz_shortcode', true ); if ( $shortcode ) { $args = array( 'post_content' => $shortcode, 'ID' => $post->ID, ); wp_update_post( $args ); } delete_post_meta( $post->ID, 'cmplz_shortcode' ); } update_post_meta( $post->ID, 'cmplz_document_status', $sync ); add_action( 'save_post', array( $this, 'save_metabox_data' ) ); } /** * add a class to the body telling the page it's a complianz doc. We use this for the soft cookie wall * * @param $classes * * @return array */ public function add_body_class_for_complianz_documents( $classes ) { global $post; if ( $post && $this->is_complianz_page( $post->ID ) ) { $classes[] = 'cmplz-document'; } return $classes; } /** * obfuscate the email address * * @param $email * * @return string */ public function obfuscate_email( $email ) { $alwaysEncode = array( '.', ':', '@' ); $result = ''; $email = strrev($email); // Encode string using oct and hex character codes for ( $i = 0; $i < strlen( $email ); $i ++ ) { // Encode 25% of characters including several that always should be encoded if ( in_array( $email[ $i ], $alwaysEncode ) || mt_rand( 1, 100 ) < 25 ) { if ( mt_rand( 0, 1 ) ) { $result .= '&#' . ord( $email[ $i ] ) . ';'; } else { $result .= '&#x' . dechex( ord( $email[ $i ] ) ) . ';'; } } else { $result .= $email[ $i ]; } } return '<span class="cmplz-obfuscate" >'.$result.'</span>'; } /** * Render shortcode for cookie list * * @hooked shortcode hook * * @param array $atts * @param null $content * @param string $tag * * @return false|string * @since 2.0 */ public function cookies( $atts = array(), $content = null, $tag = '' ) { ob_start(); echo cmplz_used_cookies(); return ob_get_clean(); } /** * Create legal document pages from the wizard using ajax */ public function ajax_create_pages(){ if (!isset($_POST['nonce']) ) { return; } if (!wp_verify_nonce($_POST['nonce'], 'complianz_save')){ return; } if ( ! cmplz_user_can_manage() ) { return; } $error = false; if (!isset($_POST['pages'])){ $error = true; } if (!$error){ $posted_pages = json_decode(stripslashes($_POST['pages'])); foreach ( $posted_pages as $region => $pages ){ foreach( $pages as $type => $title ) { $current_page_id = $this->get_shortcode_page_id($type, $region, false ); if ( !$current_page_id ){ $this->create_page( $type, $region, $title ); } else { //if the page already exists, just update it with the title $page = array( 'ID' => $current_page_id, 'post_title' => $title, 'post_type' => "page", ); wp_update_post( $page ); } } } } $data = array( 'success' => !$error, 'new_button_text' => __("Update pages","complianz-gdpr"), 'icon' => cmplz_icon('check', 'success', '', 10), ); $response = json_encode( $data ); header( "Content-Type: application/json" ); echo $response; exit; } /** * Check if the site has missing pages for the auto generated documents * @return bool */ public function has_missing_pages(){ $pages = COMPLIANZ::$document->get_required_pages(); $missing_pages = false; foreach ( $pages as $region => $region_pages ) { foreach ( $region_pages as $type => $page ) { $current_page_id = $this->get_shortcode_page_id( $type, $region ); if ( ! $current_page_id ) { $missing_pages = true; break; } } } return $missing_pages; } public function callback_wizard_add_pages() { ?> <div class="cmplz-wizard-intro"> <?php if ($this->has_missing_pages()){ echo '<p>'.__("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").'</p>'; } else { echo '<p>'.__("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").'</p>'; } ?> </div> <?php $pages = COMPLIANZ::$document->get_required_pages(); if (count($pages)==0){ ?> <?php cmplz_sidebar_notice(__("You haven't selected any legal documents to create.", "complianz-gdpr")." ".__("You can continue to the next step.", "complianz-gdpr"), "warning"); ?> <?php } else { $missing_pages = false; ?> <div class="field-group add-pages"> <div class="cmplz-field"> <?php foreach ( $pages as $region => $region_pages ) { foreach ( $region_pages as $type => $page ) { $current_page_id = $this->get_shortcode_page_id( $type, $region, false); if ( ! $current_page_id ) { $missing_pages = true; $title = $page['title']; $icon = cmplz_icon('times', 'error', '', 10); $class = 'cmplz-deleted-page'; } else { $post = get_post( $current_page_id ); $icon = cmplz_icon('check', 'success', '', 10); $title = $post->post_title; $class = 'cmplz-valid-page'; } $shortcode = $this->get_shortcode( $type, $region, $force_classic = true ); ?> <div class="cmplz-add-pages-table shortcode-container"> <div> <input name="<?php echo $type ?>" data-region="<?php echo $region ?>" class="<?php echo $class ?> cmplz-create-page-title" type="text" value="<?php echo $title ?>"> <?php echo $icon ?> </div> <?php echo cmplz_icon('shortcode', 'default', __( 'Click to copy the document shortcode', 'complianz-gdpr' ), 15, $type . '-' . $region, $shortcode ); ?> </div> <?php } } ?> <?php if ($missing_pages){ $btn = __("Create missing pages","complianz-gdpr"); } else { $btn = __("Update pages","complianz-gdpr"); } ?> <button type="button" class="button button-primary" id="cmplz-create_pages"><?php echo $btn ?></button> </div> </div> <?php } } /** * * Show form to enable user to add pages to a menu * * @hooked field callback wizard_add_pages_to_menu * @since 1.0 * */ public function wizard_add_pages_to_menu() { //this function is used as of 4.9.0 if ( ! function_exists( 'wp_get_nav_menu_name' ) ) { echo '<div class="field-group cmplz-link-to-menu">'; echo '<div class="cmplz-field"></div>'; cmplz_sidebar_notice( __( 'Your WordPress version does not support the functions needed for this step. You can upgrade to the latest WordPress version, or add the pages manually to a menu.', 'complianz-gdpr' ), 'warning' ); echo '</div>'; return; } //get list of menus $menus = wp_list_pluck( wp_get_nav_menus(), 'name', 'term_id' ); if ( empty( $menus ) ) { if ( current_theme_supports( 'menus' ) ) { $link = '<a href="' . admin_url( 'nav-menus.php' ) . '">'; } else { $link = '<a href="https://complianz.io/how-to-create-a-menu-in-wordpress/" target="_blank">'; } cmplz_notice( cmplz_sprintf( __( "No menus were found. Skip this step, or %screate a menu%s first." ), $link, '</a>' ) ); return; } $regions = cmplz_get_regions( true , true ); echo '<div class="cmplz-field">'; echo '<div class="cmplz-link-to-menu-table">'; foreach ( $regions as $region => $label ) { $pages = $this->get_created_pages( $region ); if ( count( $pages ) > 0 ) { echo '<h3>' . $label . '</h3>'; foreach ( $pages as $page_id ) { echo '<span>' . get_the_title( $page_id ) . '</span>'; ?> <select name="cmplz_assigned_menu[default][<?php echo $page_id ?>]"> <option value=""><?php _e( "Select a menu", 'complianz-gdpr' ); ?></option> <?php foreach ( $menus as $menu_id => $menu ) { $selected = $this->is_assigned_this_menu($page_id, $menu_id) ? "selected" : ""; echo "<option {$selected} value='{$menu_id}'>{$menu}</option>"; } ?> </select> <?php } } } echo '</div>'; echo '</div>'; } /** * * Show form to enable user to add pages to a menu, region redirected * * @hooked field callback wizard_add_pages_to_menu_region_redirected * @since 1.0 * */ public function wizard_add_pages_to_menu_region_redirected() { //this function is used as of 4.9.0 if ( ! function_exists( 'wp_get_nav_menu_name' ) ) { echo '<div class="field-group cmplz-link-to-menu-region">'; echo '<div class="cmplz-field"></div>'; cmplz_sidebar_notice( __( 'Your WordPress version does not support the functions needed for this step. You can upgrade to the latest WordPress version, or add the pages manually to a menu.', 'complianz-gdpr' ), 'warning' ); echo '</div>'; return; } //get list of menus $menus = wp_list_pluck( wp_get_nav_menus(), 'name', 'term_id' ); $mapping_array = COMPLIANZ::$config->generic_documents_list; if ( empty( $menus ) ) { if ( current_theme_supports( 'menus' ) ) { $link = '<a href="' . admin_url( 'nav-menus.php' ) . '">'; } else { $link = '<a href="https://complianz.io/how-to-create-a-menu-in-wordpress/" target="_blank">'; } cmplz_notice( cmplz_sprintf( __( "No menus were found. Skip this step, or %screate a menu%s first." ), $link, '</a>' ) ); return; } $page_types = $this->get_created_pages( false, true ); echo '<div class="cmplz-field">'; echo '<div class="cmplz-link-to-menu-table">'; if ( count( $page_types ) > 0 ) { foreach ( $page_types as $key => $page_type ) { if ( !$mapping_array[$page_type]['can_region_redirect'] ) { continue; } echo '<span>' . $mapping_array[$page_type]['title'] . '</span>'; ?> <select name="cmplz_assigned_menu[redirected][<?php echo $page_type ?>]"> <option value=""><?php _e( "Select a menu", 'complianz-gdpr' ); ?></option> <?php foreach ( $menus as $menu_id => $menu ) { $selected = $this->is_assigned_this_menu($page_type, $menu_id) ? "selected" : ""; echo "<option {$selected} value='{$menu_id}'>{$menu}</option>"; } ?> </select> <?php //if the document was found and can be redirected, we remove it from the pages list. unset($page_types[$key]); } } //if not all pages were in the generic document list, these should not be region redirected. if (count($page_types)>0){ foreach ($page_types as $page_type ) { $page_id = $this->get_page_id_for_generic_document($page_type); if ( $page_id ) { echo '<span>' . get_the_title( $page_id ) . '</span>'; ?> <select name="cmplz_assigned_menu[redirected][<?php echo $page_id ?>]"> <option value=""><?php _e( "Select a menu", 'complianz-gdpr' ); ?></option> <?php foreach ( $menus as $menu_id => $menu ) { $selected = $this->is_assigned_this_menu($page_id, $menu_id) ? "selected" : ""; echo "<option {$selected} value='{$menu_id}'>{$menu}</option>"; } ?> </select> <?php } } } echo '</div>'; echo '</div>'; } /** * Handle the submit of a form which assigns documents to a menu * * @hooked admin_init * */ public function assign_documents_to_menu() { if ( ! cmplz_user_can_manage() ) { return; } if ( !isset( $_POST['cmplz_assigned_menu'] ) ) { return; } if ( isset($_POST['cmplz_region_redirect']) && $_POST['cmplz_region_redirect'] === 'yes' ) { $type = 'redirected'; } else { $type = 'default'; } $this->clear_assigned_menu_items(); $assigned_menu = $_POST['cmplz_assigned_menu'][ $type ] ?? false; if ( is_array($assigned_menu) ) { foreach ( $assigned_menu as $page_id => $menu_id ) { if ( empty( $menu_id ) ) { continue; } if ( $this->is_assigned_this_menu( $page_id, $menu_id ) ) { continue; } if (is_numeric($page_id) ) { $page = get_post( $page_id ); wp_update_nav_menu_item( $menu_id, 0, array( 'menu-item-title' => get_the_title( $page ), 'menu-item-object-id' => $page->ID, 'menu-item-object' => get_post_type( $page ), 'menu-item-status' => 'publish', 'menu-item-type' => 'post_type', ) ); } else { $title = COMPLIANZ::$config->generic_documents_list[$page_id]['title']; $page_id = $this->get_page_id_for_generic_document( $page_id ); $url = add_query_arg( array('cmplz_region_redirect'=> 'true'), get_permalink($page_id) ); wp_update_nav_menu_item( $menu_id, 0, array( 'menu-item-title' => $title, 'menu-item-object' => 'object', 'menu-item-status' => 'publish', 'menu-item-type' => 'custom', 'menu-item-url' => $url, ) ); } } } } /** * Get all pages that are not assigned to any menu * * @return array|bool * @since 1.2 * * */ public function pages_not_in_menu() { //search in menus for the current post $menus = wp_list_pluck( wp_get_nav_menus(), 'name', 'term_id' ); $pages_in_menu = array(); $region_redirected = cmplz_get_value('region_redirect') === 'yes'; $pages = $this->get_created_pages(false , $region_redirected); if ( count( $pages ) > 0 ) { foreach ( $pages as $page_id ) { //check also for generic redirected documents $region_redirected_page_id = $this->get_page_id_for_generic_document($page_id); foreach ( $menus as $menu_id => $menu ) { if ( $this->is_assigned_this_menu( $page_id, $menu_id ) ) { $pages_in_menu[] = $page_id; } else if ($this->is_assigned_this_menu( $region_redirected_page_id, $menu_id )) { $pages_in_menu[] = $page_id; } } } } $pages_not_in_menu = array_diff( $pages, $pages_in_menu ); if ( count( $pages_not_in_menu ) == 0 ) { return false; } if ($region_redirected){ $output = array_map( function($page_not_in_menu){ return COMPLIANZ::$config->generic_documents_list[$page_not_in_menu]['title']; }, $pages_not_in_menu); } else { $output = array_map('get_the_title', $pages_not_in_menu); } return $output; } /** * * Check if a page is assigned to a menu * * @param int $page_id * @param int $menu_id * * @return bool * * @since 1.2 */ public function is_assigned_this_menu( $page_id, $menu_id ) { if (!cmplz_user_can_manage()) return false; if ( is_numeric($page_id) ) { $menu_items = wp_list_pluck( wp_get_nav_menu_items( $menu_id ), 'object_id' ); return ( in_array( $page_id, $menu_items ) ); } else { $page_id = $this->get_page_id_for_generic_document( $page_id ); $page = get_post($page_id); //get only custom links $menu_items = wp_get_nav_menu_items( $menu_id ); foreach ($menu_items as $key => $menu_item ) { if ($menu_item->type!=='custom') { unset($menu_items[$key]); } } $menu_items = wp_list_pluck( $menu_items, 'url' ); foreach( $menu_items as $url ) { if ( $page && strpos($url, $page->post_name) !== false && strpos( $url, 'cmplz_region_redirect') !== false ) { return true; } } return false; } } /** * Currently not active, not doing anything without explicit user action * * After switching the region_redirect option, clean all previous menu items to start fresh. */ public function clear_assigned_menu_items(){ if (!cmplz_user_can_manage()) return; //get all menus $menus = wp_list_pluck( wp_get_nav_menus(), 'name', 'term_id' ); $generic_documents = COMPLIANZ::$config->generic_documents_list; //clean up non geo ip. if ( cmplz_get_value('region_redirect') === 'yes' ) { $regions = cmplz_get_regions( true ); foreach ( $regions as $region => $label ) { $pages = $this->get_created_pages( $region ); foreach ( $pages as $page_id ) { foreach ( $menus as $menu_id => $menu ) { $menu_items = wp_get_nav_menu_items( $menu_id ); foreach ( $menu_items as $menu_item_id => $menu_item ) { if ( $menu_item->object_id == $page_id ) { wp_delete_post( $menu_item->ID ); } } } } } } //clean up geo ip items if ( cmplz_get_value('region_redirect') === 'no' ) { foreach ( $generic_documents as $type => $document ) { foreach ( $menus as $menu_id => $menu ) { $menu_items = wp_get_nav_menu_items( $menu_id ); $page_id = $this->get_page_id_for_generic_document( $type ); $page = get_post( $page_id ); if (!$page) continue; foreach ( $menu_items as $menu_item_id => $menu_item ) { if ( $menu_item->type === 'custom' ) { if ( strpos( $menu_item->url, $page->post_name ) !== false && strpos( $menu_item->url, 'cmplz_region_redirect' ) !== false ) { wp_delete_post( $menu_item->ID ); } } } } } } } /** * For use in region redirect functionality only. * We get the first page id for a page type * * @param $type * * @return bool|int */ public function get_page_id_for_generic_document($type){ $regions = cmplz_get_regions( true ); //first, try the default region. $default_region = COMPLIANZ::$company->get_default_region(); $detected_page_id = $this->get_shortcode_page_id( $type, $default_region); //if not found, try all other regions. if ( !$detected_page_id ) { foreach ( $regions as $region => $label ) { $detected_page_id = $this->get_shortcode_page_id( $type, $region ); if ($detected_page_id) { break; } } } return $detected_page_id; } /** * Create a page of certain type in wordpress * * @param string $type * @param string $region * * @return int|bool page_id * @since 1.0 */ public function create_page( $type, $region, $title ) { if ( ! cmplz_user_can_manage() ) { return false; } $pages = COMPLIANZ::$config->pages; if ( ! isset( $pages[ $region ][ $type ] ) ) { return false; } //only insert if there is no shortcode page of this type yet. $page_id = $this->get_shortcode_page_id( $type, $region, false ); if ( ! $page_id ) { $page = array( 'post_title' => $title, 'post_type' => "page", 'post_content' => $this->get_shortcode( $type, $region ), 'post_status' => 'publish', ); // Insert the post into the database $page_id = wp_insert_post( $page ); } do_action( 'cmplz_create_page', $page_id, $type, $region ); return $page_id; } /** * Delete a page of a type * * @param string $type * @param string $region * */ public function delete_page( $type, $region ) { if ( ! cmplz_user_can_manage() ) { return; } $page_id = $this->get_shortcode_page_id( $type, $region ); if ( $page_id ) { wp_delete_post( $page_id, false ); } } /** * * Check if page of certain type exists * * @param string $type * @param string $region * * @return bool * */ public function page_exists( $type, $region ) { if ( $this->get_shortcode_page_id( $type, $region ) ) { return true; } return false; } /** * get the shortcode or block for a page type * * @param string $type * @param string $region * @param bool $force_classic * * @return string $shortcode * */ public function get_shortcode( $type, $region, $force_classic = false ) { //even if on gutenberg, with elementor we have to use classic shortcodes. if ( ! $force_classic && cmplz_uses_gutenberg() && ! $this->uses_elementor() ) { $page = COMPLIANZ::$config->pages[ $region ][ $type ]; $ext = $region == 'eu' ? '' : '-' . $region; return '<!-- wp:complianz/document {"title":"' . $page['title'] . '","selectedDocument":"' . $type . $ext . '"} /-->'; } else { return '[cmplz-document type="' . $type . '" region="' . $region . '"]'; } } /** * Get shortcode pattern for this site, gutenberg or classic * * @param string $type * @param bool $legacy * * @return string */ public function get_shortcode_pattern( $type = "classic", $legacy = false ) { if ( $type === 'classic' && $legacy ) { return '/\[cmplz\-document.*?type="(.*?)".*?]/i'; } if ( $type === 'classic' && ! $legacy ) { return '/\[cmplz\-document.*?type="(.*?)".*?region="(.*?)".*?]/i'; } else { return '/<!-- wp:complianz\/document {.*?"selectedDocument":"([^\"].*?)\".*?} \/-->/i'; } } /** * Check if this site uses Elementor * When Elementor is used, the classic shortcode should be used, even when on Gutenberg * * @return bool $uses_elementor */ public function uses_elementor() { if ( defined( 'ELEMENTOR_VERSION' ) ) { return true; } return false; } /** * * Get type of document * * @param int $post_id * * @return array * * */ public function get_document_data( $post_id ) { $pattern = $this->get_shortcode_pattern('classic' ); $pattern_legacy = $this->get_shortcode_pattern('classic' , true ); $pattern_gutenberg = $this->get_shortcode_pattern('gutenberg' ); $post = get_post( $post_id ); $content = $post->post_content; $output = array( 'type' => '', 'region' => false, ); if ( preg_match_all( $pattern, $content, $matches, PREG_PATTERN_ORDER ) ) { if ( isset( $matches[1][0] ) ) { $output['type'] = $matches[1][0]; } if ( isset( $matches[2][0] ) ) { $output['region'] = $matches[2][0]; } } else if ( preg_match_all( $pattern_gutenberg, $content, $matches, PREG_PATTERN_ORDER ) ) { if ( isset( $matches[1][0] ) ) { $output['type'] = $matches[1][0]; } if ( isset( $matches[2][0] ) ) { $output['region'] = $matches[2][0]; } } else if ( preg_match_all( $pattern_legacy, $content, $matches, PREG_PATTERN_ORDER ) ) { if ( isset( $matches[1][0] ) ) { $output['type'] = $matches[1][0]; } if ( isset( $matches[2][0] ) ) { $output['region'] = $matches[2][0]; } } return $output; } /** * Get list of all created pages with page id for current setup * @param bool $filter_region * @param bool $get_type * @return array $pages * * */ public function get_created_pages( $filter_region = false, $get_type = false ) { $required_pages = COMPLIANZ::$document->get_required_pages(); $pages = array(); $types = array(); if ( $filter_region ) { if ( isset( $required_pages[ $filter_region ] ) ) { foreach ( $required_pages[ $filter_region ] as $type => $page ) { $page_id = $this->get_shortcode_page_id( $type, $filter_region , false); if ($page_id) $pages[] = $page_id; if ( $get_type ) $types[] = $type; } } } else { $regions = cmplz_get_regions(true); foreach ( $regions as $region => $label ) { if (!isset($required_pages[ $region ])) continue; foreach ( $required_pages[ $region ] as $type => $page ) { $page_id = $this->get_shortcode_page_id( $type, $region, false); if ($page_id) $pages[] = $page_id; if ( $get_type ) $types[] = $type; } } } if ( $get_type ) { return array_unique($types); } else { return $pages; } } /** * Get list of all required pages for current setup * * @return array $pages * * */ public function get_required_pages() { $regions = cmplz_get_regions( $add_all_cat = true ); $required = array(); foreach ( $regions as $region => $label ) { if ( ! isset( COMPLIANZ::$config->pages[ $region ] ) ) { continue; } $pages = COMPLIANZ::$config->pages[ $region ]; foreach ( $pages as $type => $page ) { if ( ! $page['public'] ) { continue; } if ( $this->page_required( $page, $region ) ) { $required[ $region ][ $type ] = $page; } } } return $required; } /** * Lightens/darkens a given colour (hex format), returning the altered colour in hex format.7 * * @param string $hex Colour as hexadecimal (with or without hash); * * @percent float $percent Decimal ( 0.2 = lighten by 20%(), -0.4 = darken by 40%() ) * @return string Lightened/Darkend colour as hexadecimal (with hash); */ function color_luminance( $hex, $percent ) { if ( empty( $hex ) ) { return $hex; } // validate hex string $hex = preg_replace( '/[^0-9a-f]/i', '', $hex ); $new_hex = '#'; if ( strlen( $hex ) < 6 ) { $hex = $hex[0] + $hex[0] + $hex[1] + $hex[1] + $hex[2] + $hex[2]; } // convert to decimal and change luminosity for ( $i = 0; $i < 3; $i ++ ) { $dec = hexdec( substr( $hex, $i * 2, 2 ) ); $dec = min( max( 0, $dec + $dec * $percent ), 255 ); $new_hex .= str_pad( dechex( $dec ), 2, 0, STR_PAD_LEFT ); } return $new_hex; } /** * loads document content on shortcode call * * @param array $atts * @param null $content * @param string $tag * * @return string $html * * */ public function load_document( $atts = array(), $content = null, $tag = '' ) { // normalize attribute keys, lowercase $atts = array_change_key_case( (array) $atts, CASE_LOWER ); ob_start(); // override default attributes with user attributes $atts = shortcode_atts( array( 'type' => false, 'region' => false ), $atts, $tag ); $type = sanitize_title( $atts['type'] ); $region = sanitize_title( $atts['region'] ); if ( $type ) { $html = $this->get_document_html( $type, $region ); $allowed_html = cmplz_allowed_html(); echo wp_kses( $html, $allowed_html ); } return ob_get_clean(); } /** * Show content conditionally, based on consent * @param array $atts * @param null $content * @param string $tag * * @return false|string */ public function show_consent_area_clientside( $atts = array(), $content = null, $tag = '' ) { $atts = array_change_key_case( (array) $atts, CASE_LOWER ); //should always be wrapped in closing tag if (empty($content)) { return ''; } $blocked_text = __('Click to accept the cookies for this service', 'complianz-gdpr'); // override default attributes with user attributes $atts = shortcode_atts( array( 'id' => 'default', 'service' => false, 'category' => false, 'text' => $blocked_text, ), $atts, $tag ); $category = $atts['category'] ? cmplz_sanitize_category($atts['category']) : 'marketing'; $service = $atts['service'] ? COMPLIANZ::$cookie_blocker->sanitize_service_name($atts['service']) : 'general'; $blocked_text = sanitize_text_field( $atts['text'] ); $blocked_text = apply_filters( 'cmplz_accept_cookies_blocked_content', $blocked_text ); $block_id = sanitize_title($atts['id']); global $post; $post_id = $post->ID ?? 0; ob_start(); ?> <div class="cmplz-consent-area cmplz-placeholder" data-post_id="<?php echo esc_attr($post_id)?>" data-block_id="<?php echo esc_attr($block_id)?>" data-category="<?php echo esc_attr($category)?>" data-service="<?php echo esc_attr($service)?>"> <a href="#" class="<?php echo 'cmplz_'. esc_attr($category);?>_consentarea" ><?php echo wp_kses_post($blocked_text)?></a> </div> <?php return ob_get_clean(); } /** * Show content conditionally, based on consent * @param array $atts * @param null $content * @param string $tag * * @return false|string */ public function show_consent_area( $atts = array(), $content = null, $tag = '' ) { // normalize attribute keys, lowercase $atts = array_change_key_case( (array) $atts, CASE_LOWER ); ob_start(); //should always be wrapped in closing tag if (empty($content)) return ''; $blocked_text = __('Click to accept the cookies for this service', 'complianz-gdpr'); // override default attributes with user attributes $atts = shortcode_atts( array( 'clientside' => false, 'cache_redirect' => false, 'scroll_into_view' => true, 'service' => 'general', 'category' => false, 'text' => $blocked_text, ), $atts, $tag ); //new option: clientside rendering of consent area, like in gutenberg. if ($atts['clientside']) { return $this->show_consent_area_clientside($atts, $content, $tag); } if ($atts['cache_redirect']==="true" || $atts['cache_redirect']=== 1 || $atts['cache_redirect']=== "1" || $atts['cache_redirect'] === true) { $cache_redirect = true; } else { $cache_redirect = false; } $scroll_into_view = $atts['scroll_into_view']==="true" || $atts['scroll_into_view']=== 1 || $atts['scroll_into_view'] === true; $category = $atts['category'] ? cmplz_sanitize_category($atts['category']) : 'no-category'; $service = $atts['category'] ? 'no-service' : COMPLIANZ::$cookie_blocker->sanitize_service_name($atts['service']); $blocked_text = sanitize_text_field( $atts['text'] ); if ( cmplz_has_service_consent($service) || cmplz_has_consent($category) ) { if ($cache_redirect) { //redirect if not on redirect url, to prevent caching issues ?> <script> var url = window.location.href; if (url.indexOf('cmplz_consent=1') === -1) { if (url.indexOf('?') !== -1) {url += '&';} else {url += '?';} url += 'cmplz_consent=1'; window.location.replace(url); } </script> <?php } echo '<a id="cmplz_consent_area_anchor"></a>'.do_shortcode($content); } else { //no consent $blocked_text = apply_filters( 'cmplz_accept_cookies_blocked_content', $blocked_text ); $redirect_uri = $scroll_into_view ? 'cmplz_consent=1#cmplz_consent_area_anchor' : 'cmplz_consent=1'; if ( $cache_redirect ) { ?> <script> var url = window.location.href; var consented_area_visible = document.getElementById('cmplz_consent_area_anchor'); if (url.indexOf('cmplz_consent=1') !== -1 && !consented_area_visible ) { url = url.replace('cmplz_consent=1', ''); url = url.replace('#cmplz_consent_area_anchor', ''); url = url.replace('?&', '?'); url = url.replace('&&', '?'); //if last character is ? or &, drop it if (url.substring(url.length-1) === "&" || url.substring(url.length-1) === "?") { url = url.substring(0, url.length-1); } window.location.replace(url); } document.addEventListener("cmplz_enable_category", cmplzEnableCustomBlockedContent); function cmplzEnableCustomBlockedContent(e) { if ( cmplz_has_service_consent('<?php echo esc_attr($service)?>' ) || cmplz_has_consent('<?php echo esc_attr($category)?>' )){ if (url.indexOf('cmplz_consent=1') === -1 ) { if (url.indexOf('?') !== -1) {url += '&';} else {url += '?';} url += '<?php echo $redirect_uri?>'; window.location.replace(url); } } } </script> <?php } else { ?> <script> document.addEventListener("cmplz_enable_category", cmplzEnableCustomBlockedContent); function cmplzEnableCustomBlockedContent(e) { if ( cmplz_has_service_consent('<?php echo esc_attr($service)?>', 'marketing' ) && !document.getElementById("cmplz_consent_area_anchor") ){ location.reload(); } if ( e.detail.category === '<?php echo esc_attr($category)?>' && !document.getElementById("cmplz_consent_area_anchor") ){ location.reload(); } } </script> <?php } ?> <div class="cmplz-consent-area"> <?php if ($atts['category']) {?> <a href="#" data-category="<?php echo esc_attr($category)?>" class="cmplz-accept-category <?php echo ' cmplz_'. esc_attr($category);?>_consentarea" ><?php echo wp_kses_post($blocked_text)?></a> <?php } else {?> <a href="#" data-service="<?php echo esc_attr($service)?>" class="cmplz-accept-service <?php echo ' cmplz_'. esc_attr($service);?>_consentarea" ><?php echo wp_kses_post($blocked_text)?></a> <?php }?> </div> <?php } return ob_get_clean(); } /** * Check if we should use caching * @param string $type * * @return bool */ private function use_cache( $type ) { //do not cache on multilanguage environments if ( function_exists( 'pll__' ) || function_exists( 'icl_translate' ) ) { return false; } if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) { return false; } //do not cache for these types if ( ( $type === 'processing' ) || ( $type === 'dataleak' ) ) { return false; } return true; } /** * checks if the current page contains the shortcode. * * @param int|bool $post_id * * @return boolean * @since 1.0 */ public function is_complianz_page( $post_id = false ) { $shortcode = 'cmplz-document'; $block = 'complianz/document'; $cookies_shortcode = 'cmplz-cookies'; if ( $post_id ) { $post = get_post( $post_id ); } else { global $post; $post_id = $post->ID ?? false; } $post_meta = get_post_meta( $post_id, 'cmplz_shortcode', true ); if ( $post_meta ) { return true; } if ( $post && isset($post->post_content)) { //terms conditions has it's own shortcode. if (strpos($post->post_content, '[cmplz-terms-conditions') !== FALSE ) { return false; } if (strpos($post->post_content, '[cmplz-consent-area') !== FALSE ) { return false; } if ( cmplz_uses_gutenberg() && has_block( $block, $post ) ) { return true; } if ( has_shortcode( $post->post_content, $shortcode ) ) { return true; } if ( has_shortcode( $post->post_content, $cookies_shortcode ) ) { return true; } if (strpos($post->post_content, '[cmplz-') !== FALSE ) { return true; } } return false; } /** * gets the page that contains the shortcode or the gutenberg block * * @param string $type * @param string $region * * @return int $page_id * @since 1.0 */ public function get_shortcode_page_id( $type, $region , $cache = true) { $shortcode = 'cmplz-document'; $page_id = $cache ? get_transient( 'cmplz_shortcode_' . $type . '-' . $region ) : false; if ( $page_id === 'none') { return false; } if ( ! $page_id ) { //ensure a transient, in case none is found. This prevents continuing requests on the page list set_transient( "cmplz_shortcode_$type-$region", 'none', HOUR_IN_SECONDS ); $pages = get_pages(); $type_region = ( $region === 'eu' ) ? $type : $type . '-' . $region; /** * Gutenberg block check * * */ foreach ( $pages as $page ) { $post_meta = get_post_meta( $page->ID, 'cmplz_shortcode', true ); if ( $post_meta ) { $html = $post_meta; } else { $html = $page->post_content; } //check if block contains property if ( preg_match( '/"selectedDocument":"(.*?)"/i', $html, $matches ) ) { if ( $matches[1] === $type_region ) { set_transient( "cmplz_shortcode_$type-$region", $page->ID, HOUR_IN_SECONDS ); return $page->ID; } } } /** * If nothing found, or if not Gutenberg, check for shortcodes. * Classic Editor, modern shortcode check * * */ foreach ( $pages as $page ) { $post_meta = get_post_meta( $page->ID, 'cmplz_shortcode', true ); if ( $post_meta ) { $html = $post_meta; } else { $html = $page->post_content; } if ( has_shortcode( $html, $shortcode ) && strpos( $html, 'type="' . $type . '"' ) !== false && strpos( $html, 'region="' . $region . '"' ) !== false ) { set_transient( "cmplz_shortcode_$type-$region", $page->ID, HOUR_IN_SECONDS ); return $page->ID; } } /** * legacy check */ foreach ( $pages as $page ) { $post_meta = get_post_meta( $page->ID, 'cmplz_shortcode', true ); if ( $post_meta ) { $html = $post_meta; } else { $html = $page->post_content; } //if the region is eu, we should not match if there's a region defined. if ( $region==='eu' && strpos($html, ' region="') !== FALSE ) { continue; } if ( has_shortcode( $html, $shortcode ) && strpos( $html, 'type="' . $type_region . '"' ) !== false ) { set_transient( "cmplz_shortcode_$type-$region", $page->ID, HOUR_IN_SECONDS ); return $page->ID; } } } else { return $page_id; } return false; } /** * clear shortcode transients after page update * * @param int|bool $post_id * @param object|bool $post * * @hooked save_post which is why the $post param is passed without being used. * * @return void */ public function clear_shortcode_transients( $post_id = false, $post = false ) { $regions = cmplz_get_regions(); foreach ( $regions as $region => $label ) { foreach ( COMPLIANZ::$config->pages[ $region ] as $type => $page ) { //if a post id is passed, this is from the save post hook. We only clear the transient for this specific post id. if ( $post_id ) { if ( get_transient( "cmplz_shortcode_$type-$region" ) == $post_id ) { delete_transient( "cmplz_shortcode_$type-$region" ); } } else { delete_transient( "cmplz_shortcode_$type-$region" ); } } } } /** * * get the URl of a specific page type * * @param string $type cookie-policy, privacy-statement, etc * @param string $region * @return string * * */ public function get_page_title( $type, $region ) { if ( ! cmplz_has_region( $region ) ) { return ''; } if ( cmplz_get_value( $type ) === 'none' ) { return '#'; } if ( cmplz_get_value( $type ) === 'custom' ) { $id = get_option( "cmplz_" . $type . "_custom_page" ); //get correct translated id $id = apply_filters( 'wpml_object_id', $id, 'page', true, substr( get_locale(), 0, 2 ) ); $title = intval( $id ) == 0 ? '' : get_the_title( $id ); } else if ( cmplz_get_value( $type ) === 'url' ) { $title = COMPLIANZ::$config->generic_documents_list[$type]['title']; } else { $policy_page_id = $this->get_shortcode_page_id( $type, $region ); //get correct translated id $policy_page_id = apply_filters( 'wpml_object_id', $policy_page_id, 'page', true, substr( get_locale(), 0, 2 ) ); if ( !$policy_page_id ) { return ''; } $title = get_the_title( $policy_page_id ); } return preg_replace( '/(\(.*\))/i', '', cmplz_translate($title, 'cmplz_link_title_'.$type) ); } /** * * get the URl of a specific page type * * @param string $type cookie-policy, privacy-statement, etc * @param string $region * @return string * * */ public function get_page_url( $type, $region ) { if ( ! cmplz_has_region( $region ) ) { return '#'; } if ( cmplz_get_value( $type ) === 'none' ) { return '#'; } if ( cmplz_get_value( $type ) === 'custom' ) { $id = get_option( "cmplz_" . $type . "_custom_page" ); //get correct translated id $id = apply_filters( 'wpml_object_id', $id, 'page', true, substr( get_locale(), 0, 2 ) ); return (int) $id == 0 || !get_permalink( $id ) ? '#' : esc_url_raw( get_permalink( $id ) ); } if ( cmplz_get_value( $type ) === 'url' ) { $url = get_option("cmplz_".$type."_custom_page_url"); return esc_url_raw( cmplz_translate( $url, "cmplz_".$type."_custom_page_url") ); } $policy_page_id = $this->get_shortcode_page_id( $type, $region ); //get correct translated id $policy_page_id = apply_filters( 'wpml_object_id', $policy_page_id, 'page', true, substr( get_locale(), 0, 2 ) ); $permalink = get_permalink( $policy_page_id ); return $permalink ?: '#'; } /** * Set default privacy page for WP, based on primary region * @param $page_id * @param $type * @param $region */ public function set_wp_privacy_policy($page_id, $type, $region=false){ $primary_region = COMPLIANZ::$company->get_default_region(); if ($region && $region !== $primary_region) return; if ($type === 'privacy-statement') { update_option('wp_page_for_privacy_policy', intval($page_id)); } } /** * Check if all required pages are creatd */ public function all_required_pages_created(){ $pages = $this->get_required_pages(); $total_pages = $existing_pages= 0; foreach ( $pages as $region => $region_pages ) { foreach ( $region_pages as $type => $page ) { if ( COMPLIANZ::$document->page_exists( $type, $region ) ) { $existing_pages ++; } $total_pages ++; } } return $total_pages === $existing_pages; } /** * * get the title of a specific page type. Only in use for generated docs from Complianz. * * @param string $type cookie-policy, privacy-statement, etc * @param string $region * * @return string $title */ public function get_document_title( $type, $region ) { if ( cmplz_get_value( $type ) === 'custom' || cmplz_get_value( $type ) === 'generated' ) { if ( cmplz_get_value( $type ) === 'custom' ) { $policy_page_id = get_option( "cmplz_" . $type . "_custom_page" ); } else if ( cmplz_get_value( $type ) === 'generated' ) { $policy_page_id = $this->get_shortcode_page_id( $type, $region ); } //get correct translated id $policy_page_id = apply_filters( 'wpml_object_id', $policy_page_id, 'page', true, substr( get_locale(), 0, 2 ) ); $post = get_post( $policy_page_id ); if ( $post ) { return $post->post_title; } } return str_replace('-', ' ', $type); } /** * Function to generate a pdf file, either saving to file, or echo to browser * * @param $page * @param $region * @param $post_id * @param $save_to_file * @param $intro * @param $append //if we want to add addition html * * @throws \Mpdf\MpdfException */ public function generate_pdf( $page, $region, $post_id = false, $save_to_file = false, $intro = '', $append = '' ) { if ( ! defined( 'DOING_CRON' ) ) { if ( ! cmplz_user_can_manage() ) { die( "invalid command" ); } } $error = false; $temp_dir = false; if ( ! isset( COMPLIANZ::$config->pages[ $region ] ) ) { return; } $pages = COMPLIANZ::$config->pages[ $region ]; //double check if it exists if ( ! isset( $pages[ $page ] ) ) { return; } $title = $pages[ $page ]['title']; $document_html = $intro . COMPLIANZ::$document->get_document_html( $page, $region, $post_id ) . $append; $document_html = apply_filters( 'cmplz_cookie_policy_snapshot_html', $document_html , $save_to_file ); //prevent hidden fields $document_html = str_replace('cmplz-service-hidden', '', $document_html); $load_css = cmplz_get_value( 'use_document_css' ); $css = ''; if ( $load_css ) { $css = file_get_contents( cmplz_path . "assets/css/document.css" ); } $title_html = $save_to_file ? '' : '<h4 class="center">' . $title . '</h4>'; $html = ' <style> ' . $css . ' #cmplz-datarequest-form, #cmplz-manage-consent-container-nojavascript, #cmplz-tcf-vendor-container { display:none; } body { font-family: sans; margin-top:100px; color :#000; } h2 { font-size:12pt; } h3 { font-size:12pt; } h4 { font-size:10pt; font-weight: bold; } .center { text-align:center; } #cmplz-tcf-buttons-template, #cmplz-tcf-vendor-template, #cmplz-tcf-type-template { display:none !important; } </style> <body id="cmplz-document"> ' . $title_html . ' ' . $document_html . ' </body>'; //============================================================== //============================================================== //============================================================== $html = preg_replace('/<input type="checkbox".*?>/', '', $html); require cmplz_path . '/assets/vendor/autoload.php'; //generate a token when it's not there, otherwise use the existing one. if ( get_option( 'cmplz_pdf_dir_token' ) ) { $token = get_option( 'cmplz_pdf_dir_token' ); } else { $token = time(); update_option( 'cmplz_pdf_dir_token', $token ); } $cmplz_dir = cmplz_upload_dir(); if ( !is_writable ($cmplz_dir) ) { $error = true; } if ( ! $error ) { if ( ! file_exists( $cmplz_dir . 'tmp' ) ) { mkdir( $cmplz_dir . 'tmp',0755 ); } if ( ! file_exists( $cmplz_dir . 'snapshots' ) ) { mkdir( $cmplz_dir . 'snapshots',0755 ); } $save_dir = $cmplz_dir . 'snapshots/'; $temp_dir = $cmplz_dir . 'tmp/' . $token; if ( ! file_exists( $temp_dir ) ) { mkdir( $temp_dir,0755 ); } } if ( ! $error && $temp_dir) { $mpdf = new Mpdf\Mpdf( array( 'setAutoTopMargin' => 'stretch', 'autoMarginPadding' => 5, 'tempDir' => $temp_dir, 'margin_left' => 20, 'margin_right' => 20, 'margin_top' => 30, 'margin_bottom' => 30, 'margin_header' => 30, 'margin_footer' => 10, ) ); $mpdf->SetDisplayMode( 'fullpage' ); $mpdf->SetTitle( $title ); $img = '';//'<img class="center" src="" width="150px">'; $date = date_i18n( get_option( 'date_format' ), time() ); $mpdf->SetHTMLHeader( $img ); $footer_text = cmplz_sprintf( "%s $title $date", get_bloginfo( 'name' ) ); $mpdf->SetFooter( $footer_text ); $mpdf->WriteHTML( $html ); // Save the pages to a file if ( $save_to_file ) { $file_title = $save_dir . sanitize_file_name( get_bloginfo( 'name' ) . '-' . $region . "-proof-of-consent-" . $date ); } else { $file_title = sanitize_file_name( get_bloginfo( 'name' ) . "-export-" . $date ); } $output_mode = $save_to_file ? 'F' : 'I'; $mpdf->Output( $file_title . ".pdf", $output_mode ); //clean up temp dir $this->delete_files_directories_recursively($temp_dir); } else { $_POST['cmplz_generate_snapshot_error'] = true; unset( $_POST['cmplz_generate_snapshot'] ); } } /** * @param string $dir * Delete files and directories recursively. Used to clear the tmp folder * @since 6.3.0 */ private function delete_files_directories_recursively( $dir ) { if ( strpos( $dir, 'complianz/tmp' ) !== false ) { foreach ( glob( $dir . '/*' ) as $file ) { if ( is_dir( $file ) ) { $this->delete_files_directories_recursively( $file ); } else { unlink( $file ); } } rmdir( $dir ); } } /** * Replace custom summary shortcode back to summary tags * * @return string */ public function revert_divs_to_summary( $content ): string { // Make sure content is a string $content = $content ?? ''; //only on front-end if ( is_admin() ) { return $content; } // only for classic. if ( cmplz_uses_gutenberg() ) { return $content; } // Return $data if this is not a Complianz document global $post; if ( !$post || !property_exists($post, 'ID')) { return $content; } if ( !COMPLIANZ::$document->is_complianz_page($post->ID ) ) { return $content; } // Check if post is unlinked, otherwise return if ( get_post_meta($post->ID, 'cmplz_document_status', true ) !== 'unlink') { return $content; } //quotest get encoded for some strange reason. Decode. $content = str_replace( '”', '"', $content ); $content = preg_replace('/\[cmplz-details-open([^>]*?)\]/', '<details $1>', $content); $content = preg_replace('/\[cmplz-details-close\]/', '</details>', $content); // Replace <summary> tags with custom <div> $content = preg_replace('/\[cmplz-summary-open([^>]*?)\]/', '<summary $1>', $content); $content = preg_replace('/\[cmplz-summary-close\]/', '</summary>', $content); return $content; } /** * Replace <summary> tags with summary shortcode to fix the issue with tinyMce, which drops summary because it is not supported. * * @param string $content * @param int $post_id * * @return string */ public function convert_summary_to_div( string $content, int $post_id): string { //only on back-end if (!cmplz_user_can_manage()) { return $content; } // only for classic. if ( cmplz_uses_gutenberg() ) { return $content; } // Return content if this is not a Complianz document if ( !COMPLIANZ::$document->is_complianz_page($post_id ) ) { return $content; } $content = preg_replace('/<details([^>]*?)>/', '[cmplz-details-open$1]', $content); $content = preg_replace('/<\/details>/', '[cmplz-details-close]', $content); // Replace <summary> tags with custom <div> $content = preg_replace('/<summary([^>]*?)>/', '[cmplz-summary-open$1]', $content); return preg_replace('/<\/summary>/', '[cmplz-summary-close]', $content); } } }