get_thumbnail_path(); } /** * Get a thumbnail path. * * @since 1.6.6 * @author Grégory Viguier * * @param string $size_file The basename of the file. If not provided, the path to the main file is returned. * @return string|bool Path to the file if it exists or has been successfully retrieved from S3. False on failure. */ public function get_thumbnail_path( $size_file = false ) { if ( ! $this->is_valid() ) { return ''; } $file_path = get_attached_file( $this->id, true ); if ( $size_file ) { // It's not the full size. $file_path = $this->filesystem->dir_path( $file_path ) . $size_file; } return $file_path; } /** * Get the original attachment URL. * * @since 1.6.6 * @author Grégory Viguier * * @return string|bool The main file URL. False on failure. */ public function get_original_url() { return $this->get_thumbnail_url(); } /** * Get a thumbnail URL. * * @since 1.6.6 * @author Grégory Viguier * * @param string $size_file The basename of the file. If not provided, the main file's URL is returned. * @return string|bool The file URL. False on failure. */ public function get_thumbnail_url( $size_file = false ) { if ( ! $this->is_extension_supported() ) { return false; } $file_url = wp_get_attachment_url( $this->id ); if ( $size_file ) { // It's not the full size. $file_url = $this->filesystem->dir_path( $file_url ) . $size_file; } return $file_url; } /** ----------------------------------------------------------------------------------------- */ /** THE PUBLIC STUFF ======================================================================== */ /** ----------------------------------------------------------------------------------------- */ /** * Optimize all sizes with Imagify. * * @since 1.6.6 * @author Grégory Viguier * * @param int $optimization_level The optimization level (2 = ultra, 1 = aggressive, 0 = normal). * @param array $metadata The attachment meta data, containing the sizes. Provide only for a new attachment. * @return array|bool The optimization data. False on failure. */ public function optimize( $optimization_level = null, $metadata = array() ) { $metadata_changed = false; /** * Make some sanity tests first. */ // Check if the attachment extension is allowed. if ( ! $this->is_extension_supported() ) { return false; } // To avoid issue with "original_size" at 0 in "_imagify_data". if ( 0 === (int) $this->get_stats_data( 'original_size' ) ) { $this->delete_imagify_data(); } $optimization_level = isset( $optimization_level ) ? (int) $optimization_level : get_imagify_option( 'optimization_level' ); // Check if the full size is already optimized with this level. if ( $this->is_optimized() && $this->get_optimization_level() === $optimization_level ) { return false; } // Get file path of the full size. $attachment_path = $this->get_original_path(); $attachment_url = $this->get_original_url(); if ( ! $attachment_path ) { // We're in deep sh**. return false; } if ( ! $this->filesystem->exists( $attachment_path ) && ! $this->get_file_from_s3( $attachment_path ) ) { // The file doesn't exist and couldn't be retrieved from S3. return false; } /** * Start the process. */ $this->set_running_status(); /** This hook is documented in /inc/classes/class-imagify-attachment.php. */ do_action( 'before_imagify_optimize_attachment', $this->id ); $metadata = $this->set_deletion_status( $metadata ); // Store the paths of the files that may be deleted once optimized and sent to S3. $to_delete = array(); $filesize_total = 0; // Maybe resize (and backup) the image. $resized = $this->is_image() && $this->maybe_resize( $attachment_path ); if ( $resized ) { $size = $this->filesystem->get_image_size( $attachment_path ); if ( $size ) { $metadata['width'] = $size['width']; $metadata['height'] = $size['height']; $metadata_changed = true; } } // Optimize the full size. $response = do_imagify( $attachment_path, array( 'optimization_level' => $optimization_level, 'context' => 'wp', 'resized' => $resized, 'original_size' => $this->get_original_size( false ), ) ); $data = $this->fill_data( null, $response ); if ( $this->delete_files ) { $to_delete[] = $attachment_path; // This is used by AS3CF. $bytes = $this->filesystem->size( $attachment_path ); if ( false !== $bytes ) { $metadata_changed = true; $filesize_total += $bytes; $metadata['filesize'] = $bytes; } else { $metadata['filesize'] = 0; } } /** This filter is documented in /inc/classes/class-imagify-attachment.php. */ $data = apply_filters( 'imagify_fill_full_size_data', $data, $response, $this->id, $attachment_path, $attachment_url, 'full', $optimization_level, $metadata ); // Save the optimization level. update_post_meta( $this->id, '_imagify_optimization_level', $optimization_level ); if ( ! $data ) { // The optimization failed. $metadata = $metadata_changed ? $metadata : false; $this->cleanup( $metadata, $to_delete ); return false; } // Optimize all thumbnails. if ( ! empty( $metadata['sizes'] ) ) { $disallowed_sizes = get_imagify_option( 'disallowed-sizes' ); $is_active_for_network = imagify_is_active_for_network(); foreach ( $metadata['sizes'] as $size_key => $size_data ) { $thumbnail_path = $this->get_thumbnail_path( $size_data['file'] ); $thumbnail_url = $this->get_thumbnail_url( $size_data['file'] ); if ( $this->delete_files ) { $to_delete[] = $thumbnail_path; // Even if this size must not be optimized ($disallowed_sizes), we must fetch the file from S3 to get its size, and not to trigger a `WP_Error` in `upload_attachment_to_s3()`. if ( ! $this->filesystem->exists( $thumbnail_path ) && ! $this->get_file_from_s3( $thumbnail_path ) ) { // Doesn't exist and couldn't be retrieved from S3. $data['sizes'][ $size_key ] = array( 'success' => false, 'error' => __( 'This size could not be retrieved from Amazon S3.', 'imagify' ), ); continue; } // This is used by AS3CF. $bytes = $this->filesystem->size( $thumbnail_path ); if ( false !== $bytes ) { $filesize_total += $bytes; } } // Check if this size has to be optimized. if ( ! $is_active_for_network && isset( $disallowed_sizes[ $size_key ] ) && $this->is_image() ) { $data['sizes'][ $size_key ] = array( 'success' => false, 'error' => __( 'This size is not authorized to be optimized. Update your Imagify settings if you want to optimize it.', 'imagify' ), ); /** This filter is documented in /inc/classes/class-imagify-attachment.php. */ $data = apply_filters( 'imagify_fill_unauthorized_thumbnail_data', $data, $this->id, $thumbnail_path, $thumbnail_url, $size_key, $optimization_level, $metadata ); continue; } if ( ! $this->delete_files && ! $this->filesystem->exists( $thumbnail_path ) && ! $this->get_file_from_s3( $thumbnail_path ) ) { // Doesn't exist and couldn't be retrieved from S3. $data['sizes'][ $size_key ] = array( 'success' => false, 'error' => __( 'This size could not be retrieved from Amazon S3.', 'imagify' ), ); continue; } if ( ! $this->is_image() ) { continue; } // Optimize the thumbnail size. $response = do_imagify( $thumbnail_path, array( 'backup' => false, 'optimization_level' => $optimization_level, 'context' => 'wp', ) ); $data = $this->fill_data( $data, $response, $size_key ); /** This filter is documented in /inc/classes/class-imagify-attachment.php. */ $data = apply_filters( 'imagify_fill_thumbnail_data', $data, $response, $this->id, $thumbnail_path, $thumbnail_url, $size_key, $optimization_level, $metadata ); } // End foreach(). } // End if(). $data['stats']['percent'] = round( ( ( $data['stats']['original_size'] - $data['stats']['optimized_size'] ) / $data['stats']['original_size'] ) * 100, 2 ); update_post_meta( $this->id, '_imagify_data', $data ); update_post_meta( $this->id, '_imagify_status', 'success' ); if ( $this->delete_files && $filesize_total ) { // Add the total file size for all image sizes. This is a meta used by AS3CF. update_post_meta( $this->id, 'wpos3_filesize_total', $filesize_total ); } $optimized_data = $this->get_data(); /** This hook is documented in /inc/classes/class-imagify-attachment.php. */ do_action( 'after_imagify_optimize_attachment', $this->id, $optimized_data ); $sent = $this->maybe_send_attachment_to_s3( $metadata, $attachment_path ); // Update metadata only if they changed. $metadata = $metadata_changed ? $metadata : false; // Delete files only if they have been uploaded to S3. $to_delete = $sent ? $to_delete : array(); $this->cleanup( $metadata, $to_delete ); return $optimized_data; } /** * Optimize missing thumbnail sizes with Imagify. * * @since 1.6.10 * @access public * @author Grégory Viguier * * @param int $optimization_level The optimization level (2=ultra, 1=aggressive, 0=normal). * @return array|object An array of thumbnail data, size by size. A WP_Error object on failure. */ public function optimize_missing_thumbnails( $optimization_level = null ) { // Check if the attachment extension is allowed. if ( ! $this->is_extension_supported() || ! $this->is_image() ) { return new WP_Error( 'mime_type_not_supported', __( 'This type of file is not supported.', 'imagify' ) ); } /** * Create missing thumbnails and optimize them. */ $result = parent::optimize_missing_thumbnails( $optimization_level ); $result_sizes = array(); $this->set_running_status(); if ( is_array( $result ) ) { // All good. $result_sizes = $result; } elseif ( is_wp_error( $result ) ) { // Some thumbnails could not be created. Lets see if some were. $result_sizes = $result->get_error_data( 'image_resize_error' ); $result_sizes = ! empty( $result_sizes['sizes_succeeded'] ) ? $result_sizes['sizes_succeeded'] : array(); } if ( ! $result_sizes ) { // No thumbnails created. $this->delete_running_status(); return $result; } /** * Fetch all images from S3 if they're not on the server. * S3 Offload needs ALL images (so it can update its metas), we can't just send some of them without entering Hell -_-'. */ $metadata = $this->set_deletion_status(); if ( ! $this->can_send_to_s3() ) { // The other thumbnails are not on S3, so we don't need to send the new ones. $this->delete_running_status(); return $result; } /** * The main file. */ $attachment_path = $this->get_original_path(); $to_delete = array(); $to_skip = array(); $filesize_total = 0; $metadata_changed = false; if ( ! $attachment_path ) { // WAT?! if ( ! is_wp_error( $result ) ) { $result = new WP_Error( 'no_attachment_path', __( 'Files could not be sent to Amazon S3.', 'imagify' ), array( 'sizes_succeeded' => $result_sizes, ) ); } else { $result->add( 'no_attachment_path', __( 'Files could not be sent to Amazon S3.', 'imagify' ) ); } $this->delete_running_status(); return $result; } if ( ! $this->filesystem->exists( $attachment_path ) && ! $this->get_file_from_s3( $attachment_path ) ) { // The file doesn't exist and couldn't be retrieved from S3. if ( ! is_wp_error( $result ) ) { $result = new WP_Error( 'main_file_not_on_s3', __( 'The main image could not be retrieved from Amazon S3.', 'imagify' ), array( 'sizes_succeeded' => $result_sizes, ) ); } else { $result->add( 'main_file_not_on_s3', __( 'The main image could not be retrieved from Amazon S3.', 'imagify' ) ); } $this->delete_running_status(); return $result; } // Files that must not be retrieved from S3. foreach ( $result_sizes as $size_key => $size_data ) { $to_skip[] = $this->get_thumbnail_path( $size_data['file'] ); } // Store the paths of the files that may be deleted once sent to S3. if ( $this->delete_files ) { $to_delete[] = $attachment_path; $to_delete = array_merge( $to_delete, $to_skip ); // This is used by AS3CF. $bytes = $this->filesystem->size( $attachment_path ); if ( false !== $bytes ) { $metadata_changed = true; $filesize_total += $bytes; $metadata['filesize'] = $bytes; } elseif ( ! isset( $metadata['filesize'] ) ) { $metadata_changed = true; $metadata['filesize'] = 0; } } /** * The thumbnails. */ if ( ! empty( $metadata['sizes'] ) ) { $to_skip = array_flip( $to_skip ); foreach ( $metadata['sizes'] as $size_key => $size_data ) { $thumbnail_path = $this->get_thumbnail_path( $size_data['file'] ); if ( isset( $to_skip[ $thumbnail_path ] ) ) { continue; } if ( ! $this->filesystem->exists( $thumbnail_path ) && ! $this->get_file_from_s3( $thumbnail_path ) ) { // The file doesn't exist and couldn't be retrieved from S3. if ( ! is_wp_error( $result ) ) { $result = new WP_Error( 'thumbnail_not_on_s3', __( 'This size could not be retrieved from Amazon S3.', 'imagify' ), array( 'sizes_succeeded' => $result_sizes, 'size' => $size_key, ) ); } else { $result->add( 'thumbnail_not_on_s3', __( 'This size could not be retrieved from Amazon S3.', 'imagify' ), array( 'size' => $size_key, ) ); } $this->delete_running_status(); return $result; } if ( $this->delete_files ) { $to_delete[] = $thumbnail_path; // This is used by AS3CF. $bytes = $this->filesystem->size( $thumbnail_path ); if ( false !== $bytes ) { $filesize_total += $bytes; } } } // End foreach(). } // End if(). if ( $this->delete_files && $filesize_total ) { // Add the total file size for all image sizes. This is a meta used by AS3CF. update_post_meta( $this->id, 'wpos3_filesize_total', $filesize_total ); } $sent = $this->maybe_send_attachment_to_s3( $metadata, $attachment_path ); // Update metadata only if they changed. $metadata = $metadata_changed ? $metadata : false; // Delete files only if they have been uploaded to S3. $to_delete = $sent ? $to_delete : array(); $this->cleanup( $metadata, $to_delete ); return $result; } /** * Re-optimize the given thumbnail sizes to the same level. * Not supported yet in this context. * * @since 1.7.1 * @access public * @author Grégory Viguier * * @param array $sizes The sizes to optimize. * @return array|void A WP_Error object on failure. */ public function reoptimize_thumbnails( $sizes ) {} /** * Process an attachment restoration from the backup file. * * @since 1.6.6 * @author Grégory Viguier * * @return array A list of files sent to S3. */ public function restore() { // Check if the attachment extension is allowed. if ( ! $this->is_extension_supported() ) { return false; } // Stop the process if there is no backup file to restore. if ( ! $this->has_backup() ) { return false; } /** This hook is documented in /inc/classes/class-imagify-attachment.php. */ do_action( 'before_imagify_restore_attachment', $this->id ); $backup_path = $this->get_backup_path(); $attachment_path = $this->get_original_path(); if ( ! $attachment_path ) { return false; } // Create the original image from the backup. $this->filesystem->copy( $backup_path, $attachment_path, true ); $this->filesystem->chmod_file( $attachment_path ); if ( ! $this->filesystem->exists( $attachment_path ) ) { return false; } $this->set_deletion_status(); // Remove old optimization data. $this->delete_imagify_data(); if ( ! $this->is_image() ) { // We need to delete the thumbnails for pdf, or new ones will be generated with new unique file names. $metadata = wp_get_attachment_metadata( $this->id ); if ( ! empty( $metadata['sizes'] ) && is_array( $metadata['sizes'] ) ) { foreach ( $metadata['sizes'] as $size_key => $size_data ) { $thumbnail_path = $this->get_thumbnail_path( $size_data['file'] ); if ( $this->filesystem->exists( $thumbnail_path ) ) { $this->filesystem->delete( $thumbnail_path ); } } } } if ( ! function_exists( 'wp_generate_attachment_metadata' ) ) { require_once ABSPATH . 'wp-admin/includes/image.php'; } // Generate new thumbnails and new metadata. $metadata = wp_generate_attachment_metadata( $this->id, $attachment_path ); // Send to S3. $sent = $this->maybe_send_attachment_to_s3( $metadata, $attachment_path ); // Files restored (and maybe to delete). $files = array(); // If the files must be deleted, we need to store the file sizes. $filesize_total = 0; if ( $sent ) { $files[] = $attachment_path; } if ( $this->delete_files ) { // This is used by AS3CF. $bytes = $this->filesystem->size( $attachment_path ); if ( false !== $bytes ) { $filesize_total += $bytes; $metadata['filesize'] = $bytes; } else { $metadata['filesize'] = 0; } } if ( ! empty( $metadata['sizes'] ) && ( $sent || $this->delete_files ) ) { foreach ( $metadata['sizes'] as $size_key => $size_data ) { $thumbnail_path = $this->get_thumbnail_path( $size_data['file'] ); if ( $sent ) { $files[] = $thumbnail_path; } if ( $this->delete_files ) { // This is used by AS3CF. $bytes = $this->filesystem->size( $thumbnail_path ); if ( false !== $bytes ) { $filesize_total += $bytes; } } } } if ( $this->delete_files && $filesize_total ) { // Add the total file size for all image sizes. This is a meta used by AS3CF. update_post_meta( $this->id, 'wpos3_filesize_total', $filesize_total ); } /** This hook is documented in /inc/classes/class-imagify-attachment.php. */ do_action( 'after_imagify_restore_attachment', $this->id ); $to_delete = $this->delete_files ? $files : array(); $this->cleanup( $metadata, $to_delete ); return $files; } /** ----------------------------------------------------------------------------------------- */ /** INTERNAL UTILITIES ====================================================================== */ /** ----------------------------------------------------------------------------------------- */ /** * Cleanup after optimization or a restore: * - Maybe update metadata. * - Maybe delete local files. * - Delete the "optimization status" transient. * * @since 1.6.6 * @author Grégory Viguier * * @param array $new_metadata New attachment metadata to be stored. * @param array $files_to_remove Files to delete. */ protected function cleanup( $new_metadata, $files_to_remove ) { if ( $new_metadata ) { /** * Filter the metadata stored after optimization or a restore. * * @since 1.6.6 * @author Grégory Viguier * * @param array $new_metadata New attachment metadata to be stored. * @param int $id The attachment ID. */ $new_metadata = apply_filters( 'imagify_as3cf_attachment_cleanup_metadata', $new_metadata, $this->id ); /** * Update the attachment meta that contains the file sizes. * Here we don't use wp_update_attachment_metadata() to prevent triggering unwanted hooks. */ update_post_meta( $this->id, '_wp_attachment_metadata', $new_metadata ); } if ( $files_to_remove ) { $attachment_path = $this->get_original_path(); /** This filter is documented in /amazon-s3-and-cloudfront/classes/amazon-s3-and-cloudfront.php. */ $files_to_remove = (array) apply_filters( 'as3cf_upload_attachment_local_files_to_remove', $files_to_remove, $this->id, $attachment_path ); $files_to_remove = array_filter( $files_to_remove ); if ( $files_to_remove ) { $files_to_remove = array_unique( $files_to_remove ); /** * Delete the local files. */ array_map( array( $this, 'maybe_delete_file' ), $files_to_remove ); } } /** * Delete the "optimization status" transient. */ $this->delete_running_status(); } /** * Maybe resize (and backup) an image. * * @since 1.6.6 * @author Grégory Viguier * * @param string $attachment_path The file path. * @return bool True on success. False on failure. */ protected function maybe_resize( $attachment_path ) { if ( ! $this->is_image() ) { return false; } $do_resize = get_imagify_option( 'resize_larger' ); $resize_width = get_imagify_option( 'resize_larger_w' ); $attachment_size = $this->filesystem->get_image_size( $attachment_path ); if ( ! $do_resize || ! $attachment_size || $resize_width >= $attachment_size['width'] ) { return false; } $resized_attachment_path = $this->resize( $attachment_path, $attachment_size, $resize_width ); if ( is_wp_error( $resized_attachment_path ) ) { return false; } $backuped = imagify_backup_file( $attachment_path ); if ( is_wp_error( $backuped ) ) { return false; } return $this->filesystem->move( $resized_attachment_path, $attachment_path, true ); } /** * Tell if the files must be deleted after being optimized or restored. * It sets the 2 properties $this->use_s3_settings and $this->delete_files. * * @since 1.6.6 * @author Grégory Viguier * * @param array $metadata Attachment metadata. Provide, only if it comes from a 'wp_generate_attachment_metadata' or 'wp_update_attachment_metadata' hook. * @return array Attachment metadata. If not provided as argument, new values are fetched. */ protected function set_deletion_status( $metadata = false ) { global $as3cf; if ( $metadata ) { /** * Metadata is provided: we were in a 'wp_generate_attachment_metadata' or 'wp_update_attachment_metadata' hook. * This means we'll follow AS3CF settings to know if the local files must be sent to S3 and/or deleted. */ $this->use_s3_settings = true; $this->delete_files = $as3cf && $as3cf->get_setting( 'remove-local-file' ) && $this->can_send_to_s3(); return $metadata; } /** * Metadata is not provided: we were not in a 'wp_generate_attachment_metadata' or 'wp_update_attachment_metadata' hook. * So, we fetch the current meta value. * This also means we won't follow AS3CF settings to know if the local files must be sent to S3 and/or deleted. * In that case we'll send the files to S3 if they already are there, and delete them if they is a 'filesize' entry in the metadata. */ $metadata = wp_get_attachment_metadata( $this->id, true ); $this->use_s3_settings = false; $this->delete_files = isset( $metadata['filesize'] ) && $this->can_send_to_s3(); return $metadata; } /** ----------------------------------------------------------------------------------------- */ /** S3 UTILITIES ============================================================================ */ /** ----------------------------------------------------------------------------------------- */ /** * Tell if AS3CF is set up. * * @since 1.6.6 * @author Grégory Viguier * * @return bool */ public function is_s3_setup() { global $as3cf; static $is; if ( ! isset( $is ) ) { $is = $as3cf && $as3cf->is_plugin_setup(); } return $is; } /** * Tell if an attachment is stored on S3. * * @since 1.6.6 * @author Grégory Viguier * * @return array|bool The S3 info on success. False if the attachment is not on S3. */ public function get_s3_info() { global $as3cf; if ( ! $as3cf ) { return false; } if ( method_exists( $as3cf, 'get_attachment_s3_info' ) ) { return $as3cf->get_attachment_s3_info( $this->id ); } return $as3cf->get_attachment_provider_info( $this->id ); } /** * Get a file from S3. * * @since 1.6.6 * @author Grégory Viguier * * @param string $file_path The file path. * @return string|bool The file path on success, false on failure. */ protected function get_file_from_s3( $file_path ) { global $as3cf; if ( ! $this->is_extension_supported() ) { return false; } if ( ! $this->is_s3_setup() ) { return false; } $s3_object = $this->get_s3_info(); if ( ! $s3_object ) { // The attachment is not on S3. return false; } $directory = $this->filesystem->dir_path( $s3_object['key'] ); $directory = $this->filesystem->is_root( $directory ) ? '' : $directory; $s3_object['key'] = $directory . $this->filesystem->file_name( $file_path ); // Retrieve file from S3. if ( method_exists( $as3cf->plugin_compat, 'copy_s3_file_to_server' ) ) { $as3cf->plugin_compat->copy_s3_file_to_server( $s3_object, $file_path ); } else { $as3cf->plugin_compat->copy_provider_file_to_server( $s3_object, $file_path ); } return $this->filesystem->exists( $file_path ) ? $file_path : false; } /** * Maybe send the attachment to S3. * * @since 1.6.6 * @author Grégory Viguier * * @param array $metadata The attachment metadata. * @param string $attachment_path The attachment path. * @param bool $remove_local_files True to let AS3CF delete the local files (if set in the settings). We usually don't want that, we do it by ourselves. * @return bool True on success. False otherwize. */ protected function maybe_send_attachment_to_s3( $metadata = null, $attachment_path = null, $remove_local_files = false ) { global $as3cf; if ( ! $this->can_send_to_s3() ) { return false; } $s3_object = $this->get_s3_info(); if ( ! $s3_object ) { return false; } $full_file_path = $this->get_original_path(); if ( ! $full_file_path ) { // This is bad. return false; } if ( method_exists( $as3cf, 'upload_attachment_to_s3' ) ) { $s3_data = $as3cf->upload_attachment_to_s3( $this->id, $metadata, $attachment_path, false, $remove_local_files ); } else { $s3_data = $as3cf->upload_attachment( $this->id, $metadata, $attachment_path, false, $remove_local_files ); } return ! is_wp_error( $s3_data ); } /** * Tell if an attachment can be sent to S3. * * @since 1.6.6 * @author Grégory Viguier * * @return bool */ protected function can_send_to_s3() { global $as3cf; static $can = array(); static $copy_to_s3; if ( isset( $can[ $this->id ] ) ) { return $can[ $this->id ]; } if ( ! isset( $copy_to_s3 ) ) { $copy_to_s3 = $as3cf && $as3cf->get_setting( 'copy-to-s3' ); } $is_s3_setup = $this->is_s3_setup(); $s3_object = $this->get_s3_info(); // S3 is set up and the attachment is on S3. $can[ $this->id ] = $is_s3_setup && $s3_object; if ( $can[ $this->id ] && ! empty( $this->use_s3_settings ) ) { // Use AS3CF setting to tell if we're allowed to send the files. $can[ $this->id ] = $copy_to_s3; } /** * Filter the result of Imagify_AS3CF_Attachment::can_send_to_s3(). * * @since 1.6.6 * @author Grégory Viguier * * @param bool $can True if the attachment can be sent. False otherwize. * @param int $id The attachment ID. * @param array $s3_object The S3 infos. * @param bool $is_s3_setup AS3CF is set up or not. * @param bool $copy_to_s3 AS3CF setting that tells if a "new" attachment can be sent. * @param bool $use_s3_settings Tell if we must use AS3CF setting in this case. */ $can[ $this->id ] = (bool) apply_filters( 'imagify_can_send_to_s3', $can[ $this->id ], $this->id, $s3_object, $is_s3_setup, $copy_to_s3, $this->use_s3_settings ); return $can[ $this->id ]; } /** * Maybe delete the local file. * * @since 1.6.6 * @author Grégory Viguier * * @param string $file_path The file path. * @return bool True if deleted or doesn't exist. False on failure or if the file is not supposed to be deleted. */ protected function maybe_delete_file( $file_path ) { if ( ! $this->file_should_be_deleted( $file_path ) ) { return false; } if ( ! $this->filesystem->exists( $file_path ) ) { return true; } return $this->filesystem->delete( $file_path, false, 'f' ); } /** * Tell if a file should be deleted. * * @since 1.6.6 * @author Grégory Viguier * * @param string $file_path The file path. * @return bool True to delete, false to keep. */ protected function file_should_be_deleted( $file_path ) { if ( ! $file_path || ! $this->delete_files ) { // We keep the file. return false; } /** This hook is documented in /amazon-s3-and-cloudfront/classes/amazon-s3-and-cloudfront.php. */ $preserve = apply_filters( 'as3cf_preserve_file_from_local_removal', false, $file_path ); return false === $preserve; } }