__( 'ActionPanel AI Data', 'actionpanel-ai' ), 'callback' => array( $this, 'export_personal_data' ), ); return $exporters; } /** * Add the ActionPanel AI personal data eraser. * * @param array $erasers Existing WordPress erasers. */ public function register_eraser( array $erasers ): array { $erasers[ self::GROUP_ID ] = array( 'eraser_friendly_name' => __( 'ActionPanel AI Data', 'actionpanel-ai' ), 'callback' => array( $this, 'erase_personal_data' ), ); return $erasers; } /** * Export remote ActionPanel AI data for a site-scoped email address. * * @param string $email_address Email address being exported. * @param int $page Export pagination page. */ public function export_personal_data( string $email_address, int $page = 1 ): array { if ( $page > 1 ) { return array( 'data' => array(), 'done' => true, ); } $response = $this->privacy_api_client->export_by_email( $email_address, home_url( '/' ) ); if ( ! $response['ok'] ) { return array( 'data' => array( $this->build_export_item( 'error', array( array( 'name' => __( 'Status', 'actionpanel-ai' ), 'value' => __( 'Could not retrieve remote ActionPanel AI data at this time.', 'actionpanel-ai' ), ), array( 'name' => __( 'Details', 'actionpanel-ai' ), 'value' => esc_html( (string) $response['error'] ), ), ) ), ), 'done' => true, ); } $data = isset( $response['data']['data'] ) && is_array( $response['data']['data'] ) ? $response['data']['data'] : array(); $items = array(); $account_found = ! empty( $data['account_found'] ); $user = isset( $data['user'] ) && is_array( $data['user'] ) ? $data['user'] : array(); $conversations = isset( $data['conversations'] ) && is_array( $data['conversations'] ) ? $data['conversations'] : array(); if ( $account_found && ! empty( $user ) ) { $items[] = $this->build_export_item( 'account', array( array( 'name' => __( 'Email', 'actionpanel-ai' ), 'value' => esc_html( (string) ( $user['email'] ?? '' ) ), ), array( 'name' => __( 'User ID', 'actionpanel-ai' ), 'value' => esc_html( (string) ( $user['user_id'] ?? '' ) ), ), ) ); } foreach ( $conversations as $entry ) { $conversation = is_array( $entry['conversation'] ?? null ) ? $entry['conversation'] : array(); $messages = is_array( $entry['messages'] ?? null ) ? $entry['messages'] : array(); $conversation_id = (string) ( $conversation['conversation_id'] ?? 'unknown' ); $items[] = $this->build_export_item( 'conversation-' . $conversation_id, array( array( 'name' => __( 'Conversation ID', 'actionpanel-ai' ), 'value' => esc_html( $conversation_id ), ), array( 'name' => __( 'Title', 'actionpanel-ai' ), 'value' => esc_html( (string) ( $conversation['title'] ?? '' ) ), ), array( 'name' => __( 'Source', 'actionpanel-ai' ), 'value' => esc_html( (string) ( $conversation['source'] ?? '' ) ), ), array( 'name' => __( 'Site Host', 'actionpanel-ai' ), 'value' => esc_html( (string) ( $conversation['site_host'] ?? '' ) ), ), array( 'name' => __( 'Messages', 'actionpanel-ai' ), 'value' => esc_html( wp_json_encode( $messages ) ), ), ) ); } if ( empty( $items ) ) { $items[] = $this->build_export_item( 'none', array( array( 'name' => __( 'Status', 'actionpanel-ai' ), 'value' => __( 'No ActionPanel AI remote data found for this email on this site.', 'actionpanel-ai' ), ), ) ); } return array( 'data' => $items, 'done' => true, ); } /** * Erase remote ActionPanel AI data for a site-scoped email address. * * @param string $email_address Email address being erased. * @param int $page Eraser pagination page. */ public function erase_personal_data( string $email_address, int $page = 1 ): array { if ( $page > 1 ) { return array( 'items_removed' => false, 'items_retained' => false, 'messages' => array(), 'done' => true, ); } $response = $this->privacy_api_client->erase_by_email( $email_address, home_url( '/' ) ); if ( ! $response['ok'] ) { return array( 'items_removed' => false, 'items_retained' => true, 'messages' => array( sprintf( /* translators: %s: error details */ __( 'ActionPanel AI remote erase failed: %s', 'actionpanel-ai' ), esc_html( (string) $response['error'] ) ), ), 'done' => true, ); } $deleted = isset( $response['data']['deleted'] ) && is_array( $response['data']['deleted'] ) ? $response['data']['deleted'] : array(); $account_found = ! empty( $deleted['account_found'] ); $deleted_conversations = (int) ( $deleted['deleted_conversations'] ?? 0 ); $messages = array(); if ( ! $account_found ) { $messages[] = __( 'No ActionPanel AI remote account data found for this email on this site.', 'actionpanel-ai' ); } elseif ( $deleted_conversations > 0 ) { $messages[] = sprintf( /* translators: %d: number of deleted conversations */ __( 'Removed %d ActionPanel AI conversation(s) for this site.', 'actionpanel-ai' ), $deleted_conversations ); } else { $messages[] = __( 'No site-scoped ActionPanel AI conversations needed deletion.', 'actionpanel-ai' ); } return array( 'items_removed' => $deleted_conversations > 0, 'items_retained' => false, 'messages' => $messages, 'done' => true, ); } /** * Build a WordPress personal data export item. * * @param string $id_suffix Stable item suffix. * @param array $fields Export fields for the item. */ private function build_export_item( string $id_suffix, array $fields ): array { return array( 'group_id' => self::GROUP_ID, 'group_label' => __( 'ActionPanel AI', 'actionpanel-ai' ), 'item_id' => self::GROUP_ID . '-' . sanitize_key( $id_suffix ), 'data' => $fields, ); } }