'appointments_gdpr_nod_was_changed', 'auto_erase' => 'appointments_gdpr_auto_erase_was_changed', ); public function __construct() { global $wp_version; $is_less_496 = version_compare( $wp_version, '4.9.6', '<' ); if ( $is_less_496 ) { return; } /** * GDPR - delete */ if ( ! wp_next_scheduled( $this->gdpr_delete ) ) { wp_schedule_event( time(), 'hourly', $this->gdpr_delete ); } add_action( $this->gdpr_delete, array( $this, 'gdpr_check_and_delete' ) ); /** * Add information to privacy policy page (only during creation). */ add_filter( 'wp_get_default_privacy_policy_content', array( $this, 'add_policy' ) ); /** * Adding the Personal Data Exporter */ add_filter( 'wp_privacy_personal_data_exporters', array( $this, 'register_plugin_exporter' ), 10 ); /** * Adding the Personal Data Eraser */ add_filter( 'wp_privacy_personal_data_erasers', array( $this, 'register_plugin_eraser' ), 10 ); /** * check changes */ add_filter( 'app-options-before_save', array( $this, 'check_options_changes' ) ); /** * show notice */ add_action( 'admin_notices', array( $this, 'show_notices' ) ); /** * save notice status */ add_action( 'wp_ajax_gdpr_number_of_days_user_erease', array( $this, 'delete_notice_when_we_changed_user_delete_number_of_days' ) ); add_action( 'wp_ajax_gdpr_number_of_days_auto_erease', array( $this, 'delete_notice_when_we_changed_auto_delete_number_of_days' ) ); } /** * Delete user option after clic. * * @since 2.3.0 */ public function delete_notice_when_we_changed_auto_delete_number_of_days() { if ( isset( $_POST['nonce'] ) && wp_verify_nonce( $_POST['nonce'], $this->gdpr_admin_notice_names['auto_erase'] ) && isset( $_POST['user_id'] ) ) { $user_id = filter_input( INPUT_POST, 'user_id', FILTER_VALIDATE_INT ); delete_user_option( $user_id, $this->gdpr_admin_notice_names['auto_erase'] ); } wp_send_json_success(); } /** * Delete user option after clic. * * @since 2.3.0 */ public function delete_notice_when_we_changed_user_delete_number_of_days() { if ( isset( $_POST['nonce'] ) && wp_verify_nonce( $_POST['nonce'], $this->gdpr_admin_notice_names['user_erase'] ) && isset( $_POST['user_id'] ) ) { $user_id = filter_input( INPUT_POST, 'user_id', FILTER_VALIDATE_INT ); delete_user_option( $user_id, $this->gdpr_admin_notice_names['user_erase'] ); } wp_send_json_success(); } /** * Check options changes to show admin notice * * @since 2.3.0 */ public function check_options_changes( $options ) { /** * User can erase after */ $current = appointments_get_option( 'gdpr_number_of_days_user_erease' ); /** * check changes in gdpr_number_of_days_user_erease */ $change = $current !== $options['gdpr_number_of_days_user_erease']; if ( $change ) { $user_id = get_current_user_id(); update_user_option( $user_id, $this->gdpr_admin_notice_names['user_erase'], 'show' ); } /** * Auto erase after */ /** * User can erase after */ $current = appointments_get_option( 'gdpr_number_of_days' ); /** * check changes in gdpr_number_of_days_user_erease */ $change = $current !== $options['gdpr_number_of_days']; if ( $change ) { $user_id = get_current_user_id(); update_user_option( $user_id, $this->gdpr_admin_notice_names['auto_erase'], 'show' ); } /** * return */ return $options; } /** * Show admin notice - template * * @since 2.3.0 */ private function notice_template() { $content = '
'; $content .= wpautop( __( 'Appointments/GDPR setting "%s" was changed - please update your %s', 'appointments' ) ); $content .= '
'; return $content; } /** * Show admin notice * * @since 2.3.0 */ public function show_notices() { if ( ! function_exists( 'get_privacy_policy_url' ) ) { return; } $policy_page = get_privacy_policy_url(); if ( empty( $policy_page ) ) { return; } $screen = get_current_screen(); if ( ! is_a( $screen, 'WP_Screen' ) ) { return; } if ( ! preg_match( '/appointments/', $screen->base ) ) { return; } $user_id = get_current_user_id(); $template = $this->notice_template(); /** * Privacy Policy Page */ $link = sprintf( '%s', esc_attr( $policy_page ), esc_html__( 'Privacy Policy page', 'appointments' ) ); /** * template */ /** * User can erase after */ $show = get_user_option( $this->gdpr_admin_notice_names['user_erase'] ); if ( 'show' === $show ) { printf( $template, esc_attr( 'gdpr_number_of_days_user_erease' ), wp_create_nonce( $this->gdpr_admin_notice_names['user_erase'] ), esc_attr( $user_id ), esc_attr__( 'User can erase after', 'appointments' ), $link ); } /** * Auto erase after */ $show = get_user_option( $this->gdpr_admin_notice_names['auto_erase'] ); if ( 'show' === $show ) { printf( $template, esc_attr( 'gdpr_number_of_days_auto_erease' ), wp_create_nonce( $this->gdpr_admin_notice_names['auto_erase'] ), esc_attr( $user_id ), esc_attr__( 'Auto erase after', 'appointments' ), $link ); } } /** * Get number of days of auto-erase data. * * @since 2.3.0 */ private function get_number_of_days() { $value = appointments_get_option( 'gdpr_delete' ); if ( 'yes' !== $value ) { return 0; } return intval( appointments_get_option( 'gdpr_number_of_days' ) ); } /** * Get plugin friendly name */ private function get_plugin_friendly_name() { $name = _x( 'Appointments Plugin', 'Free plugin name in personal data exporter.', 'appointments' ); $is_pro = apply_filters( 'appointments_is_pro', false ); if ( $is_pro ) { $name = _x( 'Appointments+ Plugin', 'Pro plugin name in personal data exporter.', 'appointments' ); } return $name; } /** * Register plugin exporter. * * @since 2.3.0 */ public function register_plugin_exporter( $exporters ) { $exporters['appointments'] = array( 'exporter_friendly_name' => $this->get_plugin_friendly_name(), 'callback' => array( $this, 'plugin_exporter' ), ); return $exporters; } /** * Export personal data. * * @since 2.3.0 */ public function plugin_exporter( $email, $page = 1 ) { $appointments = appointments_get_appointments( array( 'email' => $email ) ); $export_items = array(); if ( count( $appointments ) ) { foreach ( $appointments as $appointment ) { $item = array( 'group_id' => 'appointments', 'group_label' => $this->get_plugin_friendly_name(), 'item_id' => 'appointments-'.$appointment->ID, 'data' => array( array( 'name' => __( 'Name', 'appointments' ), 'value' => $appointment->name, ), array( 'name' => __( 'Email', 'appointments' ), 'value' => $appointment->email, ), array( 'name' => __( 'Phone', 'appointments' ), 'value' => $appointment->phone, ), array( 'name' => __( 'Address', 'appointments' ), 'value' => $appointment->address, ), array( 'name' => __( 'City', 'appointments' ), 'value' => $appointment->city, ), array( 'name' => __( 'Note', 'appointments' ), 'value' => $appointment->notes, ), array( 'name' => __( 'Create date', 'appointments' ), 'value' => $appointment->created, ), array( 'name' => __( 'Start date', 'appointments' ), 'value' => $appointment->start, ), array( 'name' => __( 'End date', 'appointments' ), 'value' => $appointment->end, ), ), ); /** * Export single appointment row. * * @since 2.3.0 * * @param array $item Export data for appointment. * @param string $email Appointment email. * @param object $appointment Single appointment data object. */ $export_items[] = apply_filters( 'appointments_gdpr_export', $item, $email, $appointment ); } } $export = array( 'data' => $export_items, 'done' => true, ); return $export; } /** * Register plugin eraser. * * @since 2.3.0 */ public function register_plugin_eraser( $erasers ) { $erasers['appointments'] = array( 'eraser_friendly_name' => $this->get_plugin_friendly_name(), 'callback' => array( $this, 'plugin_eraser' ), ); return $erasers; } /** * Erase personal data. * * @since 2.3.0 */ public function plugin_eraser( $email, $page = 1 ) { global $wpdb; $days = intval( appointments_get_option( 'gdpr_number_of_days_user_erease' ) ); if ( 1 > $days ) { return; } $messages = array(); $table = appointments_get_table( 'appointments' ); /** * count days */ $days = sprintf( '-%d day', $days ); $date = date( 'Y-m-d H:i', strtotime( $days ) ); /** * delete */ $sql = $wpdb->prepare( "select ID from {$table} where email = %s and start < %s", $email, $date ); $results = $wpdb->get_col( $sql ); $count = 0; foreach ( $results as $id ) { $result = appointments_delete_appointment( $id ); if ( $result ) { $count++; } } if ( 0 < $count ) { $messages[] = sprintf( _n( 'We deleted %d appointment.', 'We deleted %d appointments', $count, 'appointments' ), $count ); } else { $messages[] = __( 'We do not deleted any appointments.', 'appointments' ); } /** * check how much left */ $sql = $wpdb->prepare( "select count(ID) from {$table} where email = %s", $email ); $items_retained = $wpdb->get_var( $sql ); if ( 0 < $items_retained ) { $messages[] = sprintf( _n( 'We do not deleted %d appointment.', 'We do not deleted %d appointments', $count, 'appointments' ), $count ); } /** * return */ return array( 'items_removed' => $count, 'items_retained' => $items_retained, 'messages' => $messages, 'done' => true, ); } /** * Try to delete older appointments. * * @since 2.3.0 */ public function gdpr_check_and_delete() { global $wpdb; $days = $this->get_number_of_days(); if ( 1 > $days ) { return; } $days = sprintf( '-%d day', $days ); $table = appointments_get_table( 'appointments' ); $date = date( 'Y-m-d H:i', strtotime( $days ) ); $sql = $wpdb->prepare( "select ID from {$table} where start < %s", $date ); $results = $wpdb->get_col( $sql ); foreach ( $results as $id ) { appointments_delete_appointment( $id ); } } /** * Add Appointments Policy to "Privace Policy" page during creation. * * @since 2.3.0 */ public function add_policy( $content ) { $content .= '

' . __( 'Plugin: Appointments', 'appointments' ) . '

'; $content .= '

'.__( 'When visitors book an appointment on the site we collect the data shown in the appointments form to allow future contact with a client.' ) . '

' . '

' . __( 'All collected data is not shown publicly but we can send it to our workers or contractors who will perform ordered services.', 'appointments' ) . '

'; $days = $this->get_number_of_days(); if ( 0 < $days ) { $days_desc = sprintf( _nx( '%d day', '%d days', $days, 'policy page days string', 'appointments' ), $days ); $content .= sprintf( '

' . __( 'All collected data will be automatically erased %s after appointment date.', 'appointments' ) . '

', $days_desc ); } return $content; } }