HEX
Server: LiteSpeed
System: Linux server315.web-hosting.com 4.18.0-553.54.1.lve.el8.x86_64 #1 SMP Wed Jun 4 13:01:13 UTC 2025 x86_64
User: globfdxw (6114)
PHP: 8.1.34
Disabled: NONE
Upload Files
File: /home/globfdxw/diasporameetsafrica.com/wp-content/plugins/wpforms-pdf/src/PDF/Renderer.php
<?php

// Added to the PDF addon composer.json.
// phpcs:ignore Generic.Commenting.DocComment.MissingShort
/** @noinspection PhpComposerExtensionStubsInspection */

namespace WPFormsPDF\PDF;

use WPForms\SmartTags\SmartTag\SmartTag;
use WPForms\Emails\Notifications;
use WPForms\Helpers\File;
use WPFormsPDF\Storage;
use WPFormsPDF\Templates\Templates;
use DOMDocument;
use DOMElement;

/**
 * Renderer class.
 *
 * @since 1.0.0
 */
class Renderer {

	/**
	 * Default settings.
	 *
	 * @since 1.0.0
	 *
	 * @var array
	 */
	private const DEFAULT_SETTINGS = [
		'template'   => 'notification-modern',
		'theme'      => 'creamsicle',
		'pdf_id'     => 0,
		'is_preview' => false,
	];

	/**
	 * 1x1 transparent PNG image.
	 *
	 * @since 1.0.0
	 *
	 * @var string
	 */
	private const TRANSPARENT_PNG = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR4nGMAAQAABQABDQottAAAAABJRU5ErkJggg==';

	/**
	 * Supported image types.
	 *
	 * @since 1.0.0
	 *
	 * @var array
	 */
	private const IMAGE_TYPES = [
		'svg'  => 'image/svg+xml',
		'png'  => 'image/png',
		'gif'  => 'image/gif',
		'jpg'  => 'image/jpeg',
		'jpeg' => 'image/jpeg',
	];

	/**
	 * Settings.
	 *
	 * @since 1.0.0
	 *
	 * @var array
	 */
	private $settings = [];

	/**
	 * Templates class instance.
	 *
	 * @since 1.0.0
	 *
	 * @var Templates
	 */
	private $templates_obj;

	/**
	 * Template data.
	 *
	 * @since 1.0.0
	 *
	 * @var array
	 */
	private $template;

	/**
	 * Current entry fields data.
	 *
	 * @since 1.0.0
	 *
	 * @var array
	 */
	private $entry_fields;

	/**
	 * Current entry ID.
	 *
	 * @since 1.0.0
	 *
	 * @var int
	 */
	private $entry_id;

	/**
	 * Current form data.
	 *
	 * @since 1.0.0
	 *
	 * @var array
	 */
	private $form_data;

	/**
	 * Current PDF images data.
	 *
	 * @since 1.0.0
	 *
	 * @var array
	 */
	private $images;

	/**
	 * Class constructor.
	 *
	 * @since 1.0.0
	 *
	 * @param string $template     Template slug.
	 * @param string $theme        Theme slug.
	 * @param array  $form_data    Form data.
	 * @param array  $entry_fields Entry fields.
	 *
	 * @return void
	 */
	public function __construct( string $template = '', string $theme = '', array $form_data = [], array $entry_fields = [] ) {

		$this->templates_obj = wpforms_pdf()->templates;

		$this->hooks();

		if ( empty( $template ) || empty( $theme ) || empty( $form_data ) ) {
			return;
		}

		$this->init( $template, $theme, $form_data, $entry_fields );
	}

	/**
	 * Initialize class.
	 *
	 * @since 1.0.0
	 *
	 * @param string $template     Template slug.
	 * @param string $theme        Theme slug.
	 * @param array  $form_data    Form data.
	 * @param array  $entry_fields Entry fields.
	 *
	 * @return Renderer
	 */
	public function init( string $template, string $theme, array $form_data, array $entry_fields ): self {

		$this->settings = [
			'template' => $template,
			'theme'    => $theme,
		];

		$this->form_data    = $form_data;
		$this->entry_fields = $entry_fields;
		$this->settings     = wp_parse_args( $this->settings, self::DEFAULT_SETTINGS );

		$this->init_template();

		return $this;
	}

	/**
	 * Register hooks.
	 *
	 * @since 1.0.0
	 */
	private function hooks(): void {

		add_filter( 'wpforms_smarttags_process_value', [ $this, 'filter_smarttags_process_value' ], 10, 7 );
	}

	/**
	 * Initialize certain PDF from the form settings.
	 *
	 * @since 1.0.0
	 *
	 * @param int   $pdf_id       PDF id.
	 * @param array $form_data    Form data.
	 * @param array $entry_fields Entry fields.
	 * @param int   $entry_id     Entry id.
	 * @param bool  $is_preview   Is preview.
	 *
	 * @return Renderer
	 */
	public function init_pdf_settings( int $pdf_id, array $form_data, array $entry_fields, int $entry_id = 0, bool $is_preview = false ): self {

		$pdf           = $form_data['settings']['pdfs'][ $pdf_id ] ?? [];
		$theme_slug    = $pdf['theme'] ?? '';
		$template_slug = $pdf['template_style'] ?? '';

		$this->settings = [
			'template'    => $template_slug,
			'theme'       => $theme_slug,
			'pdf_id'      => $pdf_id,
			'is_preview'  => $is_preview,
			'orientation' => $pdf['orientation'] ?? 'portrait',
			'paper_size'  => $pdf['paper_size'] ?? 'A4',
		];

		$this->form_data    = $form_data;
		$this->entry_fields = $entry_fields;
		$this->entry_id     = $entry_id;
		$this->settings     = wp_parse_args( $this->settings, self::DEFAULT_SETTINGS );
		$this->images       = [];

		$this->init_template();

		return $this;
	}

	/**
	 * Initialize template.
	 *
	 * @since 1.0.0
	 *
	 * @return void
	 */
	private function init_template(): void {

		// Get template data.
		$this->template = $this->templates_obj->get_template( $this->settings['template'], $this->settings['theme'] );

		// Default template.
		if ( empty( $this->template ) ) {
			$this->template = $this->templates_obj->get_template( Templates::DEFAULT_TEMPLATE, $this->settings['theme'] );
		}

		$this->apply_pdf_settings();

		// Update template data.
		$this->init_template_appearance();
		$this->init_template_text();
	}

	/**
	 * Initialize a template appearance section.
	 *
	 * @since 1.0.0
	 *
	 * @return void
	 */
	private function init_template_appearance(): void {

		$this->template['appearance']['page_background_image'] = $this->get_background_image();

		// Available fonts.
		$fonts = [
			'serif'      => '"Literata", serif',
			'sans-serif' => '"Inter", sans-serif',
		];

		// Update font to actual CSS value.
		$template_font = $this->template['appearance']['font'] ?? 'sans-serif';

		$this->template['appearance']['font']     = $fonts[ $template_font ] ?? $fonts['sans-serif'];
		$this->template['appearance']['logo_url'] = $this->get_image( $this->template['appearance']['logo_url'] ?? '' );
	}

	/**
	 * Initialize a template text section.
	 *
	 * @since 1.0.0
	 *
	 * @return void
	 */
	private function init_template_text(): void {

		$this->template['text'] = $this->template['text'] ?? [];

		if ( isset( $this->template['text']['badge_show'] ) ) {
			$this->template['text']['badge_image'] = $this->get_badge_image();
		}

		if ( isset( $this->template['text']['signature_url'] ) ) {
			$this->template['text']['signature_url'] = $this->get_image( $this->template['text']['signature_url'] );
		}
	}

	/**
	 * Apply PDF settings to the template.
	 *
	 * @since 1.0.0
	 *
	 * @return void
	 */
	private function apply_pdf_settings(): void {

		$pdf_settings = $this->get_pdf_settings();

		if ( empty( $pdf_settings ) || empty( $this->template ) ) {
			return;
		}

		$template = $this->template;
		$prefix   = $template['category'] === 'notification' ? 'notification_' : 'general_';

		// Apply appearance settings.
		foreach ( $template['appearance'] as $key => $value ) {
			$appearance_key                 = $prefix . $key;
			$appearance_key                 = isset( $pdf_settings[ $appearance_key ] ) ? $appearance_key : $key;
			$template['appearance'][ $key ] = $pdf_settings[ $appearance_key ] ?? $template['appearance'][ $key ];
		}

		// Apply text settings.
		$template['text'] = $this->apply_template_settings( $template['text'], $pdf_settings );

		$this->template = $template;
	}

	/**
	 * Get PDF settings.
	 *
	 * @since 1.0.0
	 *
	 * @return array
	 */
	private function get_pdf_settings(): array {

		if ( ! isset( $this->settings['pdf_id'] ) ) {
			return [];
		}

		return $this->form_data['settings']['pdfs'][ $this->settings['pdf_id'] ?? null ] ?? [];
	}

	/**
	 * Apply template settings.
	 *
	 * @since 1.0.0
	 *
	 * @param array $template_section Template section.
	 * @param array $pdf_settings     PDF settings.
	 *
	 * @return array
	 */
	private function apply_template_settings( array $template_section, array $pdf_settings ): array {

		// Apply template section settings.
		foreach ( $template_section as $key => $value ) {
			$template_section[ $key ] = $pdf_settings[ $key ] ?? $value;
		}

		return $template_section;
	}

	/**
	 * Get rendered HTML.
	 *
	 * @since 1.0.0
	 *
	 * @param array $texts Texts.
	 *
	 * @return string
	 */
	public function render_html( array $texts = [] ): string {

		// Process content.
		$processed_texts = $this->process_texts( $texts );

		// Render template.
		$body = wpforms_render(
			$this->get_template_location(),
			[
				'appearance' => $this->get_appearance_settings(),
				'theme'      => $this->get_theme_colors(),
				'content'    => $processed_texts['content'],
				'texts'      => $processed_texts,
				'is_preview' => $this->settings['is_preview'],
				'base_url'   => $this->get_pdf_base_url(),
			],
			true
		);

		$pdf_tuning_css   = empty( $this->settings['is_preview'] ) ? $this->get_css_file_content( 'pdf_tuning' ) : '';
		$is_preview_class = $this->settings['is_preview'] ? 'preview' : '';

		// Render final HTML.
		$html = wpforms_render(
			$this->get_template_location( 'html' ),
			[
				'html_css'       => $this->get_css_file_content(),
				'pdf_tuning_css' => $pdf_tuning_css,
				'body'           => $body,
				'body_class'     => $this->settings['orientation'] . ' ' . $this->settings['paper_size'] . ' ' . $is_preview_class,
			],
			true
		);

		// Process rendered HTML.
		if ( empty( $this->settings['is_preview'] ) ) {
			$html = $this->process_rendered_html( $html );

			$this->update_images_data( $html );
		}

		// Output the final HTML to the file for debugging.
		if ( wpforms_pdf()->helpers->is_debug() ) {
			File::put_contents( Storage::get_dir() . '/debug.html', $html );
		}

		return $html;
	}

	/**
	 * Process rendered HTML.
	 *
	 * @since 1.0.0
	 *
	 * @param string $html HTML content.
	 *
	 * @return string
	 */
	private function process_rendered_html( string $html ): string {

		$emojis = [
			'star'   => '⭐',
			'heart'  => '❤️',
			'thumb'  => '👍',
			'smiley' => '🙂',
		];

		$emojis_replacement = [];

		foreach ( $emojis as $key => $value ) {
			$emojis_replacement[] = sprintf(
				'<span><img src="%1$sassets/images/emoji/%2$s.png" alt="" /></span>',
				WPFORMS_PDF_URL,
				$key
			);
		}

		$html = str_replace( array_values( $emojis ), $emojis_replacement, $html );

		return $html;
	}

	/**
	 * Get appearance settings for the template.
	 *
	 * @since 1.0.0
	 *
	 * @return array
	 */
	private function get_appearance_settings(): array {

		$appearance = $this->template['appearance'];

		if ( ! $this->settings['is_preview'] ) {
			return $appearance;
		}

		$as_is_keys = [ 'logo_id', 'logo_url', 'logo_position', 'logo_size', 'page_background_image', 'container_shadow' ];

		foreach ( $appearance as $key => $value ) {
			if ( in_array( $key, $as_is_keys, true ) ) {
				continue;
			}

			$appearance[ $key ] = "var( --wpforms-appearance-$key, $value )";
		}

		return $appearance;
	}

	/**
	 * Get theme colors for the template.
	 *
	 * @since 1.0.0
	 *
	 * @return array
	 */
	private function get_theme_colors(): array {

		$colors = $this->template['theme']['colors'];

		if ( ! $this->settings['is_preview'] ) {
			return $colors;
		}

		$colors = $this->get_unsaved_theme_colors();

		foreach ( $colors as $key => $value ) {
			$colors[ $key ] = "var( --wpforms-theme-color-$key, $value )";
		}

		return $colors;
	}

	/**
	 * Get theme colors for the template.
	 *
	 * @since 1.0.0
	 *
	 * @return array
	 */
	private function get_unsaved_theme_colors(): array {

		$colors = $this->template['theme']['colors'];

		$pdf = $this->get_pdf_settings();

		foreach ( $colors as $key => $value ) {
			$colors[ $key ] = $pdf[ 'theme_color_' . $key ] ?? $value;
		}

		return $colors;
	}

	/**
	 * Process texts.
	 *
	 * @since 1.0.0
	 *
	 * @param array $texts Texts.
	 *
	 * @return array
	 */
	private function process_texts( array $texts ): array {

		// Get template texts.
		$template_text = $this->template['text'];
		$template_text = wp_parse_args( $texts, $template_text );
		$all_fields    = $template_text['all_fields'] ?? $this->render_all_fields();
		$context       = $this->settings['is_preview'] ? 'wpforms-pdf-preview-process-texts' : 'wpforms-pdf-process-texts';

		// Process texts.
		foreach ( $template_text as $key => $value ) {
			if ( $this->settings['is_preview'] && strpos( $key, '_color' ) !== false ) {
				$template_text[ $key ] = "var( --wpforms-text-color-$key, $value )";

				continue;
			}

			$template_text[ $key ] = wpforms_process_smart_tags( wp_unslash( $value ), $this->form_data, $this->entry_fields, $this->entry_id, $context );
			$template_text[ $key ] = str_replace( '{all_fields}', $all_fields, $template_text[ $key ] );
		}

		$template_text['content'] = $template_text['content'] ?? $all_fields;

		return $template_text;
	}

	/**
	 * Get rendered {all_fields} for a given email template.
	 *
	 * @since 1.0.0
	 *
	 * @param string $template Template slug.
	 *
	 * @return string
	 */
	public function render_all_fields( string $template = '' ): string {

		$template = empty( $template ) ? $this->template['email_style'] : $template;

		// Create a new email.
		$emails = ( new Notifications() )->init( $template, 'pdf' );

		$emails->__set( 'form_data', $this->form_data );
		$emails->__set( 'fields', $this->entry_fields );

		// Render all fields.
		$all_fields = $emails->get_processed_field_values();

		return '<table class="all_fields">' . $all_fields . '</table>';
	}

	/**
	 * Get a base template slug.
	 *
	 * @since 1.0.0
	 *
	 * @param string $template Template slug. Optional.
	 *
	 * @return string
	 */
	private function get_base_template_slug( string $template = '' ): string {

		$template = empty( $template ) ? $this->settings['template'] : $template;

		return ! empty( $this->template['baseTemplate'] ) ? $this->template['baseTemplate'] : $template;
	}

	/**
	 * Get a template location.
	 *
	 * @since 1.0.0
	 *
	 * @param string $template Template slug. Optional.
	 *
	 * @return string
	 */
	private function get_template_location( string $template = '' ): string {

		$template = $template !== 'html' ? $this->get_base_template_slug( $template ) : $template;

		return sprintf(
			'%1$stemplates/pdf/%2$s',
			WPFORMS_PDF_PATH,
			$template
		);
	}

	/**
	 * Get a template CSS file path.
	 *
	 * @since 1.0.0
	 *
	 * @param string $purpose CSS purpose `html` or `pdf_tuning`. Defaults to `html`.
     *
	 * @return string
	 * @noinspection PhpSameParameterValueInspection
	 */
	private function get_css_file( string $purpose = '' ): string {

		$template = $this->get_base_template_slug();
		$sub_dir  = $purpose === 'pdf_tuning' ? '/tuning' : '';

		return sprintf(
			'%1$sassets/css/pdf%2$s/%3$s.css',
			WPFORMS_PDF_PATH,
			$sub_dir,
			$template
		);
	}

	/**
	 * Get template CSS file content.
	 *
	 * @since 1.0.0
	 *
	 * @param string $purpose CSS purpose `html` or `pdf_tuning`. Defaults to `html`.
	 *
	 * @return string
	 * @noinspection PhpSameParameterValueInspection
	 */
	private function get_css_file_content( string $purpose = 'html' ): string {

		$css_content = File::get_contents( $this->get_css_file( $purpose ) );

		if ( empty( $css_content ) ) {
			return '';
		}

		return str_replace( '{WPFORMS_PDF_URL}', $this->get_pdf_base_url(), $css_content );
	}

	/**
	 * Get PDF base URL.
	 *
	 * @since 1.0.0
	 *
	 * @return string
	 */
	private function get_pdf_base_url(): string {

		return empty( $this->settings['is_preview'] ) ? '' : WPFORMS_PDF_URL;
	}

	/**
	 * Get image content.
	 *
	 * @since 1.0.0
	 *
	 * @param string $location Image location.
	 *                         It could be a URL or a path to an image located in the `assets/images` folder.
	 *
	 * @return string
	 */
	private function get_image( string $location ): string {

		if ( empty( $location ) ) {
			return '';
		}

		[ $location_norm, $site_url ] = $this->normalize_urls( [ $location, site_url() ] );

		$upload_dir = wpforms_pdf()->helpers->get_wp_upload_dir();

		// If the image doesn't start with the full local path to addon
		// or the full URL to the default logos, assume this is the image in the `assets /images/` directory.
		if (
			strpos( $location, WPFORMS_PDF_PATH ) === false &&
			strpos( $location_norm, $site_url ) === false
		) {
			$location = WPFORMS_PDF_PATH . 'assets/images/' . $location;
		}

		// Convert the image URL to the full local path.
		$location = str_replace(
			[ $upload_dir['url'], WPFORMS_PDF_URL ],
			[ $upload_dir['dir'], WPFORMS_PDF_PATH ],
			$location
		);

		return $this->get_image_data( $location );
	}

	/**
	 * Get data:image string from given image location.
	 *
	 * @since 1.0.0
	 *
	 * @param string $location Image location.
	 *
	 * @return string
	 */
	private function get_image_data( string $location ): string {

		$image_ext     = pathinfo( $location, PATHINFO_EXTENSION );
		$image_content = File::get_contents( $location );

		if ( empty( $image_content ) ) {
			return '';
		}

		// Skip unsupported image types.
		if ( ! isset( self::IMAGE_TYPES[ $image_ext ] ) ) {
			return '';
		}

		// Add colors to SVG image.
		if ( $image_ext === 'svg' ) {
			$image_content = $this->templates_obj->replace_colors( $image_content, $this->get_colors_for_image( $location ) );
		}

		$type = self::IMAGE_TYPES[ $image_ext ];

		if ( ! empty( $this->settings['is_preview'] ) ) {
			// phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode
			return "data:$type;base64," . base64_encode( $image_content );
		}

		// Add an image to the `images` array in case it is an actual PDF generation process.
		$upload_dir     = wpforms_pdf()->helpers->get_wp_upload_dir();
		$short_location = str_replace( [ WPFORMS_PDF_PATH, $upload_dir['dir'] ], '', $location );

		$this->images[ $short_location ] = $image_ext !== 'svg' ? base64_encode( $image_content ) : $image_content; // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode

		// Return a short path to the image.
		return $short_location;
	}

	/**
	 * Get colors for the image.
	 *
	 * @since 1.0.0
	 *
	 * @param string $location Image location.
	 *
	 * @return array
	 */
	private function get_colors_for_image( string $location ): array {

		$colors = $this->template['theme']['colors'];

		if ( $this->settings['is_preview'] ) {
			$colors = $this->get_unsaved_theme_colors();
		}

		if ( strpos( $location, 'background' ) === false ) {
			return $colors;
		}

		// Adjust theme colors according to the custom colors defined in the template.
		$colors['background']       = $this->templates_obj->replace_colors( $this->template['appearance']['page_background_color'], $colors );
		$colors['background_light'] = $this->templates_obj->replace_colors( $this->template['appearance']['page_background_color_end'], $colors );

		return $colors;
	}

	/**
	 * Get normalized URLs.
	 * For cases when the image was uploaded before enabling https on the server.
	 *
	 * @since 1.0.0
	 *
	 * @param array $urls URLs.
	 */
	private function normalize_urls( array $urls ): array {

		foreach ( $urls as $key => $url ) {
			$urls[ $key ] = str_replace( 'http://', 'https://', $url );
		}

		return $urls;
	}

	/**
	 * Get badge image content.
	 *
	 * @since 1.0.0
	 *
	 * @return string
	 */
	private function get_badge_image(): string {

		$style = $this->template['style'] ?? '';

		return $this->get_image( "badges/$style.svg" );
	}

	/**
	 * Get background image content.
	 *
	 * @since 1.0.0
	 *
	 * @return string
	 */
	private function get_background_image(): string {

		$location = $this->get_background_image_location();

		// If there is no background image, return transparent PNG.
		// This is required for PDF export.
		if ( empty( $location ) ) {
			return self::TRANSPARENT_PNG;
		}

		return $this->get_image( $location );
	}

	/**
	 * Get a background image file location.
	 *
	 * @since 1.0.0
	 *
	 * @param string $image Image file name, without `.svg`. Optional.
	 *
	 * @return string
	 * @noinspection PhpSameParameterValueInspection
	 */
	private function get_background_image_location( string $image = '' ): string {

		$image       = empty( $image ) ? $this->template['appearance']['page_background_image'] : $image;
		$orientation = $this->settings['orientation'] ?? '';
		$orientation = $orientation === 'landscape' ? 'landscape' : 'portrait';

		$file     = wp_normalize_path( WPFORMS_PDF_PATH . "assets/images/background/$orientation/$image" );
		$svg_file = $file . '.svg';

		if ( File::exists( $svg_file ) ) {
			return $svg_file;
		}

		$png_file = $file . '.png';

		if ( ! File::exists( $png_file ) ) {
			return '';
		}

		// Return URL to the PNG file.
		return esc_url( str_replace( WPFORMS_PDF_PATH, WPFORMS_PDF_URL, $png_file ) );
	}

	/**
	 * Get images data.
	 *
	 * @since 1.0.0
	 *
	 * @return array
	 */
	public function get_images_data(): array {

		return $this->images;
	}

	/**
	 * Update images data by finding all img tags in HTML.
	 *
	 * @since 1.0.0
	 *
	 * @param string $html HTML content.
	 *
	 * @return void
	 */
	private function update_images_data( string $html ): void {

		// Skip if HTML is empty.
		if ( empty( $html ) ) {
			return;
		}

		// Create a new DOMDocument.
		$dom = new DOMDocument();

		// Suppress warnings from malformed HTML.
		libxml_use_internal_errors( true );

		// Load HTML content.
		$dom->loadHTML( $html );

		// Reset errors.
		libxml_clear_errors();

		// Get all image tags.
		$images = $dom->getElementsByTagName( 'img' );

		// Skip if no images found.
		if ( $images->length === 0 ) {
			return;
		}

		$upload_dir = wpforms_pdf()->helpers->get_wp_upload_dir();
		$site_url   = site_url();

		// Process each image.
		foreach ( $images as $image ) {
			$this->update_images_data_process_image( $image, $upload_dir, $site_url );
		}
	}

	/**
	 * Process a single image from the DOM.
	 *
	 * @since 1.0.0
	 *
	 * @param DOMElement $image      Image DOM element.
	 * @param array      $upload_dir WordPress upload directory information.
	 * @param string     $site_url   Site URL.
	 *
	 * @return void
	 */
	private function update_images_data_process_image( DOMElement $image, array $upload_dir, string $site_url ): void {

		// Get image source.
		$src = $image->getAttribute( 'src' );

		// Skip if the source is empty or already processed.
		if ( empty( $src ) || isset( $this->images[ $src ] ) || strpos( $src, 'data:' ) ) {
			return;
		}

		// Convert URL to local path.
		$local_path = str_replace( $upload_dir['url'], $upload_dir['dir'], $src );

		// Also try with site URL.
		if ( ! file_exists( $local_path ) ) {
			$local_path = str_replace( $site_url, ABSPATH, $src );
		}

		$local_path = wp_normalize_path( $local_path );

		// Skip if file doesn't exist.
		if ( ! File::exists( $local_path ) ) {
			return;
		}

		// Get file extension.
		$image_ext = pathinfo( $local_path, PATHINFO_EXTENSION );

		// Skip unsupported image types.
		if ( ! isset( self::IMAGE_TYPES[ $image_ext ] ) ) {
			return;
		}

		// Get image content.
		$image_content = File::get_contents( $local_path );

		// Skip if content is empty.
		if ( empty( $image_content ) ) {
			return;
		}

		// Add image to the images array.
		$this->images[ $src ] = $image_ext !== 'svg' ? base64_encode( $image_content ) : $image_content; // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode
	}

	/**
	 * Filter the smart tag value.
	 *
	 * @since 1.0.0
	 *
	 * @param string|mixed $value            Smart Tag value.
	 * @param string       $tag_name         Smart tag name.
	 * @param array        $form_data        Form data.
	 * @param array        $fields           List of fields.
	 * @param string       $entry_id         Entry ID.
	 * @param SmartTag     $smart_tag_object The smart tag object or the Generic object.
	 * @param string       $context          Context.
	 *
	 * @return string|null
	 * @noinspection PhpUnusedParameterInspection
	 */
	public static function filter_smarttags_process_value( $value, string $tag_name, array $form_data, array $fields, string $entry_id, SmartTag $smart_tag_object, string $context ): ?string {

		// Don't replace `field_id` smart tag in the PDF preview texts.
		if ( $context === 'wpforms-pdf-preview-process-texts' && $tag_name === 'field_id' ) {
			return null;
		}

		return $value;
	}
}