PluginProbe
Imagify Image Optimization: Optimize Images | Compress & Convert to WebP/AVIF / 2.2.2
Imagify Image Optimization: Optimize Images | Compress & Convert to WebP/AVIF v2.2.2
2.3.4 2.3.3 2.3.2 2.3.1 2.3.0 2.2.9 2.2.8 trunk 1.10 1.3.3 1.3.4 1.3.5 1.3.5.1 1.3.5.2 1.3.6 1.3.6.1 1.4 1.4.1 1.4.2 1.4.3 1.4.4 1.4.5 1.4.6 1.4.7 1.5 All 103 releases
imagify / classes / Optimization / Process / WP.php

WP.php in Imagify Image Optimization: Optimize Images | Compress & Convert to WebP/AVIF 2.2.2, at classes/Optimization/Process/WP.php

256 lines 8.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 namespace Imagify\Optimization\Process;
3
4 use Imagify\Optimization\File;
5
6 defined( 'ABSPATH' ) || die( 'Cheatin’ uh?' );
7
8 /**
9 * Optimization class for the attachments in the WP library.
10 * This class constructor accepts:
11 * - A post ID (int).
12 * - A \WP_Post object.
13 * - A \Imagify\Media\MediaInterface object.
14 * - A \Imagify\Media\DataInterface object.
15 *
16 * @since 1.9
17 * @author Grégory Viguier
18 */
19 class WP extends AbstractProcess {
20
21 /** ----------------------------------------------------------------------------------------- */
22 /** MISSING THUMBNAILS ====================================================================== */
23 /** ----------------------------------------------------------------------------------------- */
24
25 /**
26 * Get the sizes for this media that have not get through optimization.
27 * No sizes are returned if the file is not optimized, has no backup, or is not an image.
28 * The 'full' size os never returned.
29 *
30 * @since 1.9
31 * @access public
32 * @author Grégory Viguier
33 *
34 * @return array|WP_Error {
35 * A WP_Error object on failure.
36 * An array of data for the thumbnail sizes on success.
37 * Size names are used as array keys.
38 *
39 * @type int $width The image width.
40 * @type int $height The image height.
41 * @type bool $crop True to crop, false to resize.
42 * @type string $name The size name.
43 * @type string $file The name the thumbnail "should" have.
44 * }
45 */
46 public function get_missing_sizes() {
47 // The media must have been optimized once and have a backup.
48 if ( ! $this->is_valid() ) {
49 return new \WP_Error( 'invalid_media', __( 'This media is not valid.', 'imagify' ) );
50 }
51
52 $media = $this->get_media();
53
54 if ( ! $media->is_supported() ) {
55 return new \WP_Error( 'media_not_supported', __( 'This media is not supported.', 'imagify' ) );
56 }
57
58 $data = $this->get_data();
59
60 if ( ! $data->is_optimized() ) {
61 return new \WP_Error( 'media_not_optimized', __( 'This media is not optimized yet.', 'imagify' ) );
62 }
63
64 if ( ! $media->has_backup() ) {
65 return new \WP_Error( 'no_backup', __( 'This file has no backup file.', 'imagify' ) );
66 }
67
68 if ( ! $media->is_image() ) {
69 return new \WP_Error( 'media_not_an_image', __( 'This media is not an image.', 'imagify' ) );
70 }
71
72 // Compare registered sizes and optimized sizes.
73 $context_sizes = $media->get_context_instance()->get_thumbnail_sizes();
74 $optimized_sizes = $data->get_optimization_data();
75 $missing_sizes = array_diff_key( $context_sizes, $optimized_sizes['sizes'] );
76
77 if ( ! $missing_sizes ) {
78 // We have everything we need.
79 return [];
80 }
81
82 $media_sizes = $media->get_media_files();
83 $full_size = $media_sizes['full'];
84
85 if ( ! $full_size['path'] || ! $full_size['width'] || ! $full_size['height'] ) {
86 return [];
87 }
88
89 $file_name = $this->filesystem->path_info( $full_size['path'] );
90 $file_name = $file_name['file_base'] . '-{%suffix%}.' . $file_name['extension'];
91
92 // Test if the missing sizes are needed.
93 foreach ( $missing_sizes as $size_name => $size_data ) {
94 if ( $full_size['width'] === $size_data['width'] && $full_size['height'] === $size_data['height'] ) {
95 // Same dimensions as the full size.
96 unset( $missing_sizes[ $size_name ] );
97 continue;
98 }
99
100 if ( ! empty( $media_sizes[ $size_name ]['disabled'] ) ) {
101 // This size must not be optimized.
102 unset( $missing_sizes[ $size_name ] );
103 continue;
104 }
105
106 $resize_result = image_resize_dimensions( $full_size['width'], $full_size['height'], $size_data['width'], $size_data['height'], $size_data['crop'] );
107
108 if ( ! $resize_result ) {
109 // This thumbnail is not needed, it is smaller than this size.
110 unset( $missing_sizes[ $size_name ] );
111 continue;
112 }
113
114 // Provide what should be the file name.
115 list( , , , , $new_width, $new_height ) = $resize_result;
116 $missing_sizes[ $size_name ]['file'] = str_replace( '{%suffix%}', "{$new_width}x{$new_height}", $file_name );
117 }
118
119 return $missing_sizes;
120 }
121
122 /**
123 * Optimize missing thumbnail sizes.
124 *
125 * @since 1.9
126 * @access public
127 * @author Grégory Viguier
128 *
129 * @return bool|WP_Error True if successfully launched. A \WP_Error instance on failure.
130 */
131 public function optimize_missing_thumbnails() {
132 if ( ! $this->is_valid() ) {
133 return new \WP_Error( 'invalid_media', __( 'This media is not valid.', 'imagify' ) );
134 }
135
136 if ( ! $this->get_media()->is_supported() ) {
137 return new \WP_Error( 'media_not_supported', __( 'This media is not supported.', 'imagify' ) );
138 }
139
140 $missing_sizes = $this->get_missing_sizes();
141
142 if ( ! $missing_sizes ) {
143 return new \WP_Error( 'no_sizes', __( 'No thumbnails seem to be missing.', 'imagify' ) );
144 }
145
146 if ( is_wp_error( $missing_sizes ) ) {
147 return $missing_sizes;
148 }
149
150 if ( $this->is_locked() ) {
151 return new \WP_Error( 'media_locked', __( 'This media is already being processed.', 'imagify' ) );
152 }
153
154 $this->lock();
155
156 // Create the missing thumbnails.
157 $sizes = $this->create_missing_thumbnails( $missing_sizes );
158
159 if ( ! $sizes ) {
160 $this->unlock();
161 return new \WP_Error( 'thumbnail_creation_failed', __( 'The thumbnails failed to be created.', 'imagify' ) );
162 }
163
164 $optimization_level = $this->get_data()->get_optimization_level();
165
166 if ( false === $optimization_level ) {
167 $this->unlock();
168 return new \WP_Error( 'optimization_level_not_set', __( 'The optimization level of this media seems to have disappear from the database. You should restore this media and then launch a new optimization.', 'imagify' ) );
169 }
170
171 $args = [
172 'hook_suffix' => 'optimize_missing_thumbnails',
173 'locked' => true,
174 ];
175
176 // Optimize.
177 return $this->optimize_sizes( array_keys( $sizes ), $optimization_level, $args );
178 }
179
180 /**
181 * Create all missing thumbnails if they don't exist and update the attachment metadata.
182 *
183 * @since 1.9
184 * @access protected
185 * @see $this->get_missing_sizes()
186 * @author Grégory Viguier
187 *
188 * @param array $missing_sizes array {
189 * An array of data for the thumbnail sizes on success.
190 * Size names are used as array keys.
191 *
192 * @type int $width The image width.
193 * @type int $height The image height.
194 * @type bool $crop True to crop, false to resize.
195 * @type string $name The size name.
196 * @type string $file The name the thumbnail "should" have.
197 * }
198 * @return array {
199 * An array of thumbnail data (those without errors):
200 *
201 * @type string $file File name.
202 * @type int $width The image width.
203 * @type int $height The image height.
204 * @type string $mime-type The mime type.
205 * }
206 */
207 protected function create_missing_thumbnails( $missing_sizes ) {
208 if ( ! $missing_sizes ) {
209 return [];
210 }
211
212 $media = $this->get_media();
213 $media_id = $media->get_id();
214 $metadata = wp_get_attachment_metadata( $media_id );
215 $metadata['sizes'] = ! empty( $metadata['sizes'] ) && is_array( $metadata['sizes'] ) ? $metadata['sizes'] : [];
216
217 $destination_dir = $this->filesystem->dir_path( $media->get_raw_fullsize_path() );
218 $backup_file = new File( $media->get_backup_path() );
219 $without_errors = [];
220 $has_new_data = false;
221
222 // Create the missing thumbnails.
223 foreach ( $missing_sizes as $size_name => $thumbnail_data ) {
224 // The path to the destination file.
225 $thumbnail_data['path'] = $destination_dir . $thumbnail_data['file'];
226
227 if ( ! $this->filesystem->exists( $thumbnail_data['path'] ) ) {
228 $result = $backup_file->create_thumbnail( $thumbnail_data );
229
230 if ( is_array( $result ) ) {
231 // New file.
232 $metadata['sizes'][ $size_name ] = $result;
233 $has_new_data = true;
234 }
235 } else {
236 $result = true;
237 }
238
239 if ( ! empty( $metadata['sizes'][ $size_name ] ) && ! is_wp_error( $result ) ) {
240 // Not an error.
241 $without_errors[ $size_name ] = $metadata['sizes'][ $size_name ];
242 }
243 }
244
245 // Save the new data into the attachment metadata.
246 if ( $has_new_data ) {
247 /**
248 * Here we don't use wp_update_attachment_metadata() to prevent triggering unwanted hooks.
249 */
250 update_post_meta( $media_id, '_wp_attachment_metadata', $metadata );
251 }
252
253 return $without_errors;
254 }
255 }
256