<?php
/**
 * Image resolution post-processor.
 *
 * Walks the Elementor template, collects __FIGMA_IMAGE_REF__ placeholders,
 * resolves them via the Figma API, downloads images into the WP Media Library,
 * and replaces placeholders with WordPress attachment URLs.
 */

if ( ! defined( 'ABSPATH' ) ) exit;

class FTE_Image_Resolver {

    private FTE_Figma_Client $client;
    private string           $file_key;

    public function __construct( FTE_Figma_Client $client, string $file_key ) {
        $this->client   = $client;
        $this->file_key = $file_key;
    }

    /**
     * Resolve all image placeholders in an Elementor template (mutates in place).
     *
     * @param array &$template Elementor template (content array).
     * @return array Manifest of resolved images.
     */
    public function resolve( array &$template ): array {
        // Step 1: Collect placeholders
        $placeholders = $this->collect_placeholders( $template['content'] );

        if ( empty( $placeholders ) ) {
            return [];
        }

        // Step 2: Classify
        $fill_refs   = [];
        $export_ids  = [];

        foreach ( $placeholders as $p ) {
            if ( $p['requires_export'] ) {
                $export_ids[] = $p['ref'];
            } else {
                $fill_refs[] = $p['ref'];
            }
        }

        // Step 3: Resolve fill URLs
        $fill_map = [];
        if ( ! empty( $fill_refs ) ) {
            $fill_map = $this->client->get_image_fills( $this->file_key );
        }

        // Step 4: Export node images
        $export_map = [];
        if ( ! empty( $export_ids ) ) {
            $export_map = $this->client->export_images( $this->file_key, $export_ids, 'png', 2.0 );
        }

        // Step 5: Download to WP Media Library and build final URL map
        $url_map  = [];
        $manifest = [];

        foreach ( array_unique( $fill_refs ) as $ref ) {
            $remote_url = $fill_map[ $ref ] ?? null;
            if ( ! $remote_url ) continue;

            $local_url = $this->sideload_to_media_library( $remote_url, "figma-fill-{$ref}" );
            if ( $local_url ) {
                $url_map[ $ref ] = $local_url;
                $manifest[]      = [ 'ref' => $ref, 'url' => $local_url, 'source' => 'fill' ];
            }
        }

        foreach ( array_unique( $export_ids ) as $id ) {
            $remote_url = $export_map[ $id ] ?? null;
            if ( ! $remote_url ) continue;

            $safe_id   = str_replace( ':', '-', $id );
            $local_url = $this->sideload_to_media_library( $remote_url, "figma-export-{$safe_id}" );
            if ( $local_url ) {
                $url_map[ $id ] = $local_url;
                $manifest[]     = [ 'ref' => $id, 'url' => $local_url, 'source' => 'export' ];
            }
        }

        // Step 6: Replace in template
        $template['content'] = $this->replace_placeholders( $template['content'], $url_map );

        return $manifest;
    }

    // -----------------------------------------------------------------------
    // Placeholder collection
    // -----------------------------------------------------------------------

    private function collect_placeholders( array $nodes ): array {
        $results = [];

        foreach ( $nodes as $node ) {
            $this->scan_for_placeholders( $node, $results );
        }

        return $results;
    }

    private function scan_for_placeholders( array $node, array &$results ): void {
        $requires_export = ! empty( $node['settings']['_requires_image_export'] );

        // Scan settings recursively for placeholder strings
        if ( isset( $node['settings'] ) ) {
            $this->scan_value( $node['settings'], $requires_export, $results );
        }

        foreach ( $node['elements'] ?? [] as $child ) {
            $this->scan_for_placeholders( $child, $results );
        }
    }

    private function scan_value( $value, bool $requires_export, array &$results ): void {
        if ( is_string( $value ) && str_starts_with( $value, '__FIGMA_IMAGE_REF__:' ) ) {
            $ref = substr( $value, strlen( '__FIGMA_IMAGE_REF__:' ) );
            $results[] = [
                'ref'             => $ref,
                'requires_export' => $requires_export,
            ];
        } elseif ( is_array( $value ) ) {
            foreach ( $value as $v ) {
                $this->scan_value( $v, $requires_export, $results );
            }
        }
    }

    // -----------------------------------------------------------------------
    // Placeholder replacement
    // -----------------------------------------------------------------------

    private function replace_placeholders( array $nodes, array $url_map ): array {
        return array_map( fn( $node ) => $this->replace_in_node( $node, $url_map ), $nodes );
    }

    private function replace_in_node( $value, array $url_map ) {
        if ( is_string( $value ) && str_starts_with( $value, '__FIGMA_IMAGE_REF__:' ) ) {
            $ref = substr( $value, strlen( '__FIGMA_IMAGE_REF__:' ) );
            return $url_map[ $ref ] ?? '';
        }

        if ( is_array( $value ) ) {
            $result = [];
            foreach ( $value as $key => $v ) {
                $result[ $key ] = $this->replace_in_node( $v, $url_map );
            }
            return $result;
        }

        return $value;
    }

    // -----------------------------------------------------------------------
    // WordPress Media Library sideloading
    // -----------------------------------------------------------------------

    /**
     * Download a remote image and add it to the WP Media Library.
     *
     * @param string $url      Remote image URL.
     * @param string $filename Desired filename (without extension).
     * @return string|null      Local WordPress URL, or null on failure.
     */
    private function sideload_to_media_library( string $url, string $filename ): ?string {
        if ( ! function_exists( 'media_handle_sideload' ) ) {
            require_once ABSPATH . 'wp-admin/includes/file.php';
            require_once ABSPATH . 'wp-admin/includes/media.php';
            require_once ABSPATH . 'wp-admin/includes/image.php';
        }

        // Download to temp file
        $tmp = download_url( $url, 30 );
        if ( is_wp_error( $tmp ) ) {
            return null;
        }

        $file_array = [
            'name'     => sanitize_file_name( $filename ) . '.png',
            'tmp_name' => $tmp,
        ];

        $attachment_id = media_handle_sideload( $file_array, 0, "Figma import: $filename" );

        if ( is_wp_error( $attachment_id ) ) {
            @unlink( $tmp );
            return null;
        }

        return wp_get_attachment_url( $attachment_id );
    }
}

כתיבת תגובה

האימייל לא יוצג באתר. שדות החובה מסומנים *


Notice: ob_end_flush(): Failed to send buffer of zlib output compression (1) in /home/greenspacecoil/public_html/wp-includes/functions.php on line 5493

Notice: ob_end_flush(): Failed to send buffer of zlib output compression (1) in /home/greenspacecoil/public_html/wp-includes/functions.php on line 5493