Handle webp errors. if ( is_wp_error( $webp_files ) ) { $ref_errors = $webp_files; } // Smush the image. $smush = $this->resize_from_meta_data( $attachment_id, $ref_meta ); // Handle compress errors. if ( is_wp_error( $smush ) ) { // Handle WP_Error. $ref_errors->merge_from( $smush ); } } } /** * Fires after optimizing a file. * * @param int $attachment_id Attachment ID. * @param array $ref_meta Metadata. * @param WP_Error The WP_Error object (passed by reference). * * @hooked Smush\Core\Integrations\S3::release_smush_mode() * @hooked Smush\Core\Integrations\S3::maybe_remove_sizes_from_s3_upload() */ do_action_ref_array( 'wp_smush_after_smush_file', array( $attachment_id, $ref_meta, &$ref_errors ) ); // Maybe update metadata after smushing image. $has_error = $has_error || $ref_errors && is_wp_error( $ref_errors ) && $ref_errors->has_errors(); // Update the metadata if there are no errors or converted PNG2JPG or resized image. if ( isset( $generating_metadata ) && ! $generating_metadata && ( ! $has_error || did_action( 'wp_smush_png_jpg_converted' ) || did_action( 'wp_smush_image_resized' ) ) ) { Helper::wp_update_attachment_metadata( $attachment_id, $ref_meta ); } // Log all errors. if ( $has_error ) { Helper::logger()->error( $ref_errors->errors ); } // Delete the transient after attachment meta is updated. delete_transient( 'smush-in-progress-' . $attachment_id ); // Reset prevent infinite loop. $this->prevent_infinite_loop = null; return $has_error ? $this->no_smushit( $attachment_id, $ref_errors ) : true; } /** * Read the image paths from an attachment's metadata and process each image with wp_smushit(). * * @param array $meta Attachment metadata. * @param int $id Attachment ID. * * @return mixed */ public function smush_image( $meta, $id ) { // We need to check if this call originated from Gutenberg and allow only media. if ( Helper::is_non_rest_media() ) { // If not - return image metadata. return $this->no_smushit( $id, null, $meta ); } $upload_attachment = filter_input( INPUT_POST, 'action', FILTER_SANITIZE_SPECIAL_CHARS ); $is_upload_attachment = 'upload-attachment' === $upload_attachment || isset( $_POST['post_id'] ); // Our async task runs when action is upload-attachment and post_id found. So do not run on these conditions. if ( $is_upload_attachment && defined( 'WP_SMUSH_ASYNC' ) && WP_SMUSH_ASYNC ) { return $meta; } /** * Smush image. * * @since 3.9.6 * * @param int $id Attachment ID. * @param array $meta Image metadata (passed by reference). * @param WP_Error $errors WP_Error (passed by reference). */ $this->smushit( $id, $meta, $errors ); return $meta; } /** * Smush single images * * @param int $attachment_id Attachment ID. * @param bool $return Return/echo the stats. * * @return array|string */ public function smush_single( $attachment_id, $return = false ) { /** * If the smushing option is already set, return the status. * * @since 3.9.6 * If it's not in ajax we are already handled it inside self::smushit(). */ if ( ! $return && $attachment_id > 0 && ( get_transient( 'smush-in-progress-' . $attachment_id ) || get_transient( 'wp-smush-restore-' . $attachment_id ) ) ) { // Get the button status. $status = WP_Smush::get_instance()->library()->generate_markup( $attachment_id ); wp_send_json_success( $status ); } // Get the image metadata from $_POST. $original_meta = ! empty( $_POST['metadata'] ) ? Helper::format_meta_from_post( $_POST['metadata'] ) : ''; /** * Smush image. * * @since 3.9.6 * * @param int $attachment_id Attachment ID. * @param array $original_meta Image metadata (passed by reference). * @param WP_Error $errors WP_Error (passed by reference). */ $this->smushit( $attachment_id, $original_meta, $errors ); // Send JSON response if we are not supposed to return the results. if ( $errors && is_wp_error( $errors ) && $errors->has_errors() ) { if ( $return ) { return array( 'error' => $errors->get_error_message() ); } // Prepare data for ajax. $error_code = $errors->get_error_code(); $error_data = $errors->get_error_data(); $status = array( 'error' => $error_code, 'error_msg' => '

' . Helper::filter_error( $errors->get_error_message( $error_code ), $attachment_id ) . '

', 'show_warning' => (int) $this->show_warning(), ); // Add error data (file_name) to status. if ( $error_data && is_array( $error_data ) ) { $status = array_merge( $error_data, $status ); } // Send data. wp_send_json_error( $status ); } // Get the button status. $status = WP_Smush::get_instance()->library()->generate_markup( $attachment_id ); $this->update_resmush_list( $attachment_id ); \Smush\Core\Core::add_to_smushed_list( $attachment_id ); if ( $return ) { return $status; } wp_send_json_success( $status ); } /** * If auto smush is set to true or not, default is true * * @return int|mixed */ public function is_auto_smush_enabled() { $auto_smush = $this->settings->get( 'auto' ); // Keep the auto smush on by default. if ( ! isset( $auto_smush ) ) { $auto_smush = 1; } return $auto_smush; } /** * Deletes all the backup files when an attachment is deleted * Update resmush List * Update Super Smush image count * * @param int $image_id Attachment ID. * * @return bool|void */ public function delete_images( $image_id ) { // Update the savings cache. WP_Smush::get_instance()->core()->get_savings( 'resize' ); // Update the savings cache. WP_Smush::get_instance()->core()->get_savings( 'pngjpg' ); // If no image id provided. if ( empty( $image_id ) ) { return false; } // Check and Update resmush list. $resmush_list = get_option( 'wp-smush-resmush-list' ); if ( $resmush_list ) { $this->update_resmush_list( $image_id, 'wp-smush-resmush-list' ); } /** Delete Backups */ // Check if we have any smush data for image. WP_Smush::get_instance()->core()->mod->backup->delete_backup_files( $image_id ); /** * Delete webp. * * Run WebP::delete_images always even when the module is deactivated. * * @since 3.8.0 */ WP_Smush::get_instance()->core()->mod->webp->delete_images( $image_id, false ); } /** * Calculate saving percentage for a given size stats * * @param object $stats Stats object. * * @return float|int */ private function calculate_percentage_from_stats( $stats ) { if ( empty( $stats ) || ! isset( $stats->size_before, $stats->size_after ) ) { return 0; } $savings = $stats->size_before - $stats->size_after; if ( $savings > 0 ) { $percentage = ( $savings / $stats->size_before ) * 100; $percentage = $percentage > 0 ? round( $percentage, 2 ) : $percentage; return $percentage; } return 0; } /** * Perform the resize operation for the image * * @param int $attachment_id Attachment ID. * @param array $meta Attachment meta. * * @return mixed */ public function resize_image( $attachment_id, $meta ) { if ( empty( $attachment_id ) || empty( $meta ) ) { return $meta; } return WP_Smush::get_instance()->core()->mod->resize->auto_resize( $attachment_id, $meta ); } /** * Send a smush request for the attachment * * @param int $id Attachment ID. */ public function wp_smush_handle_async( $id ) { // If we don't have image id or auto Smush is disabled, return. if ( empty( $id ) || ! $this->is_auto_smush_enabled() ) { return; } // Try to use smushit. $this->smush_single( $id, true ); } /** * Send a smush request for the attachment * * @param int $id Attachment ID. * @param array $post_data Post data. */ public function wp_smush_handle_editor_async( $id, $post_data ) { // If we don't have image id, or the smush is already in progress for the image, return. if ( empty( $id ) || get_transient( 'smush-in-progress-' . $id ) || get_transient( 'wp-smush-restore-' . $id ) ) { return; } // If auto Smush is disabled. if ( ! $this->is_auto_smush_enabled() ) { return; } /** * Filter: wp_smush_image * * Whether to smush the given attachment id or not * * @param bool $skip Whether to Smush image or not. * @param int $id Attachment ID of the image being processed. */ if ( ! apply_filters( 'wp_smush_image', true, $id ) ) { return; } // If filepath is not set or file doesn't exist. if ( ! isset( $post_data['filepath'] ) || ! file_exists( $post_data['filepath'] ) ) { return; } $res = $this->do_smushit( $post_data['filepath'] ); if ( is_wp_error( $res ) || empty( $res['success'] ) || ! $res['success'] ) { // Logged the error inside do_smushit. return; } // Update stats if it's the full size image. Return if it's not the full image size. if ( $post_data['filepath'] != get_attached_file( $post_data['postid'] ) ) { return; } // Get the existing Stats. $smush_stats = get_post_meta( $post_data['postid'], self::$smushed_meta_key, true ); $stats_full = ! empty( $smush_stats['sizes'] ) && ! empty( $smush_stats['sizes']['full'] ) ? $smush_stats['sizes']['full'] : ''; if ( empty( $stats_full ) ) { return; } // store the original image size. $stats_full->size_before = ( ! empty( $stats_full->size_before ) && $stats_full->size_before > $res['data']->before_size ) ? $stats_full->size_before : $res['data']->before_size; $stats_full->size_after = $res['data']->after_size; // Update compression percent and bytes saved for each size. $stats_full->bytes = $stats_full->size_before - $stats_full->size_after; $stats_full->percent = $this->calculate_percentage_from_stats( $stats_full ); $smush_stats['sizes']['full'] = $stats_full; // Update stats. update_post_meta( $post_data['postid'], self::$smushed_meta_key, $smush_stats ); } /** * Make sure we treat the scaled image as an attachment size, rather than the original uploaded image. * * @since 3.9.1 * * @param array $meta Attachment meta data. * @param int $attachment_id Attachment ID. * * @return array */ public function add_scaled_to_meta( $meta, $attachment_id ) { // If the image is not a scaled version - do nothing. if ( false === strpos( $meta['file'], '-scaled.' ) || ! isset( $meta['original_image'] ) || isset( $meta['sizes']['wp_scaled'] ) ) { return $meta; } $meta['sizes']['wp_scaled'] = array( 'file' => basename( $meta['file'] ), 'width' => $meta['width'], 'height' => $meta['height'], 'mime-type' => get_post_mime_type( $attachment_id ), ); return $meta; } }