__( 'AcquisitionSuite contacts and submissions', 'acquisitionsuite' ), 'callback' => array( __CLASS__, 'export' ), ); return $exporters; } public static function register_eraser( $erasers ) { $erasers['acquisitionsuite'] = array( 'eraser_friendly_name' => __( 'AcquisitionSuite contacts and submissions', 'acquisitionsuite' ), 'callback' => array( __CLASS__, 'erase' ), ); return $erasers; } private static function leads_for( $email ) { global $wpdb; return (array) $wpdb->get_results( $wpdb->prepare( 'SELECT * FROM %i WHERE email = %s ORDER BY id ASC', $wpdb->prefix . 'acquis_leads', $email ) ); } private static function pairs( array $map ) { $out = array(); foreach ( $map as $name => $value ) { if ( null === $value || '' === (string) $value ) { continue; } $out[] = array( 'name' => $name, 'value' => is_scalar( $value ) ? (string) $value : wp_json_encode( $value ) ); } return $out; } // ── Export ───────────────────────────────────────────────────────────── public static function export( $email, $page = 1 ) { global $wpdb; $email = sanitize_email( (string) $email ); $leads = is_email( $email ) ? self::leads_for( $email ) : array(); $groups = array(); foreach ( $leads as $lead ) { $groups[] = array( 'group_id' => 'acquis-contact', 'group_label' => __( 'AcquisitionSuite contact', 'acquisitionsuite' ), 'group_description' => __( 'The contact record kept when this person used a form or made a purchase.', 'acquisitionsuite' ), 'item_id' => 'acquis-contact-' . $lead->id, 'data' => self::pairs( array( __( 'Name', 'acquisitionsuite' ) => $lead->full_name, __( 'Email', 'acquisitionsuite' ) => $lead->email, __( 'IP address', 'acquisitionsuite' ) => $lead->ip_address, __( 'Browser', 'acquisitionsuite' ) => trim( $lead->browser . ' ' . $lead->os . ' ' . $lead->device ), __( 'User agent', 'acquisitionsuite' ) => $lead->user_agent, __( 'Location', 'acquisitionsuite' ) => trim( implode( ', ', array_filter( array( $lead->city, $lead->region, $lead->country ) ) ) ), __( 'Visits', 'acquisitionsuite' ) => $lead->visit_count, __( 'Value to the business', 'acquisitionsuite' ) => $lead->deal_value, __( 'First seen', 'acquisitionsuite' ) => $lead->created_at, __( 'Last seen', 'acquisitionsuite' ) => $lead->last_seen_at, ) ), ); $subs = (array) $wpdb->get_results( $wpdb->prepare( 'SELECT * FROM %i WHERE lead_id = %d ORDER BY id ASC', $wpdb->prefix . 'acquis_submissions', $lead->id ) ); foreach ( $subs as $sub ) { $data = array( __( 'Date', 'acquisitionsuite' ) => $sub->created_at, __( 'Page', 'acquisitionsuite' ) => $sub->source_url, __( 'Referrer', 'acquisitionsuite' ) => $sub->referrer, __( 'Campaign', 'acquisitionsuite' ) => trim( implode( ' / ', array_filter( array( $sub->utm_source, $sub->utm_medium, $sub->utm_campaign ) ) ) ), __( 'IP address', 'acquisitionsuite' ) => $sub->ip_address, __( 'Came from', 'acquisitionsuite' ) => $sub->source, ); $values = (array) $wpdb->get_results( $wpdb->prepare( 'SELECT field_key, field_label, value FROM %i WHERE submission_id = %d ORDER BY id ASC', $wpdb->prefix . 'acquis_submission_values', $sub->id ) ); foreach ( $values as $v ) { $data[ '' !== $v->field_label ? $v->field_label : $v->field_key ] = $v->value; } $groups[] = array( 'group_id' => 'acquis-submissions', 'group_label' => __( 'AcquisitionSuite submissions', 'acquisitionsuite' ), 'group_description' => __( 'What this person submitted through forms, and details recorded from orders.', 'acquisitionsuite' ), 'item_id' => 'acquis-submission-' . $sub->id, 'data' => self::pairs( $data ), ); } $logs = (array) $wpdb->get_results( $wpdb->prepare( 'SELECT * FROM %i WHERE lead_id = %d ORDER BY id ASC', $wpdb->prefix . 'acquis_email_logs', $lead->id ) ); foreach ( $logs as $log ) { $groups[] = array( 'group_id' => 'acquis-emails', 'group_label' => __( 'Emails sent by AcquisitionSuite', 'acquisitionsuite' ), 'group_description' => __( 'A record of the emails sent to this person.', 'acquisitionsuite' ), 'item_id' => 'acquis-email-' . $log->id, 'data' => self::pairs( array( __( 'Subject', 'acquisitionsuite' ) => $log->subject, __( 'Status', 'acquisitionsuite' ) => $log->status, __( 'Sent', 'acquisitionsuite' ) => $log->created_at, __( 'Opened', 'acquisitionsuite' ) => $log->opened_at, __( 'Link clicks', 'acquisitionsuite' ) => $log->click_count ? $log->click_count : '', ) ), ); } } /** * Add export groups for the same person: Pro's tags, scores and orders, an add-on's own records. * * @param array $groups Items in WordPress's export format (group_id, group_label, item_id, data). * @param string $email * @param array $leads This person's rows from the leads table (may be empty). */ $groups = (array) apply_filters( 'acquis_privacy_export_email', $groups, $email, $leads ); return array( 'data' => $groups, 'done' => true ); } // ── Erase ────────────────────────────────────────────────────────────── public static function erase( $email, $page = 1 ) { global $wpdb; $email = sanitize_email( (string) $email ); $leads = is_email( $email ) ? self::leads_for( $email ) : array(); $result = array( 'items_removed' => false, 'items_retained' => false, 'messages' => array(), 'done' => true ); foreach ( $leads as $lead ) { $lead_id = (int) $lead->id; $sub_ids = array_map( 'absint', (array) $wpdb->get_col( $wpdb->prepare( 'SELECT id FROM %i WHERE lead_id = %d', $wpdb->prefix . 'acquis_submissions', $lead_id ) ) ); if ( $sub_ids ) { $ph = implode( ',', array_fill( 0, count( $sub_ids ), '%d' ) ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- placeholders only $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->prefix}acquis_submission_values WHERE submission_id IN ($ph)", $sub_ids ) ); } $wpdb->delete( $wpdb->prefix . 'acquis_submissions', array( 'lead_id' => $lead_id ) ); $wpdb->delete( $wpdb->prefix . 'acquis_tokens', array( 'lead_id' => $lead_id ) ); $wpdb->delete( $wpdb->prefix . 'acquis_email_logs', array( 'lead_id' => $lead_id ) ); $wpdb->delete( $wpdb->prefix . 'acquis_integration_logs', array( 'lead_id' => $lead_id ) ); // Page-view and form counts stay as anonymous totals; only the link to the person and their IP go. $wpdb->update( $wpdb->prefix . 'acquis_analytics', array( 'lead_id' => 0, 'ip_address' => '' ), array( 'lead_id' => $lead_id ) ); // Pro (scores, tags, pipeline, sequences, …) clears its own tables on this action. do_action( 'acquis_before_lead_deleted', $lead_id ); $wpdb->delete( $wpdb->prefix . 'acquis_leads', array( 'id' => $lead_id ) ); $result['items_removed'] = true; } /** * Erase more for the same person, and report anything kept on purpose. * * @param array $result { items_removed: bool, items_retained: bool, messages: string[], done: bool } * @param string $email * @param array $leads The leads that were just erased. */ $result = (array) apply_filters( 'acquis_privacy_erase_email', $result, $email, $leads ); $result['done'] = true; return $result; } // ── Privacy policy text ──────────────────────────────────────────────── public static function policy_text() { if ( ! function_exists( 'wp_add_privacy_policy_content' ) ) { return; } $text = '
' . esc_html__( 'Suggested text. Review it and adjust it to how you use the plugin.', 'acquisitionsuite' ) . '
'; $text .= '' . esc_html__( 'When you fill in a form on this site, we save your name, email address and anything else you type into the form, together with the page you were on, the site you came from, your IP address and your browser details. If the form offers a download, we also keep a record of the download links and emails we send you.', 'acquisitionsuite' ) . '
'; $text .= '' . esc_html__( 'We use this to send you what you asked for and, if you agreed, to keep in touch with you. You can opt out of marketing emails at any time with the unsubscribe link in every one.', 'acquisitionsuite' ) . '
'; $text .= '' . esc_html__( 'You can ask us for a copy of this data, or to erase it, and we will do so unless the law requires us to keep it (for example payment records).', 'acquisitionsuite' ) . '
'; $text .= '' . esc_html__( 'If a form on this site opens as a slide-in panel and you close it, a note of when you closed it is kept in the local storage of your browser for seven days so the panel does not open again. It holds only that time, nothing about you, and never leaves your browser.', 'acquisitionsuite' ) . '
'; wp_add_privacy_policy_content( 'AcquisitionSuite', wp_kses_post( $text ) ); } }