> $exporters * @return array> */ public function exporters( array $exporters ): array { $exporters['senti-subscriptions'] = [ 'exporter_friendly_name' => __( 'Senti subscriptions', 'senti-feedback' ), 'callback' => [ $this, 'export' ], ]; return $exporters; } /** * @internal * @param array> $erasers * @return array> */ public function erasers( array $erasers ): array { $erasers['senti-subscriptions'] = [ 'eraser_friendly_name' => __( 'Senti subscriptions', 'senti-feedback' ), 'callback' => [ $this, 'erase' ], ]; return $erasers; } /** * @internal * @return array{data: array>, done: bool} */ public function export( string $email, int $page = 1 ): array { $rows = $this->rows( $email, max( 0, $page - 1 ) * self::PAGE_SIZE, self::PAGE_SIZE ); $data = []; foreach ( $rows as $row ) { $data[] = [ 'group_id' => 'senti-subscriptions', 'group_label' => __( 'Senti subscriptions', 'senti-feedback' ), 'item_id' => 'senti-subscription-' . $row['id'], 'data' => [ [ 'name' => __( 'Subscription subject', 'senti-feedback' ), 'value' => $row['subject_type'] . ':' . $row['subject_id'], ], [ 'name' => __( 'Subscription state', 'senti-feedback' ), 'value' => $row['state'], ], [ 'name' => __( 'Subscribed', 'senti-feedback' ), 'value' => $row['created_gmt'], ], ], ]; } return [ 'data' => $data, 'done' => count( $rows ) < self::PAGE_SIZE, ]; } /** * @internal * @return array{items_removed: bool, items_retained: bool, messages: string[], done: bool} */ public function erase( string $email, int $page = 1 ): array { $query = $this->wpdb->prepare( 'SELECT id FROM %i WHERE email_hash = %s ORDER BY id LIMIT %d', $this->wpdb->prefix . 'senti_subscriptions', $this->email_hash( $email ), self::PAGE_SIZE ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared -- $query is prepared immediately above. $ids = is_string( $query ) ? array_map( 'intval', $this->wpdb->get_col( $query ) ) : []; if ( $ids !== [] ) { $placeholders = implode( ',', array_fill( 0, count( $ids ), '%d' ) ); $notifications_table = "{$this->wpdb->prefix}senti_notifications"; $subscriptions_table = "{$this->wpdb->prefix}senti_subscriptions"; // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.PreparedSQLPlaceholders.ReplacementsWrongNumber $notif_delete = $this->wpdb->prepare( "DELETE FROM %i WHERE subscription_id IN ($placeholders)", $notifications_table, ...$ids ); if ( is_string( $notif_delete ) ) { // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $this->wpdb->query( $notif_delete ); } // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.PreparedSQLPlaceholders.ReplacementsWrongNumber $sub_delete = $this->wpdb->prepare( "DELETE FROM %i WHERE id IN ($placeholders)", $subscriptions_table, ...$ids ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $removed = is_string( $sub_delete ) ? $this->wpdb->query( $sub_delete ) : false; } else { $removed = 0; } $remaining_query = $this->wpdb->prepare( 'SELECT COUNT(*) FROM %i WHERE email_hash = %s', $this->wpdb->prefix . 'senti_subscriptions', $this->email_hash( $email ) ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared -- $remaining_query is prepared immediately above. $remaining = is_string( $remaining_query ) ? (int) $this->wpdb->get_var( $remaining_query ) : 0; return [ 'items_removed' => $removed !== false && $removed > 0, 'items_retained' => false, 'messages' => [], 'done' => $remaining === 0, ]; } /** * @return list> */ private function rows( string $email, int $offset, int $limit ): array { $query = $this->wpdb->prepare( 'SELECT id, subject_type, subject_id, state, created_gmt FROM %i WHERE email_hash = %s ORDER BY id LIMIT %d OFFSET %d', $this->wpdb->prefix . 'senti_subscriptions', $this->email_hash( $email ), $limit, $offset ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared -- $query is prepared immediately above. return is_string( $query ) ? $this->wpdb->get_results( $query, ARRAY_A ) ?: [] : []; } private function email_hash( string $email ): string { return hash( 'sha256', strtolower( sanitize_email( $email ) ) ); } }