emaining; } if ( isset( $responseBody->orders ) ) { aioseo()->internalOptions->internal->ai->credits->orders = aioseo()->helpers->sanitizeOption( $responseBody->orders ); } if ( ! empty( $responseBody->license ) ) { aioseo()->internalOptions->internal->ai->credits->license->total = (int) $responseBody->license->total ?? 0; aioseo()->internalOptions->internal->ai->credits->license->remaining = (int) $responseBody->license->remaining ?? 0; aioseo()->internalOptions->internal->ai->credits->license->expires = (int) $responseBody->license->expires ?? 0; } if ( ! empty( $responseBody->costPerFeature ) ) { aioseo()->internalOptions->internal->ai->costPerFeature = json_decode( wp_json_encode( $responseBody->costPerFeature ), true ); } } /** * Sanitizes AI social post content, keeping links and preserving newlines. * * @since 4.9.9 * * @param object|array $socialPosts The social posts keyed by network type. * @return array The sanitized social posts. */ public function sanitizeSocialPosts( $socialPosts ) { $sanitized = []; foreach ( (array) $socialPosts as $type => $content ) { if ( 'email' === $type ) { $content = (array) $content; $sanitized[ $type ] = [ 'subject' => $this->sanitizeSocialPostText( $content['subject'] ?? '' ), 'preview' => $this->sanitizeSocialPostText( $content['preview'] ?? '' ), 'content' => $this->sanitizeSocialPostContent( $content['content'] ?? '' ) ]; continue; } if ( is_string( $content ) ) { $sanitized[ $type ] = $this->sanitizeSocialPostContent( $content ); } } return $sanitized; } /** * Sanitizes a social post body, keeping links and newlines while stripping all other HTML. * * NOTE: Entities are decoded before wp_kses() so kses is the final gate — encoded markup can't be reconstructed into a live tag afterwards. * * @since 4.9.9 * * @param string $content The raw content. * @return string The sanitized content. */ private function sanitizeSocialPostContent( $content ) { $allowedHtml = [ 'a' => [ 'href' => true, 'title' => true, 'target' => true, 'rel' => true ] ]; return wp_kses( aioseo()->helpers->decodeHtmlEntities( (string) $content ), $allowedHtml ); } /** * Sanitizes a single-line social post field, such as an email subject, stripping all HTML. * * @since 4.9.9 * * @param string $text The raw text. * @return string The sanitized text. */ private function sanitizeSocialPostText( $text ) { return sanitize_text_field( aioseo()->helpers->decodeHtmlEntities( (string) $text ) ); } /** * Set {@see self::$options}. * Ideally set options only for Vue usage on the front-end. * * @since 4.9.6 * * @return void */ private function setOptions() { $this->options = [ 'minContentLength' => 200 ]; } }