# wp-stateless/2.3.2/lib/classes/compatibility/shortpixel.php

WP-Stateless – Google Cloud Storage, version 2.3.2. 486 lines.

- Page: https://pluginprobe.com/plugins/wp-stateless/2.3.2/code/lib/classes/compatibility/shortpixel.php
- Raw: https://pluginprobe.com/plugins/wp-stateless/2.3.2/raw/lib/classes/compatibility/shortpixel.php
- Modified: 2019-12-26T05:14:14+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/wp-stateless/2.3.2/code/lib/classes/compatibility/shortpixel.php#L10-L20`.

```php
<?php
/**
 * Plugin Name: ShortPixel Image Optimizer
 * Plugin URI: https://wordpress.org/plugins/shortpixel-image-optimiser/
 *
 * Compatibility Description: Ensures compatibility with ShortPixel Image Optimizer.
 *
 * We don't need to download image to server from GCS to optimize image. As it can directly use GCS URL.
 * 
 * @todo Use backup version of image on Regenerate and Sync with GCS.
 * @todo Restore image now download from backup dir then upload to regular GCS path again. We need to fix that. 
 *          https://cloud.google.com/storage/docs/renaming-copying-moving-objects#copy
 * @todo implement a customized version of ShortPixelMetaFacade::getURLsAndPATHs() function.
 * @todo convert GCS URL from http://storage.googleapis.com/udx-ci-develop-alim/ to http://udx-ci-develop-alim.storage.googleapis.com
 */

namespace wpCloud\StatelessMedia {
    use ShortPixel\ShortPixelLogger\ShortPixelLogger as Log;

    if(!class_exists('wpCloud\StatelessMedia\ShortPixel')) {
        
        class ShortPixel extends ICompatibility {

            protected $id = 'shortpixel';
            protected $title = 'ShortPixel Image Optimizer';
            protected $constant = 'WP_STATELESS_COMPATIBILITY_SHORTPIXEL';
            protected $description = 'Ensures compatibility with ShortPixel Image Optimizer.';
            protected $plugin_file = 'shortpixel-image-optimiser/wp-shortpixel.php';
            private   $jsSuffix = '.min.js';

            public function module_init($sm){
                add_action( 'shortpixel_image_optimised', array($this, 'shortpixel_image_optimised') );
                add_filter( 'shortpixel_image_exists', array($this, 'shortpixel_image_exists'), 10, 3 );
                // A way to disable the URL conversion to subdomain format.
                if(!defined( 'WP_STATELESS_MEDIA_SHORTPIXEL_DISABLE_SUBDOMAIN_LINK' ) ||  !WP_STATELESS_MEDIA_SHORTPIXEL_DISABLE_SUBDOMAIN_LINK){
                    // URL conversion to subdomain format {bucket}.storage.googleapis.com instead of storage.googleapis.com/{bucket}
                    // So that ShortPixel don't count all Stateless request as one domain.
                    add_filter( 'shortpixel_image_urls', array($this, 'shortpixel_image_urls'), 10, 2 );
                }
                add_filter( 'shortpixel_skip_backup', array($this, 'shortpixel_skip_backup'), 10, 3 );
                add_filter( 'wp_update_attachment_metadata', array( $this, 'wp_update_attachment_metadata' ), 10, 2 );
                // Remove backup and webp version of image.
                add_filter( 'shortpixel_skip_delete_backups_and_webps', array( $this, 'shortpixel_skip_delete_backups_and_webps' ), 10, 2 );
                add_filter( 'shortpixel_backup_folder', array( $this, 'getBackupFolderAny' ), 10, 3 );
                add_filter( 'wp_stateless_add_media_args', array($this, 'wp_stateless_add_media_args') );
                add_filter( 'shortpixel_webp_image_base', array($this, 'shortpixel_webp_image_base'), 10, 2 );
                // add_filter( 'shortpixel_skip_restore_image', array( $this, 'shortpixel_skip_restore_image' ), 10, 2 );

                add_action( 'shortpixel_before_restore_image', array($this, 'shortpixel_before_restore_image') );
                add_action( 'shortpixel_after_restore_image', array($this, 'handleRestoreBackup') );
                add_action( 'admin_enqueue_scripts', array( $this, 'shortPixelJS') );
                // Sync from sync tab
                add_action( 'sm:synced::image', array( $this, 'sync_backup_file'), 10, 2 );
                add_action( 'sm:synced::image', array( $this, 'sync_webp_file'), 10, 2 );

                
                if (Log::debugIsActive()) {
                    $this->jsSuffix = '.js'; //use unminified versions for easier debugging
                }

            }

            public function shortPixelJS(){
                $upload_dir = wp_upload_dir();

                wp_enqueue_script('stateless-short-pixel', ud_get_stateless_media()->path( 'lib/classes/compatibility/js/shortpixel.js', 'url'), array('shortpixel' . $this->jsSuffix), '', true);
                
                $image_host = ud_get_stateless_media()->get_gs_host();
                $bucketLink = apply_filters('wp_stateless_bucket_link', $image_host);
                
                wp_localize_script( 'stateless-short-pixel', '_stateless_short_pixel', array(
                    'baseurl' => $upload_dir[ 'baseurl' ],
                    'bucketLink' => $bucketLink,
                ));

            }

            /**
             * Return Path of ShortPixel backup path.
             * Bypass the checking whether a backup file exist when returning backup path.
             * @todo check on GCS if backup really exist. Maybe we can implement transient caching for performance.
             */
            public function getBackupFolderAny( $ret, $file, $thumbs ) {
                if($ret == false){
                    $fullSubDir = $this->returnSubDir($file);
                    $ret = SHORTPIXEL_BACKUP_FOLDER . '/' . $fullSubDir;
                    
                }
                return $ret;
            }

            /**
             * Check whether image exist on GCS.
             * Only when image is not available on server.
             */
            public function shortpixel_image_exists( $return, $path, $id = null ) {
                if($return) return $return;

                $key = "stateless_url_to_postid_" . md5($path);
                $return = get_transient( $key );
                // echo "\npath: $path \nKey: $key\nReturn: $return\nID: $id\n  ";
                if(!$return){
                    // Checking by matching file name in gs_name and $path.
                    if(!empty($id)){
                        $metadata = wp_get_attachment_metadata($id);
                        $basename = basename($path);
                        if(!empty($metadata['gs_name'])){
                            $gs_basename = basename($metadata['gs_name']);
                            if($gs_basename == $basename){
                                $return = true;
                            }

                            if(is_array($metadata['sizes'])){
                                foreach ($metadata['sizes'] as $key => &$data) {
                                    if(empty($data['gs_name'])) continue;
                                    $gs_basename = basename($data['gs_name']);
                                    if($gs_basename == $basename){
                                        $return = true;
                                    }
                                }
                            }
                        }
                    }
                    // Directly check on GCS if image exist.
                    else if(empty($id)){
                        $wp_uploads_dir = wp_get_upload_dir();
                        $gs_name = str_replace(trailingslashit($wp_uploads_dir['basedir']), '', $path);
                        $gs_name = str_replace(trailingslashit($wp_uploads_dir['baseurl']), '', $gs_name);
                        $gs_name = str_replace(trailingslashit(ud_get_stateless_media()->get_gs_host()), '', $gs_name);
                        $gs_name = apply_filters( 'wp_stateless_file_name', $gs_name);
                        if ( $media = ud_get_stateless_media()->get_client()->media_exists( $gs_name ) ) {
                            $return = true;
                        }
                    }
                    set_transient( $key, $return, 10 * MINUTE_IN_SECONDS );
                }
                return $return;
            }

            /**
             * Short-circuit filter.
             * We need to remove backup image from GCS when shortpixel tries to delete from server.
             * We are returning true to short-circuit in stateless mood, because file not exist in server.
             */
            public function shortpixel_skip_delete_backups_and_webps($return, $paths){
                if(empty($paths) || !is_array($paths)) return $return;

                $sp__uploads = wp_upload_dir();
                $fullSubDir = $this->returnSubDir($paths[0]);
                $backup_path = SHORTPIXEL_BACKUP_FOLDER . '/' . $fullSubDir;

                foreach ($paths as $key => $path) {
                    // Removing backup
                    $name = apply_filters( 'wp_stateless_file_name',  SHORTPIXEL_BACKUP . '/' . $fullSubDir . basename($path));
                    do_action( 'sm:sync::deleteFile', $name);

                    // Removing WebP
                    $backup_images = \WPShortPixelSettings::getOpt('wp-short-create-webp');
                    if($backup_images){
                        $name = str_replace($sp__uploads['basedir'], '', $path);
                        $name = apply_filters( 'wp_stateless_file_name',  $name . '.webp');
                        do_action( 'sm:sync::deleteFile', $name);
                    }
                }

                if ( ud_get_stateless_media()->get( 'sm.mode' ) == 'stateless' ) {
                    return true;
                }
                // When stateless mode isn't set backup files will be available in server. So no short-circuit.
                return $return;
            }

            /**
             * Skip the original backup process in stateless mode.
             */
            public function shortpixel_skip_backup( $return, $mainPath, $PATHs ){
                if ( ud_get_stateless_media()->get( 'sm.mode' ) == 'stateless' ) {
                    return true;
                }
                return $return;
            }

            /**
             * In stateless mode we need to take backup directly from original location.
             * Because we will skip the backup process of shortpixel.
             */
            public function wp_update_attachment_metadata( $metadata, $attachment_id ){
                if ( ud_get_stateless_media()->get( 'sm.mode' ) == 'stateless' ) {
                    $backup_images = \WPShortPixelSettings::getOpt('wp-short-backup_images');
                    if($backup_images){
                        $this->sync_backup_file($attachment_id, $metadata, false, array('before_optimization' => true));
                    }
                }
                return $metadata;
            }

            /**
             * Sync image after optimization.
             * 
             */
            public function shortpixel_image_optimised($id){
                $metadata = wp_get_attachment_metadata( $id );
                ud_get_stateless_media()->add_media( $metadata, $id, true );
                // Sync the webp to GCS
                $create_webp = \WPShortPixelSettings::getOpt('wp-short-create-webp');
                if($create_webp){
                    add_filter( 'upload_mimes', array($this, 'add_webp_mime'), 10, 2 );
                    ud_get_stateless_media()->add_media( $metadata, $id, true, array('is_webp' => '.webp') );
                }
                // Don't needed in stateless mode. In stateless mode the back will be sync once on wp_update_attachment_metadata filter.
                if ( ud_get_stateless_media()->get( 'sm.mode' ) !== 'stateless' ) {
                    $this->sync_backup_file($id, $metadata, true);
                }
            }

            /**
             * Before shortpixel tries to restore from backup we need to make files available on server.
             */
            public function shortpixel_before_restore_image($id, $metadata = null){
                $this->sync_backup_file($id, $metadata, true, array('download' => true));
            }

            /**
             * Disable default shortpixel restore and directly update image on GCS from backup copy in GCS.
             */
            public function shortpixel_skip_restore_image($return, $id = null){
                if(ud_get_stateless_media()->get( 'sm.mode' ) === 'stateless'){
                    $this->client = ud_get_stateless_media()->get_client();
                    $this->client->copy_media('localhost/ShortpixelBackups/wp-content/uploads/2019/04/htpps.png', 'localhost/2019/04/htpps.png');
                    return true;
                }
                return $return;
            }

            /**
             * Sync backup image
             * 
             * @param $before_optimization: pass true if you want to sync directly from original path instead of backup path.
             */
            public function sync_backup_file($id, $metadata = null, $force = false, $args = array()){
                $args = wp_parse_args($args, array(
                    'download'              => false, // whether to only download.
                    'before_optimization'   => false, // whether to delete local file in stateless mode.
                ));
                
                /* Get metadata in case if method is called directly. */
                if( empty($metadata) ) {
                    $metadata = wp_get_attachment_metadata( $id );
                }
                /* Now we go through all available image sizes and upload them to Google Storage */
                if( !empty( $metadata[ 'sizes' ] ) && is_array( $metadata[ 'sizes' ] ) ) {

                    // Sync backup file with GCS
                    $file_path = get_attached_file( $id );
                    $fullSubDir = $this->returnSubDir($file_path);
                    $backup_path = SHORTPIXEL_BACKUP_FOLDER . '/' . $fullSubDir;
                    if($args['before_optimization']){
                        $upload_dir = wp_upload_dir();
                        $backup_path = $upload_dir['basedir'] . '/' . dirname($metadata[ 'file' ]);
                        $args = array( 'stateless' => false );
                    }
                    
                    $absolutePath = trailingslashit($backup_path) . basename($metadata[ 'file' ]);
                    $name = apply_filters( 'wp_stateless_file_name',  SHORTPIXEL_BACKUP . '/' . $fullSubDir . basename($metadata[ 'file' ]));
                    do_action( 'sm:sync::syncFile', $name, $absolutePath, $force, $args);

                    foreach( (array) $metadata[ 'sizes' ] as $image_size => $data ) {
                        $absolutePath = trailingslashit($backup_path) . $data[ 'file' ];
                        $name = apply_filters( 'wp_stateless_file_name',  SHORTPIXEL_BACKUP . '/' . $fullSubDir . $data[ 'file' ]);
                        
                        do_action( 'sm:sync::syncFile', $name, $absolutePath, $force, $args);
                    }

                }
            }

            /**
             * Sync from sync tab
             * 
             */
            public function sync_webp_file($id, $metadata = null){
                /* Get metadata in case if method is called directly. */
                if( empty($metadata) ) {
                    $metadata = wp_get_attachment_metadata( $id );
                }
                add_filter( 'upload_mimes', array($this, 'add_webp_mime'), 10, 2 );
                // Sync the webp to GCS
                ud_get_stateless_media()->add_media( $metadata, $id, true, array('is_webp' => '.webp') );
            }

            /**
             * return subdir for that particular attached file - if it's media library then last 3 path items, otherwise substract the uploads path
             * Has trailing directory separator (/)
             * 
             * @copied from shortpixel-image-optimiser\class\db\shortpixel-meta-facade.php
             * @param type $file
             * @return string
             */
            public function returnSubDir($file){
                $hp = wp_normalize_path(get_home_path());
                $file = wp_normalize_path($file);
                $sp__uploads = wp_upload_dir();
                if(strstr($file, $hp)) {
                    $path = str_replace( $hp, "", $file);
                } elseif( strstr($file, dirname( WP_CONTENT_DIR ))) { //in some situations the content dir is not inside the root, check this also (ex. single.shortpixel.com)
                    $path = str_replace( trailingslashit(dirname( WP_CONTENT_DIR )), "", $file);
                } elseif( (strstr(realpath($file), realpath($hp)))) {
                    $path = str_replace( realpath($hp), "", realpath($file));
                } elseif( strstr($file, trailingslashit(dirname(dirname( $sp__uploads['basedir'] )))) ) {
                    $path = str_replace( trailingslashit(dirname(dirname( $sp__uploads['basedir'] ))), "", $file);
                } else {
                    $path = (substr($file, 1));
                }
                $pathArr = explode('/', $path);
                unset($pathArr[count($pathArr) - 1]);
                return implode('/', $pathArr) . '/';
            }

            /**
             * Sync images after shortpixel restore them from backup.
             */
            public function handleRestoreBackup($attachmentID){
                $metadata = wp_get_attachment_metadata( $attachmentID );
                $this->add_media( $metadata, $attachmentID );
            }
            
            /**
             * Customized version of wpCloud\StatelessMedia\Utility::add_media()
             * to satisfied our need in restore backup
             * If a image isn't restored from backup then ignore it.
             */
            public static function add_media( $metadata, $attachment_id ) {
                $upload_dir = wp_upload_dir();

                $client = ud_get_stateless_media()->get_client();

                if( !is_wp_error( $client ) ) {

                    $fullsizepath = wp_normalize_path( get_attached_file( $attachment_id ) );
                    // Make non-images uploadable.
                    if( empty( $metadata['file'] ) && $attachment_id ) {
                        $metadata = array( "file" => str_replace( trailingslashit( $upload_dir[ 'basedir' ] ), '', get_attached_file( $attachment_id ) ) );
                    }

                    $file = wp_normalize_path( $metadata[ 'file' ] );
                    $image_host = ud_get_stateless_media()->get_gs_host();
                    $bucketLink = apply_filters('wp_stateless_bucket_link', $image_host);
                    $_cacheControl = \wpCloud\StatelessMedia\Utility::getCacheControl( $attachment_id, $metadata, null );
                    $_contentDisposition = \wpCloud\StatelessMedia\Utility::getContentDisposition( $attachment_id, $metadata, null );
                    $_metadata = array(
                        "width" => isset( $metadata[ 'width' ] ) ? $metadata[ 'width' ] : null,
                        "height" => isset( $metadata[ 'height' ] )  ? $metadata[ 'height' ] : null,
                        'object-id' => $attachment_id,
                        'source-id' => md5( $attachment_id . ud_get_stateless_media()->get( 'sm.bucket' ) ),
                        'file-hash' => md5( $metadata[ 'file' ] )
                    );

                    if(file_exists($fullsizepath)){
                        $file = apply_filters( 'wp_stateless_file_name', $file);

                        /* Add default image */
                        $media = $client->add_media( $_mediaOptions = array_filter( array(
                            'force' => true,
                            'name' => $file,
                            'absolutePath' => wp_normalize_path( get_attached_file( $attachment_id ) ),
                            'cacheControl' => $_cacheControl,
                            'contentDisposition' => $_contentDisposition,
                            'mimeType' => get_post_mime_type( $attachment_id ),
                            'metadata' => $_metadata
                        ) ));

                        // Stateless mode: we don't need the local version.
                        if(ud_get_stateless_media()->get( 'sm.mode' ) === 'stateless'){
                            unlink($fullsizepath);
                        }
                    }

                    /* Now we go through all available image sizes and upload them to Google Storage */
                    if( !empty( $metadata[ 'sizes' ] ) && is_array( $metadata[ 'sizes' ] ) ) {

                        $path = wp_normalize_path( dirname( get_attached_file( $attachment_id ) ) );
                        $mediaPath = apply_filters( 'wp_stateless_file_name', trim( dirname( $metadata[ 'file' ] ), '\/\\' ) );

                        foreach( (array) $metadata[ 'sizes' ] as $image_size => $data ) {

                            $absolutePath = wp_normalize_path( $path . '/' . $data[ 'file' ] );

                            if( !file_exists($absolutePath)){
                                continue;
                            }
                            
                            /* Add 'image size' image */
                            $media = $client->add_media( array(
                                'force' => true,
                                'name' => $file_path = trim($mediaPath . '/' . $data[ 'file' ], '/'),
                                'absolutePath' => $absolutePath,
                                'cacheControl' => $_cacheControl,
                                'contentDisposition' => $_contentDisposition,
                                'mimeType' => $data[ 'mime-type' ],
                                'metadata' => array_merge( $_metadata, array(
                                    'width' => $data['width'],
                                    'height' => $data['height'],
                                    'child-of' => $attachment_id,
                                    'file-hash' => md5( $data[ 'file' ] )
                                ))
                            ));

                            /* Break if we have errors. */
                            if( !is_wp_error( $media ) ) {
                                // Stateless mode: we don't need the local version.
                                if(ud_get_stateless_media()->get( 'sm.mode' ) === 'stateless'){
                                    unlink($absolutePath);
                                }
                            }

                        }

                    }

                }
            }
            // End add_media

            /**
             * modifying gs_name and absolutePath so that we can upload webp image using the same Utility::add_media function.
             */
            public function wp_stateless_add_media_args($args){
                if(!empty($args['is_webp']) && $args['is_webp']){
                    if(\file_exists($args['absolutePath'] . '.webp')){
                        $args['name'] = $args['name'] . '.webp';
                        $args['absolutePath'] = $args['absolutePath'] . '.webp';
                    }
                    else{
                        $pathinfo = pathinfo($args['absolutePath']);
                        $absolutePath = trailingslashit($pathinfo['dirname']) . $pathinfo['filename'] . '.webp';
                        if(file_exists($absolutePath)){
                            $args['name'] = $args['name'] . '.webp';
                            $args['absolutePath'] = $absolutePath;
                        }
                    }
                    $args['mimeType'] = 'image/webp';
                }
                return $args;
            }
            
            /**
             * Bypass server url check and return base url for GCS image.
             */
            public function shortpixel_webp_image_base($imageBase, $src){
                $gs_link = \ud_get_stateless_media()->convert_to_gs_link($src, true);
                if($gs_link){
                    $imageBase = trailingslashit(dirname($gs_link));
                }
                return $imageBase;
            }

            public function shortpixel_image_urls($URLs, $id){
                foreach ($URLs as $key => $url) {
                    $url_parts = wp_parse_url( $url );
                    if($url_parts['host'] == 'storage.googleapis.com'){
                        if(preg_match("@(^/?.*?/)(.*)@", $url_parts['path'], $matches)){
                            $bucket = trim($matches[1], '/');
                            $url_parts['path'] = $matches[2];
                            $url_parts['host'] = $bucket . '.' . $url_parts['host'];
                            $URLs[$key] = Utility::join_url($url_parts);
                        }
                    }
                }
                return $URLs;
            }

            /**
             * add_webp_mime
             * 
             */
            public function add_webp_mime($t, $user){
                $t['webp'] = 'image/webp';
                return $t;
            }

        }

    }

}

```
