PluginProbe
Imagify Image Optimization: Optimize Images | Compress & Convert to WebP/AVIF / 2.3.0
Imagify Image Optimization: Optimize Images | Compress & Convert to WebP/AVIF v2.3.0
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 / Data / CustomFolders.php

CustomFolders.php in Imagify Image Optimization: Optimize Images | Compress & Convert to WebP/AVIF 2.3.0, at classes/Optimization/Data/CustomFolders.php

327 lines 8.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 namespace Imagify\Optimization\Data;
3
4 use Imagify\Traits\MediaRowTrait;
5
6 /**
7 * Optimization data class for the custom folders.
8 * This class constructor accepts:
9 * - A media ID (int).
10 * - An array of data coming from the files DB table /!\
11 * - An object of data coming from the files DB table /!\
12 * - A \Imagify\Media\MediaInterface object.
13 *
14 * @since 1.9
15 * @see Imagify\Media\CustomFolders
16 * @author Grégory Viguier
17 */
18 class CustomFolders extends AbstractData {
19 use MediaRowTrait;
20
21 /**
22 * The attachment SQL DB class.
23 *
24 * @var string
25 * @since 1.9
26 * @access protected
27 * @author Grégory Viguier
28 */
29 protected $db_class_name = 'Imagify_Files_DB';
30
31 /**
32 * The constructor.
33 *
34 * @since 1.9
35 * @access public
36 * @author Grégory Viguier
37 *
38 * @param mixed $id An ID, or whatever type the "Media" class constructor accepts.
39 */
40 public function __construct( $id ) {
41 parent::__construct( $id );
42
43 if ( ! $this->is_valid() ) {
44 return;
45 }
46
47 $media = $this->get_media();
48
49 if ( ! $media ) {
50 return;
51 }
52
53 // This is required by MediaRowTrait.
54 $this->id = $media->get_id();
55
56 // In this context, the media data and the optimization data are stored in the same DB table, so, no need to request twice the DB.
57 $this->row = $media->get_row(); // @phpstan-ignore-line
58 }
59
60 /**
61 * Get the whole media optimization data.
62 *
63 * @since 1.9
64 * @access public
65 * @author Grégory Viguier
66 *
67 * @return array The data. See parent method for details.
68 */
69 public function get_optimization_data() {
70 if ( ! $this->is_valid() ) {
71 return $this->default_optimization_data;
72 }
73
74 $row = array_merge( $this->get_row_db_instance()->get_column_defaults(), $this->get_row() );
75 $data = $this->default_optimization_data;
76
77 $data['status'] = $row['status'];
78 $data['level'] = $row['optimization_level'];
79 $data['level'] = is_numeric( $data['level'] ) ? (int) $data['level'] : false;
80
81 if ( 'success' === $row['status'] ) {
82 /**
83 * Success.
84 */
85 $data['sizes']['full'] = [
86 'success' => true,
87 'original_size' => $row['original_size'],
88 'optimized_size' => $row['optimized_size'],
89 'percent' => $row['percent'],
90 ];
91 } elseif ( ! empty( $row['status'] ) ) {
92 /**
93 * Error.
94 */
95 $data['sizes']['full'] = [
96 'success' => false,
97 'error' => $row['error'],
98 ];
99 }
100
101 if ( ! empty( $row['data']['sizes'] ) && is_array( $row['data']['sizes'] ) ) {
102 unset( $row['data']['sizes']['full'] );
103 $data['sizes'] = array_merge( $data['sizes'], $row['data']['sizes'] );
104 $data['sizes'] = array_filter( $data['sizes'], 'is_array' );
105 }
106
107 if ( empty( $data['sizes'] ) ) {
108 return $data;
109 }
110
111 foreach ( $data['sizes'] as $size_data ) {
112 // Cast.
113 if ( isset( $size_data['original_size'] ) ) {
114 $size_data['original_size'] = (int) $size_data['original_size'];
115 }
116 if ( isset( $size_data['optimized_size'] ) ) {
117 $size_data['optimized_size'] = (int) $size_data['optimized_size'];
118 }
119 if ( isset( $size_data['percent'] ) ) {
120 $size_data['percent'] = round( $size_data['percent'], 2 );
121 }
122 // Stats.
123 if ( ! empty( $size_data['original_size'] ) && ! empty( $size_data['optimized_size'] ) ) {
124 $data['stats']['original_size'] += $size_data['original_size'];
125 $data['stats']['optimized_size'] += $size_data['optimized_size'];
126 }
127 }
128
129 if ( $data['stats']['original_size'] && $data['stats']['optimized_size'] ) {
130 $data['stats']['percent'] = $data['stats']['original_size'] - $data['stats']['optimized_size'];
131 $data['stats']['percent'] = round( $data['stats']['percent'] / $data['stats']['original_size'] * 100, 2 );
132 }
133
134 return $data;
135 }
136
137 /**
138 * Update the optimization data, level, and status for a size.
139 *
140 * @since 1.9
141 * @access public
142 * @author Grégory Viguier
143 *
144 * @param string $size The size name.
145 * @param array $data The optimization data. See parent method for details.
146 */
147 public function update_size_optimization_data( $size, array $data ) {
148 if ( ! $this->is_valid() ) {
149 return;
150 }
151
152 $old_data = array_merge( $this->get_reset_data(), $this->get_row() );
153
154 if ( 'full' === $size ) {
155 /**
156 * Original file.
157 */
158 $old_data['optimization_level'] = $data['level'];
159 $old_data['status'] = $data['status'];
160 $old_data['modified'] = 0;
161
162 $file_path = $this->get_media()->get_fullsize_path();
163
164 if ( $file_path ) {
165 $old_data['hash'] = md5_file( $file_path );
166 }
167
168 if ( key_exists( 'message', $data ) ) {
169 $old_data['message'] = $data['message'];
170 }
171
172 if ( ! $data['success'] ) {
173 /**
174 * Error.
175 */
176 $old_data['error'] = $data['error'];
177 } else {
178 /**
179 * Success.
180 */
181 $old_data['original_size'] = $data['original_size'];
182 $old_data['optimized_size'] = $data['optimized_size'];
183 $old_data['percent'] = $data['original_size'] - $data['optimized_size'];
184 $old_data['percent'] = round( ( $old_data['percent'] / $data['original_size'] ) * 100, 2 );
185 }
186 } else {
187 /**
188 * WebP version or any other size.
189 */
190 $old_data['data'] = ! empty( $old_data['data'] ) && is_array( $old_data['data'] ) ? $old_data['data'] : [];
191 $old_data['data']['sizes'] = ! empty( $old_data['data']['sizes'] ) && is_array( $old_data['data']['sizes'] ) ? $old_data['data']['sizes'] : [];
192
193 if ( ! $data['success'] ) {
194 /**
195 * Error.
196 */
197 $old_data['data']['sizes'][ $size ] = [
198 'success' => false,
199 'error' => $data['error'],
200 ];
201 } else {
202 /**
203 * Success.
204 */
205 $old_data['data']['sizes'][ $size ] = [
206 'success' => true,
207 'original_size' => $data['original_size'],
208 'optimized_size' => $data['optimized_size'],
209 'percent' => round( ( ( $data['original_size'] - $data['optimized_size'] ) / $data['original_size'] ) * 100, 2 ),
210 ];
211 }
212 }
213
214 if ( isset( $old_data['data']['sizes'] ) && ( ! $old_data['data']['sizes'] || ! is_array( $old_data['data']['sizes'] ) ) ) {
215 unset( $old_data['data']['sizes'] );
216 }
217
218 $this->update_row( $old_data );
219 }
220
221 /**
222 * Delete the media optimization data, level, and status.
223 *
224 * @since 1.9
225 * @access public
226 * @author Grégory Viguier
227 */
228 public function delete_optimization_data() {
229 if ( ! $this->is_valid() ) {
230 return;
231 }
232
233 $this->update_row( $this->get_reset_data() );
234 }
235
236 /**
237 * Delete the optimization data for the given sizes.
238 * If all sizes are removed, all optimization data is deleted.
239 * Status and level are not modified nor removed if the "full" size is removed. This leaves the media in a Schrödinger state.
240 *
241 * @since 1.9.8
242 * @access public
243 * @author Grégory Viguier
244 *
245 * @param array $sizes A list of sizes to remove.
246 */
247 public function delete_sizes_optimization_data( array $sizes ) {
248 if ( ! $sizes || ! $this->is_valid() ) {
249 return;
250 }
251
252 $data = array_merge( $this->get_reset_data(), $this->get_row() );
253
254 $data['data']['sizes'] = ! empty( $data['data']['sizes'] ) && is_array( $data['data']['sizes'] ) ? $data['data']['sizes'] : [];
255
256 if ( ! $data['data']['sizes'] ) {
257 return;
258 }
259
260 $remaining_sizes_data = array_diff_key( $data['data']['sizes'], array_flip( $sizes ) );
261
262 if ( ! $remaining_sizes_data ) {
263 // All sizes have been removed: delete everything.
264 $this->delete_optimization_data();
265 return;
266 }
267
268 if ( count( $remaining_sizes_data ) === count( $data['data']['sizes'] ) ) {
269 // Nothing has been removed.
270 return;
271 }
272
273 $data['data']['sizes'] = $remaining_sizes_data;
274
275 $this->update_row( $data );
276 }
277
278 /**
279 * Get default values used to reset optimization data.
280 *
281 * @since 1.9
282 * @access protected
283 * @author Grégory Viguier
284 *
285 * @return array {
286 * The default values related to the optimization.
287 *
288 * @type string $hash The file hash.
289 * @type int $modified 0 to tell that the file has not been modified
290 * @type int $optimized_size File size after optimization.
291 * @type int $percent Saving optimized/original in percent.
292 * @type int $optimization_level The optimization level.
293 * @type string $status The status: success, already_optimized, error.
294 * @type string $error An error message.
295 * }
296 */
297 protected function get_reset_data() {
298 static $column_defaults;
299
300 if ( ! isset( $column_defaults ) ) {
301 $column_defaults = $this->get_row_db_instance()->get_column_defaults();
302
303 // All DB columns that have `null` as default value, are Imagify data.
304 foreach ( $column_defaults as $column_name => $value ) {
305 if ( 'hash' === $column_name || 'modified' === $column_name || 'data' === $column_name ) {
306 continue;
307 }
308
309 if ( isset( $value ) ) {
310 unset( $column_defaults[ $column_name ] );
311 }
312 }
313 }
314
315 $imagify_columns = $column_defaults;
316
317 // Also set the new file hash.
318 $file_path = $this->get_media()->get_fullsize_path();
319
320 if ( $file_path ) {
321 $imagify_columns['hash'] = md5_file( $file_path );
322 }
323
324 return $imagify_columns;
325 }
326 }
327