# media-cloud-sync/1.3.0/includes/integrations/media-library.php

Media Cloud Sync, version 1.3.0. 1,105 lines.

- Page: https://pluginprobe.com/plugins/media-cloud-sync/1.3.0/code/includes/integrations/media-library.php
- Raw: https://pluginprobe.com/plugins/media-cloud-sync/1.3.0/raw/includes/integrations/media-library.php
- Modified: 2025-09-28T14:09:44+00:00

Line numbers below start at 1. Link to a line or a range by appending a fragment to the
page URL, for example `https://pluginprobe.com/plugins/media-cloud-sync/1.3.0/code/includes/integrations/media-library.php#L10-L20`.

```php
<?php
namespace Dudlewebs\WPMCS;

defined('ABSPATH') || exit;

use Exception;
use WP_Error;

class MediaLibrary {
    private static $instance = null;
    private $assets_url;
    private $version;
    private $token;

    protected $settings;
	private $deleting_attachment = false;


    public static $source_type_prefix = "media";
	public static $label = 'Media Library';

    // Map which meta to be updated
	public static $source_types = [
		"media_library" => [
            'table'         => 'posts',
			'class'			=> 'MediaLibrary'
        ]
	];

    /**
     * Admin constructor.
     * @since 1.0.0
     */
    public function __construct() {
        $this->assets_url   = WPMCS_ASSETS_URL;
        $this->version      = WPMCS_VERSION;
        $this->token        = WPMCS_TOKEN;
        $this->settings     = Utils::get_settings();

        // Initialize setup
        $this->registerActions();
    }

    /**
     * Register integration access
     */
    public function registerActions() {
        /** IMAGE EDITOR COMPATIBILITY */
        add_action( 'attachment_submitbox_misc_actions', array( $this, 'attachment_submitbox_metadata'),99 );
        //Media Modal Ajax
		add_action( 'wp_ajax_wpmcs_get_attachment_details', array( $this, 'ajax_get_attachment_details' ) );

        /** URL RE-WRITING HOOKS */
        add_filter( 'wp_get_attachment_url', [ $this, 'wp_get_attachment_url' ], 99, 2 );
        add_filter( 'wp_get_attachment_image_attributes', [ $this, 'wp_get_attachment_image_attributes' ], 99, 3 );
        add_filter( 'wp_calculate_image_srcset', [ $this, 'wp_calculate_image_srcset' ], 99, 5 );
        add_filter( 'get_attached_file', [ $this, 'get_attached_file' ], 10, 2 );
        add_filter( 'wp_get_original_image_path', [ $this, 'get_attached_file' ], 10, 2 );
        add_filter( 'wp_video_shortcode', [ $this, 'wp_media_shortcode' ], 100, 5  );
        add_filter( 'wp_audio_shortcode', [ $this, 'wp_media_shortcode' ], 100, 5  );

        /** FILE MANAGEMENT HOOKS */
        add_filter( 'wp_unique_filename', [ $this, 'wp_unique_filename' ], 10, 3 );
        add_filter( 'wp_update_attachment_metadata', [ $this, 'update_attachment_metadata' ], 110, 2 );
		add_filter( 'pre_delete_attachment', [ $this, 'pre_delete_attachment' ], 20  );
        add_filter( 'delete_attachment', [ $this, 'delete_attachment' ], 20 );
		add_action( 'delete_post',  [$this, 'delete_post'] );
        add_filter( 'update_attached_file', [ $this, 'update_attached_file' ], 100, 2 ); 
    }


    /**
     * Allow processes to update the file on provider via update_attached_file()
     * @since 1.0.0
     * @param string $file
     * @param int    $attachment_id
     *
     * @return string
     */
    public function update_attached_file($file, $attachment_id) {
        if( !Utils::is_ok_to_upload($attachment_id) ) {
            return $file;
        }

        $item = Item::instance()->get($attachment_id, 'media_library');

        if (Utils::is_empty($item)) {
            return $file;
        }

        $file = apply_filters('wpmcs_update_attached_file', $file, $attachment_id, $item);

        return $file;
    }


    /**
     * Function to remove data from provider by attachment ID
     * @since 1.0.0
     *
     */
    public function delete_attachment($attachment_id){
        if (!Utils::is_service_enabled()) {
            return $attachment_id;
        }

        $wpmcsItem  = Item::instance();
        $item       = $wpmcsItem->get($attachment_id, 'media_library');

        if (Utils::is_empty($item)) {
            return $attachment_id;
        }

        $wpmcsItem->delete($attachment_id, 'media_library');

        return $attachment_id;
    }

    /**
     * Function to execute on wp_update_attachment_metadata
     * @since 1.0.0
     * @param array $attachment_meta
     * @param int   $attachment_id
     * @return array|WP_Error
     */
    public function update_attachment_metadata($attachment_meta, $attachment_id) {
        if (!Utils::is_ok_to_upload($attachment_id) || is_wp_error($attachment_meta)) {
            return $attachment_meta;
        }

        $attachment_id = (int) $attachment_id;
        $is_image = wp_attachment_is_image($attachment_id);

        if ($is_image && $this->should_wait_for_subsizes($attachment_meta, $attachment_id)) {
            return $attachment_meta;
        }

        $attachment_meta = $attachment_meta ?: wp_get_attachment_metadata($attachment_id);

        $file = $this->get_attachment_file($attachment_meta, $attachment_id);
        $source_path = Utils::get_attachment_source_path($file);

        // Remove Logs
        Logger::instance()->remove_log('sync_to_cloud', $attachment_id, 'media_library');

        if (empty($source_path) || !is_string($source_path)) {
            // Add Log
            Logger::instance()->add_log('sync_to_cloud', $attachment_id, 'media_library', [
                'message' => __('Unable to get attachment source path', 'media-cloud-sync'),
                'file' => $source_path,
                'code' => 400,
            ]);
            return $attachment_meta;
        }

        $existing = Item::instance()->get($attachment_id, 'media_library');
        $backup   = Item::instance()->get_backup($attachment_id, 'media_library');

        if (Utils::is_empty($existing)) {
            $this->handle_media_first_upload($attachment_meta, $attachment_id, $source_path);
        } elseif (Utils::is_empty($backup)) {
            $this->handle_media_with_no_backup($attachment_meta, $attachment_id, $source_path, $existing);
        } else {
            $this->handle_media_with_backup($attachment_meta, $attachment_id, $source_path, $existing, $backup);
        }

        return $attachment_meta;
    }

    /**
     * Checks if we should wait for WordPress to generate subsizes.
     */
    private function should_wait_for_subsizes($attachment_meta, $attachment_id) {
        if (empty($attachment_meta) || !function_exists('wp_get_registered_image_subsizes')) {
            return false;
        }

        // Wait for generate_attachment_metadata if the filter is set to true.
        if (apply_filters('wpmcs_wait_for_generate_attachment_metadata', false)) {
            return true;
        }

        // Check if there are any missing image subsizes.
        $image_sizes = apply_filters(
            'intermediate_image_sizes_advanced',
            wp_get_registered_image_subsizes(),
            $attachment_meta,
            $attachment_id
        );

        // If an image has been rotated, remove original image from metadata so that
        // `wp_get_missing_image_subsizes()` doesn't use non-rotated image for
        // generating missing thumbnail sizes.
        // Also, some images, particularly SVGs, don't create thumbnails but do have
        // metadata for them. At the time `wp_get_missing_image_subsizes()` checks
        // the saved metadata, it isn't there, but we already have it.
        $handle_post_meta = function ($value, $object_id, $meta_key, $single, $meta_type) use ($attachment_id, $attachment_meta) {
            if (
                !empty($value['image_meta']['orientation']) || 
                !empty($attachment_meta['image_meta']['orientation'])
            ) {
                if (!empty($value['image_meta']['orientation'])) {
                    unset($value['image_meta']['orientation']);
                }
                if (!empty($attachment_meta['image_meta']['orientation'])) {
                    unset($attachment_meta['image_meta']['orientation']);
                }
                unset($value['original_image'], $attachment_meta['original_image']);
            }
            if (
                is_null($value) && 
                $object_id === $attachment_id && 
                '_wp_attachment_metadata' === $meta_key && 
                $single && $meta_type === 'post'
            ) {
                return [$attachment_meta];
            }
            return $value;
        };

        add_filter('get_post_metadata', $handle_post_meta, 10, 5);
        $missing_sizes = wp_get_missing_image_subsizes($attachment_id);
        remove_filter('get_post_metadata', $handle_post_meta);

        return !empty(array_intersect_key($missing_sizes, $image_sizes));
    }

    /**
     * Gets the attachment file path.
     */
    private function get_attachment_file($attachment_meta, $attachment_id) {
        $file = $attachment_meta['file'] ?? Utils::get_post_meta($attachment_id, '_wp_attached_file', true);
        if ($file === basename($file)) {
            $file = Utils::get_post_meta($attachment_id, '_wp_attached_file', true);
        }
        return $file;
    }

    /**
     * Handles first upload.
     * @since 1.2.13
     * @param array $attachment_meta
     * @param int   $attachment_id
     * @param string $source_path
     */
    private function handle_media_first_upload($attachment_meta, $attachment_id, $source_path) {
        $uploaded_data = $this->uploadMedia($attachment_meta, $attachment_id, $source_path);
        if ( $uploaded_data && isset($uploaded_data['file']) && !empty($uploaded_data['file'])) {
            Item::instance()->add(
                $attachment_id,
                $uploaded_data['file']['url'],
                $uploaded_data['file']['key'],
                $uploaded_data['file']['source_path'],
                $uploaded_data['extra'],
                'media_library'
            );
        }
    }

    /**
     * Handles upload when no backup exists.
     * @since 1.2.13
     * @param array $attachment_meta
     * @param int   $attachment_id
     * @param string $source_path
     * @param array $existing
     */
    private function handle_media_with_no_backup($attachment_meta, $attachment_id, $source_path, $existing) {
        $uploaded_data = $this->uploadMedia($attachment_meta, $attachment_id, $source_path);

        if ($existing['source_path'] != $source_path) {
            $uploaded_data['extra']['backup'] = serialize($existing);
        }

        $this->update_item_if_uploaded($attachment_id, $uploaded_data);
    }

    /**
     * Handles upload when backup exists.
     * @since 1.2.13
     * @param array $attachment_meta
     * @param int   $attachment_id
     * @param string $source_path
     * @param array $existing
     * @param array $backup
     */
    private function handle_media_with_backup($attachment_meta, $attachment_id, $source_path, $existing, $backup) {
        $delete_existing = false;

        if ($backup['source_path'] != $source_path) {
            $uploaded_data = $this->uploadMedia($attachment_meta, $attachment_id, $source_path);
            $uploaded_data['extra']['backup'] = maybe_serialize($backup);

            if ($existing['source_path'] != $source_path) {
                $delete_existing = true;
            }
        } else {
            $delete_existing = true;

            // construct upload data from backup
            $uploaded_data = [
                'file' => [
                    'source_path' => $backup['source_path'],
                    'url'         => $backup['url'],
                    'key'         => $backup['key'],
                ],
                'extra' => maybe_unserialize($backup['extra']),
            ];
        }

        if ($delete_existing) {
            Item::instance()->delete_attachments_by_item($existing, false);
            Item::instance()->may_be_delete_server_files_by_item($existing, true);
        }

        $this->update_item_if_uploaded($attachment_id, $uploaded_data);
    }

    /**
     * Updates item if upload was successful.
     * @since 1.2.13
     * @param int   $attachment_id
     * @param array $uploaded_data
     * @return void
     */
    private function update_item_if_uploaded($attachment_id, $uploaded_data) {
        if (!empty($uploaded_data['file'])) {
            Item::instance()->update(
                $attachment_id,
                [
                    'source_path' => $uploaded_data['file']['source_path'],
                    'url'         => $uploaded_data['file']['url'],
                    'key'         => $uploaded_data['file']['key'],
                    'extra'       => maybe_serialize($uploaded_data['extra']),
                ],
                'media_library'
            );
        }
    }


    /**
     * Create unique names for files effects mainly on delete files from server settings
     * @since 1.0.0
     * @return string
     */
    public function wp_unique_filename($filename, $ext, $dir) {
        // Get Post ID if uploaded in post screen.
        $post_id = Utils::filter_input( 'post_id', INPUT_POST, FILTER_VALIDATE_INT );

        $filename = $this->filter_unique_filename($filename, $ext, $dir, $post_id);

        return $filename;
    }

    /**
     * filter unique file names
     * @since 1.0.0
     * @return string
     */
    private function filter_unique_filename($filename, $ext, $dir, $post_id = null) {
        if (!Utils::is_service_enabled()) {
            return $filename;
        }

        // sanitize the file name before we begin processing
        $filename   = sanitize_file_name($filename);
        $ext        = strtolower($ext);
        $name       = wp_basename($filename, $ext);

        // Edge case: if file is named '.ext', treat as an empty name.
        if ($name === $ext) {
            $name = '';
        }

        // Rebuild filename with lowercase extension as provider will have converted extension on upload.
        $filename = $name . $ext;

        return $this->generate_unique_filename($name, $ext, $dir);
    }


    /**
     * Generate unique filename
     * @since 1.0.0
     * @param string $name
     * @param string $ext
     * @param string $time
     *
     * @return string
     */
    private function generate_unique_filename($name, $ext, $dir) {
        $upload_dir         = wp_get_upload_dir();
        $filename           = $name . $ext;
        $no_ext_path        = $dir . '/' . $name;
        $rel_no_ext_path    = substr($no_ext_path, strlen(trailingslashit($upload_dir['basedir'])),strlen($no_ext_path));
        $path               = $dir . '/' . $name . $ext;
        $source_path        = substr($path, strlen(trailingslashit($upload_dir['basedir'])),strlen($path));


        $uploaded_files = Item::instance()->get_similar_files_by_path($rel_no_ext_path);

        if ($uploaded_files !== false) {
            if (Utils::check_existing_file_names($source_path, $uploaded_files) || file_exists($path)) {
                $count = 1;
                $new_file_name = '';
                $found = true;
                while ($found) {
                    $tmp_path   = $dir . '/' . $name . '-' . $count . $ext;
                    $rel_temp_path   = substr($tmp_path, strlen(trailingslashit($upload_dir['basedir'])),strlen($tmp_path));

                    if (Utils::check_existing_file_names($rel_temp_path, $uploaded_files) || file_exists($tmp_path)) {
                        $count++;
                    } else {
                        $found = false;
                        $new_file_name = $name . '-' . $count . $ext;
                    }
                }
                return $new_file_name;
            }
        } else {
            if (file_exists($path)) {
                $count = 1;
                $new_file_name = '';
                $found = true;

                while ($found) {
                    $tmp_path = $dir . '/' . $name . '-' . $count . $ext;
                    if (file_exists($tmp_path)) {
                        $count++;
                    } else {
                        $found = false;
                        $new_file_name = $name . '-' . $count . $ext;
                    }
                }
                return $new_file_name;
            }
        }

        return $filename;
    }


    /**
	 * Filters the audio & video shortcodes output to remove "&_=NN" params from source.src as it breaks signed URLs.
	 *
	 * @param string $html    Shortcode HTML output.
	 * @param array  $atts    Array of shortcode attributes.
	 * @param string $media   Media file.
	 * @param int    $post_id Post ID.
	 * @param string $library Media library used for the shortcode.
	 *
	 * @return string
	 *
	 * Note: Depends on 30377.4.diff from https://core.trac.wordpress.org/ticket/30377
	 */
	public function wp_media_shortcode( $html, $atts, $media, $post_id, $library ) {
		return preg_replace( '/&#038;_=[0-9]+/', '', $html );
	}

    /**
     * Return the provider URL when the server file is missing
     * unless we know who the calling process is and we are happy
     * to copy the file back to the server to be used.
     *
     * @handles get_attached_file
     * @handles wp_get_original_image_path
     * @since 1.0.0
     * @param string $file
     * @param int    $attachment_id
     *
     * @return string
     */
    public function get_attached_file($file, $attachment_id) {
        $attachment_id = (int)$attachment_id;

        // During the deletion of an attachment, stream wrapper URLs should not be returned.
		if ( $this->deleting_attachment ) {
			return $file;
		}

        if (!Utils::is_ok_to_serve($attachment_id)) {
            return $file;
        }

        $wpmcsItem = Item::instance();

        $item = $wpmcsItem->get($attachment_id, 'media_library');

        if ( file_exists( $file ) || Utils::is_empty($item)) {
            if(!Utils::is_empty($item)) {
                /**
                 * Added filter to allow plugins to copy the pending size to the server
                 * before the file is served.
                 * 
                 * @param string $file
                 * @param string $file
                 * @param int    $attachment_id
                 */
                return apply_filters( 'wpmcs_get_attached_file_noop', $file, $file, $attachment_id, $item );
            } else {
                return $file;
            }
        }
        
        $url = $wpmcsItem->get_url($attachment_id, 'full', 'media_library');
        if(Utils::is_empty($url)) { 
            return $file;
        }
        /**
		 * This filter gives filter implementors a chance to copy back missing item files
		 * from the provider before WordPress returns the file name/path for it. Defaults to
		 * returning the remote URL.
		 *
		 * @param string             $url           Item URL
         * @param string             $file          Server file path
         * @param int                $attachment_id Attachment ID
         * @param array              $item          Item data
		 */
        return apply_filters('wpmcs_get_attached_file', $url, $file, $attachment_id, $item);
    }


    /**
     * Change src attributes
     * @since 1.0.0
     */

    public function wp_calculate_image_srcset($sources, $size_array, $image_src, $attachment_meta, $attachment_id = 0) {
        $attachment_id = (int)$attachment_id;

        // Must need $attachment_id other wise not possible to get data from the table
        if (!Utils::is_ok_to_serve($attachment_id)) {
            return $sources;
        }

        $wpmcsItem = Item::instance();

        $item = $wpmcsItem->get($attachment_id, 'media_library');

        if (Utils::is_empty($item)) {
            return $sources;
        }

        $item_extra = $wpmcsItem->get_extras($attachment_id, false, 'media_library');

        if (isset($item_extra['width']) && !empty($item_extra['width'])) {
            $sources[$item_extra['width']]=[
                'url'           => $wpmcsItem->get_url($attachment_id, 'full', 'media_library'),
                'descriptor'    => 'w',
				'value'         => $item_extra['width']
            ];
        }

        if ($item_extra) {
            if (isset($item_extra['sizes']) && !empty($item_extra['sizes'])) {
                foreach ($item_extra['sizes'] as $size => $size_array) {
                    if (isset($size_array['width']) && !empty($size_array['width'])) {
                        $w = $size_array['width'];
                        if (isset($sources[$w]) && !empty($sources[$w])) {
                            $sources[$w]['url'] = $wpmcsItem->get_url($attachment_id, $size, 'media_library');
                        }
                    }
                }
            }
        }

        return $sources;
    }

    /**
     * Filters the list of attachment image attributes.
     *
     * @since 1.0.0
     * @param array        $attr  Attributes for the image markup.
     * @param WP_Post      $attachment Image attachment post.
     * @param string|array $size  Requested size. Image size or array of width and height values (in that order).
     *
     * @return array
     */
    public function wp_get_attachment_image_attributes($attr, $attachment, $size='thumbnail') {
        if (
            !$attachment || 
            !Utils::is_ok_to_serve($attachment->ID)
        ) {
            return $attr;
        }

        $wpmcsItem = Item::instance();

        $item = $wpmcsItem->get($attachment->ID, 'media_library');

        if (Utils::is_empty($item)) {
            return $attr;
        }

        $size = Utils::maybe_convert_size_to_string($attachment->ID, $size);
        if ($size === false) {
            return $attr;
        }

        

        if (
            isset($size) && !empty($size) &&
            isset($attr['src']) && !empty($attr['src'])
        ) {
            $source = $wpmcsItem->get_url($attachment->ID, $size, 'media_library');
            if (isset($source) && !empty($source)) {
                $attr['src'] = $source;
            }
        }

        /**
         * Filtered list of attachment image attributes.
         *
         * @param array              $attr       Attributes for the image markup.
         * @param WP_Post            $attachment Image attachment post.
         * @param string             $size       Requested size.
         */
        return apply_filters('wpmcs_wp_get_attachment_image_attributes', $attr, $attachment, $size, $item);
    }

    /**
     * Get attachment url
     * @since 1.0.0
     * @param string $url
     * @param int    $attachment_id
     *
     * @return bool|mixed|WP_Error
     */
    public function wp_get_attachment_url($url, $attachment_id) {
        if (!Utils::is_ok_to_serve($attachment_id)) {
            return $url;
        }

        $new_url = Item::instance()->get_url($attachment_id, 'full', 'media_library');

        if (Utils::is_empty($new_url)) {
            return $url;
        }

        $new_url = apply_filters('wpmcs_wp_get_attachment_url', $new_url, $url, $attachment_id);

        return $new_url;
    }

    /**
     * Upload media item
     */
    public function uploadMedia($attachment_meta, $attachment_id, $source_path) {
        $wpmcsItem              = Item::instance();
        $upload_dir             = wp_get_upload_dir();
        $is_image               = wp_attachment_is_image($attachment_id);
        $existing               = $wpmcsItem->get($attachment_id, 'media_library'); 
        $existing_extras        = $wpmcsItem->get_extras($attachment_id, false, 'media_library'); 
        $has_existing           = !Utils::is_empty($existing);
        $sizes                  = [];
        $uploaded               = [];
        $extras                 = [];
        $prefix                 = '';
        $file_path              = '';
        $file_dir               = '';
        $original_file_path     = '';
        $original_file_source_path = '';


        // Add prefix if object versioning is ON
        if (isset($this->settings['object_versioning']) && $this->settings['object_versioning']) {
            $prefix             = ($existing_extras && isset($existing_extras['prefix']) && !empty($existing_extras['prefix'])) 
                                    ? $existing_extras['prefix'] 
                                    : Utils::generate_object_versioning_prefix();
            $extras['prefix']   = $prefix;
        }

        // Get width and height from image meta
        if (isset($attachment_meta) && !empty($attachment_meta)) {
            $extras['width']  = (isset($attachment_meta['width']) && !empty($attachment_meta['width'])) ? $attachment_meta['width'] : 0;
            $extras['height'] = (isset($attachment_meta['height']) && !empty($attachment_meta['height'])) ? $attachment_meta['height'] : 0;
        }


        // Get Original File Name/Path from Image meta
        $original_file = isset($attachment_meta) && !empty($attachment_meta) && 
                         isset($attachment_meta['original_image']) && !empty($attachment_meta['original_image'])
                            ? $attachment_meta['original_image'] : '';

        $file_path  = trailingslashit($upload_dir['basedir']) . $source_path;
        $file_dir   = isset(pathinfo($file_path)['dirname']) ? pathinfo($file_path)['dirname'] : '';

        // Check whether the extension is enabled for uploading
        if (!Utils::is_extension_available($file_path)) {
            Logger::instance()->add_log('sync_to_cloud', $attachment_id, 'media_library', [
                'message' => __('File extension is not supported', 'media-cloud-sync'),
                'file'    => $file_path,
                'code'    => 415
            ]);
            return $attachment_meta;
        }

        // Upload the Full Size file
        if( $has_existing && ( $existing['source_path'] == $source_path ) ) {
            $uploaded = [
                'success'   => true,
                'file_url'  => $existing['url'],
                'key'       => $existing['key']
            ];
        } else if(file_exists($file_path)){
            $uploaded = Service::instance()->uploadSingle($file_path, $source_path, $prefix);
        } else {
            Logger::instance()->add_log('sync_to_cloud', $attachment_id, 'media_library', [
                'message' => __('File not found', 'media-cloud-sync'),
                'file'    => $file_path,
                'code'    => 404
            ]);
        }

        if(
            isset($uploaded) && !empty($uploaded) &&
            isset($uploaded['success']) && $uploaded['success']
        ) {
            if(isset($original_file) && !empty($original_file)){
                // Find original image relative and absolute path
                $original_file_path = trailingslashit($file_dir) . $original_file;
                $original_file_source_path = Utils::get_attachment_source_path($original_file_path);
                $uploaded_original  = [];

                // Upload Original File
                if(
                    !Utils::is_empty($existing_extras) && 
                    isset($existing_extras['original']) && !Utils::is_empty($existing_extras['original']) &&
                    $existing_extras['original']['source_path'] == $original_file_source_path
                ) {
                    $uploaded_original = [
                        'success'   => true,
                        'file_url'  => $existing_extras['original']['url'],
                        'key'       => $existing_extras['original']['key']
                    ];
                } else if(file_exists($original_file_path)) {
                    $uploaded_original = Service::instance()->uploadSingle($original_file_path, $original_file_source_path, $prefix);
                } else {
                    Logger::instance()->add_log('sync_to_cloud', $attachment_id, 'media_library', [
                        'message' => __('Original File not found', 'media-cloud-sync'),
                        'file'    => $original_file_path,
                        'code'    => 404
                    ]);
                }

                if(
                    isset($uploaded_original) && !empty($uploaded_original) &&
                    isset($uploaded_original['success']) && $uploaded_original['success']
                ) {
                    $extras['original'] = array(
                        'source_path'   => $original_file_source_path,
                        'url'           => $uploaded_original['file_url'],
                        'key'           => $uploaded_original['key']
                    );
                } else {
                    if(isset($uploaded_original['success']) && !$uploaded_original['success']) {
                        Logger::instance()->add_log('sync_to_cloud', $attachment_id, 'media_library', [
                            'message' => __('Original File upload failed', 'media-cloud-sync'),
                            'file'    => $original_file_path,
                            'code'    => 500
                        ]);
                    }
                }
            }

            if (
                $is_image &&
                isset($attachment_meta['sizes']) && !empty($attachment_meta['sizes']) &&
                isset($file_dir) && !empty($file_dir)
            ) {
                foreach ($attachment_meta['sizes'] as $size => $sub_image) {
                    $sub_size           = [];
                    $sub_file           = isset($sub_image['file']) ? $sub_image['file'] : false;
                    $sub_file_path      = '';
                    $sub_file_source_path  = '';
                    $uploaded_sub_image = [];
    
                    if ($sub_file) {
                        $sub_file_path = $file_dir . '/' . $sub_file;
                        $sub_file_source_path = Utils::get_attachment_source_path($sub_file_path);
                    }

                    // Upload Image size
                    if(
                        !Utils::is_empty($existing_extras) && 
                        isset($existing_extras['sizes']) && !Utils::is_empty($existing_extras['sizes']) &&
                        isset($existing_extras['sizes'][$size]) && !Utils::is_empty($existing_extras['sizes'][$size]) &&
                        $existing_extras['sizes'][$size]['source_path'] == $sub_file_source_path
                    ) {
                        $uploaded_sub_image = [
                            'success'   => true,
                            'file_url'  => $existing_extras['sizes'][$size]['url'],
                            'key'       => $existing_extras['sizes'][$size]['key']
                        ];
                    } else if(file_exists($sub_file_path)) {
                        $uploaded_sub_image = Service::instance()->uploadSingle($sub_file_path, $sub_file_source_path, $prefix);
                    } else {
                        Logger::instance()->add_log('sync_to_cloud', $attachment_id, 'media_library', [
                            /* translators: %1$s: image size name */
                            'message' => sprintf(__('Image size %1$s not found', 'media-cloud-sync'), $size),
                            'file'    => $sub_file_path,
                            'code'    => 404
                        ]);
                    }

                    if (
                        isset($uploaded_sub_image) && !empty($uploaded_sub_image) &&
                        isset($uploaded_sub_image['success']) && $uploaded_sub_image['success']
                    ) {
                        $sub_size['source_path']    = $sub_file_source_path;
                        $sub_size['url']            = $uploaded_sub_image['file_url'];
                        $sub_size['key']            = $uploaded_sub_image['key'];
                        $sub_size['width']          = isset($sub_image['width']) ? $sub_image['width']: 0;
                        $sub_size['height']         = isset($sub_image['height']) ? $sub_image['height']: 0;
                    } else {
                        if(isset($uploaded_sub_image['success']) && !$uploaded_sub_image['success']) {
                            Logger::instance()->add_log('sync_to_cloud', $attachment_id, 'media_library', [
                                /* translators: %1$s: image size name */
                                'message' => sprintf(__('Image size %1$s upload failed', 'media-cloud-sync'), $size),
                                'file'    => $sub_file_path,
                                'code'    => 500
                            ]);
                        }
                    }
    
                    $sizes[$size] = $sub_size;
                }
            }
    
            
            if (isset($sizes) && !empty($sizes)) {
                $extras['sizes'] = $sizes;
            }

            return [
                'file' => [
                    'source_path'   => $source_path,
                    'url'           => $uploaded['file_url'],
                    'key'           => $uploaded['key'],
                ],
                'extra' => $extras
            ];

        } else {
            if(isset($uploaded['success']) && !$uploaded['success']) {
                Logger::instance()->add_log('sync_to_cloud', $attachment_id, 'media_library', [
                    'message' => __('File upload failed', 'media-cloud-sync'),
                    'file'    => $file_path,
                    'code'    => 500
                ]);
            }
        }

        return false;
    }


    /**
     * Get Total Media Count (queried)
     * 
     * Param added because need a generic function name, 
     * if the function calls by source_type
     */
    public static function get_total_media($source_type) {
        global $wpdb;
    
        // Fetch the count of attachments with the 'inherit' status
        $count = $wpdb->get_var(
            $wpdb->prepare(
                "SELECT COUNT(1) FROM {$wpdb->posts} WHERE post_type = %s AND post_status = %s",
                'attachment',
                'inherit'
            )
        );
    
        return (int)$count;
    }


    /**
     * Upload pending media files.
     *
     * Processes media attachments that are pending and haven't been synced yet.
     *
     * @param string $source_type Source type for identifying which source..
     * @param int $count  Number of media to process. Default is 0.
     * @param int $offset Offset for media query. Default is 0.
     * @return array      Status array with success and failed media IDs.
     */
    public function upload_pending_media($source_type, $count = 0, $offset = 0 ) {
        global $wpdb;
        
        $failed     = 0;

        $source_type_data = self::$source_types[$source_type] ?? false;
		if (!$source_type_data) {
			return [
				'success' => true,
				'failed' => $failed + $count,
			];
		}
	
		$source_table = $wpdb->prefix . $source_type_data['table'];

        // Sanitize inputs
        $count  = intval($count);
        $offset = intval($offset);

        // Query pending media
        $query = $wpdb->prepare(
            "SELECT DISTINCT posts.ID
            FROM {$source_table} AS posts
            WHERE posts.post_type = 'attachment'
			AND posts.ID NOT IN (
			    SELECT items.source_id
				FROM " . Db::get_table_name() . " AS items
				WHERE items.source_type = %s
				AND items.source_id = posts.ID                
            ) 
            ORDER BY posts.ID DESC LIMIT %d, %d",
            $source_type,
            $offset,
            $count > 0 ? $count : PHP_INT_MAX // Handle no limit for -1
        );

        $medias = $wpdb->get_results($query);

        // Process the queried media
        if (!empty($medias)) {
            foreach ($medias as $media) {
                $media_id = $media->ID;
                // Attempt to sync the attachment
                try {
                    $this->update_attachment_metadata([], $media_id);
                } catch (Exception $e) {
                    $failed++; // Add to failed if sync fails
                    continue;
                }

                // Verify if the media was successfully processed
                if (!Item::instance()->get($media_id)) {
                    $failed++;
                }
            }
        }

        return [
            'success' => true,
            'failed'  => $failed,
        ];
    }


    /**
	 * Edit Image Meta In View Image
	 * @since 1.0.0
	 */
	function attachment_submitbox_metadata( ) {
        $post          = get_post();
	    $attachment_id = $post->ID;

        if (!Utils::is_ok_to_serve($attachment_id)) {
            return;
        }

        $wpmcsItem = Item::instance();

        $item = $wpmcsItem->get($attachment_id, 'media_library');

        if (Utils::is_empty($item)) {
            return;
        }
        
        $provider = $wpmcsItem->get_field($attachment_id, 'provider', 'media_library');
        if($provider) { 
            $label = Schema::getServiceLabels($provider); ?>
            <div class="misc-pub-section misc-pub-provider">
                <?php esc_html_e( 'Provider :', 'media-cloud-sync' ); ?> <strong><?php echo esc_textarea(!empty($label) ? $label : $provider); ?></strong></a>
            </div>
        <?php
        }

        $region = $wpmcsItem->get_field($attachment_id, 'region', 'media_library');
        if($region) { ?>
            <div class="misc-pub-section misc-pub-provider">
                <?php esc_html_e( 'Region :', 'media-cloud-sync' ); ?> <strong><?php echo esc_textarea($region); ?></strong></a>
            </div>
        <?php
        }
        $private = (int)$wpmcsItem->get_field($attachment_id, 'is_private', 'media_library');
        ?>
            <div class="misc-pub-section misc-pub-provider">
                <?php esc_html_e( 'Access :', 'media-cloud-sync' ); ?> <strong><?php $private ? esc_html_e( 'Private', 'media-cloud-sync' ) : esc_html_e( 'Public', 'media-cloud-sync' ); ?></strong></a>
            </div>
        <?php
	}


    /**
     * Function to get attachment details by ID
     */
    public function ajax_get_attachment_details() {
        $result = array(
            'status'    => false,
            'data'      => array(),
            'exclude'   => false
        );

        if ( ! isset( $_POST['id'] ) ) {
            wp_send_json_success( $result );
		}

		check_ajax_referer( 'get_media_provider_details', '_nonce' );

		$id= intval( sanitize_text_field( $_POST['id'] ) );
        
        // Return if extension not allowed
        $path = get_attached_file( $id );
        if(!Utils::is_extension_available($path)) {
            $result['exclude'] = true;
            wp_send_json_success( $result );
        }

        if (!Utils::is_ok_to_serve($id)) {
            wp_send_json_success( $result );
        }

        $wpmcsItem = Item::instance();

        $item = $wpmcsItem->get($id, 'media_library');

        if (Utils::is_empty($item)) {
            wp_send_json_success( $result );
        }

        $provider = $wpmcsItem->get_field($id, 'provider', 'media_library');
        if($provider){
            $label = Schema::getServiceLabels($provider);
            $item['provider'] = !empty($label) ? $label : $provider;
        }
        $region = $wpmcsItem->get_field($id, 'region', 'media_library');
        if($region){
            $item['region'] = $region;
        }
        $item['private'] = $wpmcsItem->get_field($id, 'private', 'media_library');
        if($item) {
            $result= array(
                'status' => true,
                'data' => $item
            );
        }
        
        wp_send_json_success( $result );
    }

    /**
	 * Takes notice that an attachment is about to be deleted and prepares for it.
	 *
	 * @handles pre_delete_attachment
	 *
	 * @param bool|null $delete Whether to go forward with deletion.
	 *
	 * @return bool|null
	 */
	public function pre_delete_attachment( $delete ) {
		if ( is_null( $delete ) ) {
			$this->deleting_attachment = true;
		}

		return $delete;
	}

	/**
	 * Takes notice that an attachment has been deleted and undoes previous preparations for the event.
	 *
	 * @handles delete_post
	 *
	 * Note: delete_post is used as there is a potential that deleted_post is not reached.
	 */
	public function delete_post() {
		$this->deleting_attachment = false;
	}

    /**
     * Is installed?
     *
     * @return bool
     */
    public static function is_installed(): bool {
        // It is inbuilt in worpress
        return true;
    }


    
    public static function instance(){
        if (is_null(self::$instance)) {
            self::$instance = new self();
        }
        return self::$instance;
    }
}
```
